ocr / compare_decoders.py
borreooo's picture
Add project files
b42373a
Raw
History Blame Contribute Delete
5.05 kB
import cv2
import os
import re
import time
from collections import defaultdict
BARCODE_DIR = "images/barcode"
PART_NUMBER_RE = re.compile(r'^0301BAB\d+N$')
def get_image_files():
files = sorted([f for f in os.listdir(BARCODE_DIR)
if f.lower().endswith(('.jpg', '.jpeg', '.png'))])
return files
def is_chassis(text):
text = text.strip()
return bool(text) and not PART_NUMBER_RE.match(text)
def decode_pyzbar(img, gray, thresh):
from pyzbar.pyzbar import decode
all_values = set()
for frame in [img, thresh]:
for d in decode(frame):
text = d.data.decode("utf-8").strip()
all_values.add(text)
return all_values
def decode_zxingcpp(img, gray, thresh):
import zxingcpp
all_values = set()
for frame in [gray, thresh]:
try:
results = zxingcpp.read_barcodes(frame)
for r in results:
text = r.text.strip()
if text:
all_values.add(text)
except Exception as e:
pass
return all_values
def decode_cv2barcode(img, gray, thresh):
all_values = set()
try:
detector = cv2.barcode.BarcodeDetector()
for frame in [gray, thresh]:
ok, decoded_info, decoded_type, points = detector.detectAndDecode(frame)
if ok and decoded_info is not None:
for text in decoded_info:
if text and text.strip():
all_values.add(text.strip())
except AttributeError:
pass
except Exception as e:
pass
return all_values
def main():
files = get_image_files()
print(f"Testing {len(files)} barcode images from {BARCODE_DIR}/\n")
decoders = {
"pyzbar": decode_pyzbar,
"zxing-cpp": decode_zxingcpp,
"cv2.barcode": decode_cv2barcode,
}
stats = {name: {"chassis": 0, "part_only": 0, "none": 0, "chassis_list": []}
for name in decoders}
timings = {name: 0.0 for name in decoders}
detail_rows = []
for fname in files:
path = os.path.join(BARCODE_DIR, fname)
img = cv2.imread(path)
if img is None:
continue
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
key = os.path.splitext(fname)[0]
row = {"file": fname}
for name, decoder_fn in decoders.items():
t0 = time.perf_counter()
all_values = decoder_fn(img, gray, thresh)
elapsed = time.perf_counter() - t0
timings[name] += elapsed
chassis_vals = {v for v in all_values if is_chassis(v)}
part_vals = {v for v in all_values if PART_NUMBER_RE.match(v)}
if chassis_vals:
stats[name]["chassis"] += 1
stats[name]["chassis_list"].append((key, chassis_vals))
row[name] = ", ".join(sorted(chassis_vals))
elif part_vals:
stats[name]["part_only"] += 1
row[name] = "(part# only)"
else:
stats[name]["none"] += 1
row[name] = "—"
detail_rows.append(row)
print("=" * 100)
print(f"{'File':<14} {'pyzbar':<20} {'zxing-cpp':<20} {'cv2.barcode':<20}")
print("-" * 100)
for row in detail_rows:
pyz = row.get("pyzbar", "—")
zxc = row.get("zxing-cpp", "—")
cv2b = row.get("cv2.barcode", "—")
print(f"{row['file']:<14} {pyz:<20} {zxc:<20} {cv2b:<20}")
total = len(files)
print("\n" + "=" * 100)
print("SUMMARY")
print("=" * 100)
print(f"{'Metric':<30} {'pyzbar':>12} {'zxing-cpp':>12} {'cv2.barcode':>12}")
print("-" * 70)
print(f"{'Chassis decoded':.<30} {stats['pyzbar']['chassis']:>12} {stats['zxing-cpp']['chassis']:>12} {stats['cv2.barcode']['chassis']:>12}")
print(f"{'Part# only (filtered out)':.<30} {stats['pyzbar']['part_only']:>12} {stats['zxing-cpp']['part_only']:>12} {stats['cv2.barcode']['part_only']:>12}")
print(f"{'Nothing decoded':.<30} {stats['pyzbar']['none']:>12} {stats['zxing-cpp']['none']:>12} {stats['cv2.barcode']['none']:>12}")
print(f"{'Total time (s)':.<30} {timings['pyzbar']:>12.2f} {timings['zxing-cpp']:>12.2f} {timings['cv2.barcode']:>12.2f}")
print("-" * 70)
print(f"{'CHASSIS DECODE RATE':.<30} {stats['pyzbar']['chassis']/total:>11.0%} {stats['zxing-cpp']['chassis']/total:>11.0%} {stats['cv2.barcode']['chassis']/total:>11.0%}")
print("=" * 100)
best_name = max(decoders.keys(), key=lambda n: stats[n]["chassis"])
print(f"\n★ Best decoder: {best_name} ({stats[best_name]['chassis']}/{total} chassis barcodes)")
for name in decoders:
if stats[name]["chassis_list"]:
print(f"\n {name} decoded chassis numbers:")
for key, vals in stats[name]["chassis_list"]:
print(f" {key}: {', '.join(sorted(vals))}")
if __name__ == "__main__":
main()