⚡ MareArts ANPR V14 - Advanced Manual Processing
Ready to take control? In this advanced guide, I'll show you how to manually process detections, measure performance, and optimize for your specific use case.
π― Why Manual Processing?
- Full control over detection pipeline
- Custom filtering and post-processing
- Performance measurement and optimization
- Integration with existing computer vision pipelines
- Custom confidence thresholds per stage
π§ Manual Detection & OCR Pipeline
from marearts_anpr import ma_anpr_detector_v14, ma_anpr_ocr_v14
import cv2
from PIL import Image
import time
# Initialize models
detector = ma_anpr_detector_v14(
"medium_640p_fp32",
user_name, serial_key, signature,
backend="cpu",
conf_thres=0.25,
iou_thres=0.5
)
ocr = ma_anpr_ocr_v14("medium_fp32", "eup", user_name, serial_key, signature)
# Load image
img = cv2.imread("plate.jpg")
# Step 1: Detect license plates
start = time.time()
detections = detector.detector(img)
detection_time = time.time() - start
print(f"Detection time: {detection_time:.4f}s")
print(f"Found {len(detections)} plate(s)")
# Step 2: Process each detection
results = []
ocr_time = 0
for i, box_info in enumerate(detections):
# Get bounding box
bbox = box_info['bbox'] # [x1, y1, x2, y2]
score = box_info['score'] # Detection confidence
# Crop plate region
x1, y1, x2, y2 = int(bbox[0]), int(bbox[1]), int(bbox[2]), int(bbox[3])
crop = img[y1:y2, x1:x2]
if crop.size == 0:
continue
# Convert to PIL for OCR
pil_img = Image.fromarray(crop)
if pil_img.mode != "RGB":
pil_img = pil_img.convert("RGB")
# Run OCR
start = time.time()
text, confidence = ocr.predict(pil_img)
elapsed = time.time() - start
ocr_time += elapsed
print(f"Plate {i+1}: {text} ({confidence}%) - {elapsed:.4f}s")
results.append({
"ocr": text,
"ocr_conf": confidence,
"bbox": [x1, y1, x2, y2],
"det_conf": int(score * 100)
})
print(f"\nTotal time: {detection_time + ocr_time:.4f}s")
π Detection Object Structure
# detector.detector(img) returns list of dictionaries:
[
{
'bbox': [x1, y1, x2, y2], # Bounding box coordinates
'score': 0.95, # Detection confidence (0-1)
'class': 'license_plate' # Object class
},
...
]
# ocr.predict(pil_image) returns tuple:
("ABC1234", 98.5) # (text, confidence_percentage)
π Backend Performance Comparison
backends = ["cpu", "cuda"] # Add "directml" on Windows
for backend_name in backends:
try:
print(f"\nπ§ Testing {backend_name}...")
# Initialize with specific backend
test_detector = ma_anpr_detector_v14(
"medium_640p_fp32",
user_name, serial_key, signature,
backend=backend_name,
conf_thres=0.25
)
# Measure performance
start = time.time()
detections = test_detector.detector(img)
elapsed = time.time() - start
print(f"Detected {len(detections)} plates in {elapsed:.4f}s")
print(f"Speed: {1/elapsed:.1f} FPS")
except Exception as e:
print(f"⚠️ {backend_name} not available: {e}")
⚙️ Performance Results (Typical)
| Backend | Detection | OCR | Total | FPS |
|---|---|---|---|---|
| CPU (i7) | ~0.15s | ~0.03s | ~0.18s | ~5.5 |
| CUDA (RTX 3060) | ~0.008s | ~0.002s | ~0.01s | ~100 |
Result: GPU acceleration = 18x faster! π
π️ Custom Filtering
# Filter detections by confidence
min_detection_conf = 0.50
min_ocr_conf = 80.0
filtered_results = []
for box_info in detections:
if box_info['score'] < min_detection_conf:
continue # Skip low confidence detections
# Process with OCR...
text, conf = ocr.predict(plate_crop)
if conf < min_ocr_conf:
continue # Skip low confidence OCR
filtered_results.append({
"text": text,
"confidence": conf,
"bbox": bbox
})
print(f"After filtering: {len(filtered_results)} high-confidence plates")
π¨ Custom Visualization
import cv2
# Draw boxes and text on image
for result in results:
x1, y1, x2, y2 = result['bbox']
text = result['ocr']
conf = result['ocr_conf']
# Draw rectangle
cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
# Draw text
label = f"{text} ({conf}%)"
cv2.putText(img, label, (x1, y1-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
cv2.imwrite("result.jpg", img)
πΉ Video Processing Pipeline
import cv2
# Open video
cap = cv2.VideoCapture("traffic.mp4")
frame_count = 0
plate_history = {}
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
frame_count += 1
# Process every N frames (skip frames for speed)
if frame_count % 5 != 0:
continue
# Detect plates
detections = detector.detector(frame)
for det in detections:
bbox = det['bbox']
x1, y1, x2, y2 = int(bbox[0]), int(bbox[1]), int(bbox[2]), int(bbox[3])
crop = frame[y1:y2, x1:x2]
if crop.size == 0:
continue
# OCR
pil_crop = Image.fromarray(cv2.cvtColor(crop, cv2.COLOR_BGR2RGB))
text, conf = ocr.predict(pil_crop)
# Track plates (simple tracking by position)
plate_id = f"{x1//50}_{y1//50}"
if plate_id not in plate_history:
plate_history[plate_id] = []
plate_history[plate_id].append(text)
# Draw
cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv2.putText(frame, text, (x1, y1-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
cv2.imshow('ANPR', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
# Print detected plates
print("\nDetected plates:")
for plate_id, texts in plate_history.items():
# Most common text for this plate
most_common = max(set(texts), key=texts.count)
print(f" {most_common} (seen {len(texts)} times)")
πΎ Batch Processing from Directory
import os
from pathlib import Path
image_dir = Path("./images")
results_all = {}
for img_path in image_dir.glob("*.jpg"):
print(f"Processing {img_path.name}...")
img = cv2.imread(str(img_path))
detections = detector.detector(img)
plates = []
for det in detections:
bbox = det['bbox']
x1, y1, x2, y2 = int(bbox[0]), int(bbox[1]), int(bbox[2]), int(bbox[3])
crop = img[y1:y2, x1:x2]
if crop.size > 0:
pil_crop = Image.fromarray(cv2.cvtColor(crop, cv2.COLOR_BGR2RGB))
text, conf = ocr.predict(pil_crop)
plates.append({"text": text, "conf": conf})
results_all[img_path.name] = plates
# Save results
import json
with open("results.json", "w") as f:
json.dump(results_all, f, indent=2)
print(f"\nProcessed {len(results_all)} images")
π Advanced Tips
- GPU Memory: Use
cudabackend for 10-100x speedup - Confidence Tuning: Lower
conf_thresto 0.15-0.20 for difficult images - IOU Threshold: Increase
iou_thresto reduce duplicate detections - Batch Processing: Process multiple crops at once with
ocr.predict([img1, img2, ...]) - Frame Skipping: Process every Nth frame in videos for speed
- Multi-threading: Run detector and OCR in separate threads
π Troubleshooting
No detections?
- Lower
conf_thresto 0.15 - Try larger model (
large_640p_fp32) - Check image quality and resolution
Wrong OCR results?
- Verify correct region (
kr,eup,na,cn) - Try larger OCR model (
large_fp32) - Check plate crop quality
Slow performance?
- Use GPU backend (
cudaordirectml) - Use smaller models (
small_640p_fp32,small_fp32) - Skip video frames
- Batch process multiple images
π‘ Conclusion
Manual processing gives you complete control over the ANPR pipeline. Use it for:
- ✅ Custom filtering and validation
- ✅ Performance optimization
- ✅ Video stream processing
- ✅ Integration with existing CV pipelines
- ✅ Advanced visualization and tracking
Happy optimizing! ⚡π
No comments:
Post a Comment