sync: Auto-sync from ACG-M-L5090 at 2026-02-09
Synced files: - ai-misconceptions-reading-list.md (radio show research) - ai-misconceptions-radio-segments.md (distilled radio segments) - extract_license_plate.py - review_best_plates.py Machine: ACG-M-L5090 Timestamp: 2026-02-09 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
145
review_best_plates.py
Normal file
145
review_best_plates.py
Normal file
@@ -0,0 +1,145 @@
|
||||
"""
|
||||
Identify the best license plate candidates from extraction results
|
||||
Filter by ideal aspect ratio (2-5) and larger area
|
||||
"""
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
def parse_summary(summary_path):
|
||||
"""Parse summary.txt to find best candidates"""
|
||||
candidates = []
|
||||
|
||||
with open(summary_path, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Parse each candidate line
|
||||
pattern = r'Time: ([\d.]+)s \| Candidate #(\d+) \| Aspect Ratio: ([\d.]+) \| Area: (\d+)'
|
||||
|
||||
for match in re.finditer(pattern, content):
|
||||
timestamp = float(match.group(1))
|
||||
candidate_num = int(match.group(2))
|
||||
aspect_ratio = float(match.group(3))
|
||||
area = int(match.group(4))
|
||||
|
||||
# Score candidates based on ideal license plate characteristics
|
||||
# Ideal aspect ratio: 3-4.5 (most US license plates)
|
||||
# Prefer larger areas (closer to camera)
|
||||
ar_score = 0
|
||||
if 2.5 <= aspect_ratio <= 5.0:
|
||||
# Best score for aspect ratio between 3-4.5
|
||||
if 3.0 <= aspect_ratio <= 4.5:
|
||||
ar_score = 100
|
||||
else:
|
||||
ar_score = 50
|
||||
|
||||
# Area score (normalize to 0-100)
|
||||
area_score = min(area / 500, 100) # Scale area
|
||||
|
||||
# Combined score
|
||||
total_score = (ar_score * 0.6) + (area_score * 0.4)
|
||||
|
||||
candidates.append({
|
||||
'timestamp': timestamp,
|
||||
'candidate': candidate_num,
|
||||
'aspect_ratio': aspect_ratio,
|
||||
'area': area,
|
||||
'score': total_score
|
||||
})
|
||||
|
||||
return candidates
|
||||
|
||||
def main():
|
||||
summary_path = Path("D:/Scratchpad/pickup_truck_25-30s/summary.txt")
|
||||
output_dir = Path("D:/Scratchpad/pickup_truck_25-30s")
|
||||
|
||||
print("[INFO] Analyzing license plate candidates...")
|
||||
candidates = parse_summary(summary_path)
|
||||
|
||||
# Sort by score
|
||||
candidates.sort(key=lambda x: x['score'], reverse=True)
|
||||
|
||||
# Show top 20 candidates
|
||||
print("\n" + "=" * 80)
|
||||
print("TOP 20 LICENSE PLATE CANDIDATES")
|
||||
print("=" * 80)
|
||||
print(f"{'Rank':<6} {'Time':<10} {'Cand':<6} {'AR':<8} {'Area':<10} {'Score':<8} {'Files'}")
|
||||
print("-" * 80)
|
||||
|
||||
for idx, candidate in enumerate(candidates[:20], 1):
|
||||
timestamp = candidate['timestamp']
|
||||
cand_num = candidate['candidate']
|
||||
ar = candidate['aspect_ratio']
|
||||
area = candidate['area']
|
||||
score = candidate['score']
|
||||
|
||||
# Check which files exist for this candidate
|
||||
frame_name = f"frame_{timestamp:.2f}s"
|
||||
base_pattern = f"{frame_name}_plate_{cand_num}_"
|
||||
|
||||
# Count enhancement files
|
||||
enhancement_files = list(output_dir.glob(f"{base_pattern}*.jpg"))
|
||||
enhancement_count = len([f for f in enhancement_files if '_raw' not in f.name])
|
||||
|
||||
print(f"{idx:<6} {timestamp:<10.2f} {cand_num:<6} {ar:<8.2f} {area:<10} {score:<8.1f} {enhancement_count} enhanced")
|
||||
|
||||
# Create recommendation file
|
||||
recommendation_path = output_dir / "RECOMMENDATIONS.txt"
|
||||
with open(recommendation_path, 'w') as f:
|
||||
f.write("LICENSE PLATE EXTRACTION - TOP CANDIDATES\n")
|
||||
f.write("=" * 80 + "\n\n")
|
||||
f.write("These are the top 20 most likely license plate candidates based on:\n")
|
||||
f.write("- Aspect ratio (ideal: 3.0-4.5 for US plates)\n")
|
||||
f.write("- Area size (larger = closer to camera)\n\n")
|
||||
f.write("REVIEW THESE FILES FIRST:\n")
|
||||
f.write("-" * 80 + "\n\n")
|
||||
|
||||
for idx, candidate in enumerate(candidates[:20], 1):
|
||||
timestamp = candidate['timestamp']
|
||||
cand_num = candidate['candidate']
|
||||
ar = candidate['aspect_ratio']
|
||||
area = candidate['area']
|
||||
score = candidate['score']
|
||||
|
||||
f.write(f"RANK {idx}: Time {timestamp:.2f}s - Candidate #{cand_num}\n")
|
||||
f.write(f" Aspect Ratio: {ar:.2f} | Area: {area} | Score: {score:.1f}\n")
|
||||
f.write(f" Files to review:\n")
|
||||
|
||||
frame_name = f"frame_{timestamp:.2f}s"
|
||||
|
||||
# List specific enhancement files to check
|
||||
enhancements = [
|
||||
f"{frame_name}_detection_{cand_num}.jpg (shows detection box on frame)",
|
||||
f"{frame_name}_plate_{cand_num}_high_contrast.jpg (best for dark plates)",
|
||||
f"{frame_name}_plate_{cand_num}_extreme_sharp.jpg (best for clarity)",
|
||||
f"{frame_name}_plate_{cand_num}_adaptive_thresh.jpg (best for OCR)",
|
||||
f"{frame_name}_plate_{cand_num}_bilateral_sharp.jpg (balanced enhancement)",
|
||||
]
|
||||
|
||||
for enhancement in enhancements:
|
||||
f.write(f" - {enhancement}\n")
|
||||
|
||||
f.write("\n")
|
||||
|
||||
f.write("\n" + "=" * 80 + "\n")
|
||||
f.write("ENHANCEMENT TYPES EXPLAINED:\n")
|
||||
f.write("-" * 80 + "\n")
|
||||
f.write("- detection_X.jpg: Shows where the plate was detected on the frame\n")
|
||||
f.write("- high_contrast.jpg: Best for dark/low-contrast plates\n")
|
||||
f.write("- extreme_sharp.jpg: Best for overall clarity and readability\n")
|
||||
f.write("- adaptive_thresh.jpg: Black/white threshold - best for OCR\n")
|
||||
f.write("- bilateral_sharp.jpg: Noise reduction + sharpening\n")
|
||||
f.write("- unsharp_mask.jpg: Professional-grade sharpening\n")
|
||||
f.write("- bright_contrast.jpg: Brightness + contrast boost\n")
|
||||
|
||||
print("\n[SUCCESS] Analysis complete!")
|
||||
print(f"[INFO] Recommendations saved to: {recommendation_path}")
|
||||
print("\n[NEXT STEPS]")
|
||||
print("1. Open the output directory in File Explorer:")
|
||||
print(f" {output_dir}")
|
||||
print("2. Read RECOMMENDATIONS.txt for the best candidates")
|
||||
print("3. Start with Rank 1, review the enhancement files listed")
|
||||
print("4. The 'extreme_sharp' and 'adaptive_thresh' versions usually work best")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user