Initial commit for push folder

This commit is contained in:
Nguyen Hong Van 2026-09-18 09:13:53 +09:00
commit c4af9fcbb5
82 changed files with 3294 additions and 0 deletions

View file

@ -0,0 +1,103 @@
"""
Benchmark Suite for Supermarket Product Classification
Compares SURF, ORB, BRISK, and Hybrid methods following
MDPI Electronics 2023, 12(17), 3640.
"""
import os
import sys
import time
import cv2
import numpy as np
from typing import Dict, List, Any
current_dir = os.path.dirname(os.path.abspath(__file__))
if current_dir not in sys.path:
sys.path.insert(0, current_dir)
from feature_matcher import ProductFeatureMatcher
def run_benchmark(stock_dir: str = "stock", num_runs: int = 3):
print("=" * 70)
print("RETAIL SHELF PRODUCT RECOGNITION - ALGORITHM BENCHMARK")
print("Methods Evaluated: SURF | ORB | BRISK | HYBRID (Paper Method)")
print("=" * 70)
matcher = ProductFeatureMatcher(stock_dir=stock_dir)
templates = matcher.db.templates
if not templates:
print("[Error] No templates found in stock directory.")
return
methods = ["surf", "orb", "brisk", "hybrid"]
results = {m: {"latencies": [], "inliers": [], "keypoints_query": []} for m in methods}
# Test images: We will evaluate using crops synthesized with slight transformations
# (scale, rotation, noise) as well as the template images themselves
print(f"\nEvaluating across {len(templates)} catalog SKUs (repeat count: {num_runs})...\n")
for sku_id, tmpl in templates.items():
original_img = tmpl["image"]
h, w = original_img.shape[:2]
# Apply synthetic shelf condition (rotation by 10 deg, resize by 0.85)
M = cv2.getRotationMatrix2D((w / 2, h / 2), 10, 0.85)
query_img = cv2.warpAffine(original_img, M, (w, h))
for method in methods:
times = []
for _ in range(num_runs):
t0 = time.perf_counter()
res = matcher.classify_crop(query_img, method=method)
t1 = time.perf_counter()
times.append((t1 - t0) * 1000.0) # ms
avg_latency = np.mean(times)
results[method]["latencies"].append(avg_latency)
# Record inliers/score
if res.get("status") == "success":
top_sku = res["best_sku"]
score = res["score"]
results[method]["inliers"].append(score)
# Summarize metrics
summary_rows = []
for method in methods:
latencies = results[method]["latencies"]
scores = results[method]["inliers"]
avg_lat = np.mean(latencies) if latencies else 0.0
p95_lat = np.percentile(latencies, 95) if latencies else 0.0
avg_score = np.mean(scores) if scores else 0.0
# Paper characteristics notes
notes = {
"surf": "Scale & rotation robust; Hessian gradient features",
"orb": "Ultra fast binary descriptor; FAST + BRIEF",
"brisk": "Scale-space AGAST; circular pattern descriptor",
"hybrid": "Paper fusion (SURF+ORB+BRISK); optimal accuracy/speed"
}[method]
summary_rows.append([
method.upper(),
f"{avg_lat:.2f} ms",
f"{p95_lat:.2f} ms",
f"{avg_score:.1f}",
notes
])
headers = ["Method", "Avg Latency (ms)", "P95 Latency (ms)", "Avg Match Score", "Characteristics / Paper Findings"]
print("\n" + "-" * 105)
print(f"{headers[0]:<10} | {headers[1]:<18} | {headers[2]:<18} | {headers[3]:<16} | {headers[4]}")
print("-" * 105)
for row in summary_rows:
print(f"{row[0]:<10} | {row[1]:<18} | {row[2]:<18} | {row[3]:<16} | {row[4]}")
print("-" * 105)
print("\n[Benchmark Complete] All methods operational.")
if __name__ == "__main__":
run_benchmark()