Commit Graph

82 Commits

Author SHA1 Message Date
Adriano 6da4dd5329 feat: dedup varianti con feature-set identico post-quantizzazione
Hash byte-exact su (dx, dy, bin) ordinati + scale. Se due varianti
post-rasterizzazione hanno lo stesso feature-set, ne tiene solo una.

Tipico caso d'uso: template con simmetrie discrete (quadrati, croci,
forme regolari) generano duplicati esatti per rotazioni multiple
del periodo. Su quadrato 80x80 con angle_step=10 deg: 36 -> 27 varianti
(~25% in meno di lavoro top-pruning).

Approccio conservativo (byte-exact): zero rischio di rimuovere varianti
distinte. Forme arrotondate (cerchi) o template asimmetrici non beneficiano
ma non vengono compromessi.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 15:37:42 +02:00
Adriano b143c6607a feat: numpy.bitwise_count come fallback SIMD per popcount
NumPy 2.0+ espone np.bitwise_count: implementato in C nativo con
intrinsics SIMD (POPCNT/AVX2 vpopcnt). Aggiunto come fallback secondo
livello quando Numba non e disponibile (es. wheel constraint, env
ristretto). Numba JIT parallel resta default: misura su 1080p 0.5ms
vs 1.6ms (bitwise_count e single-thread).

AVX2 puro su _jit_score_bitmap_rescored richiederebbe C extension
con build nativa: out-of-scope per questo branch (Numba LLVM gia
autovettorizza il loop interno).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 15:36:48 +02:00
Adriano 6704d66cd5 feat: kernel JIT batch top-max-per-variant (opt-in)
Nuovo kernel _jit_top_max_per_variant: prange esterno sulle varianti
invece di n_vars chiamate JIT separate via ThreadPoolExecutor.
Wrapper Python top_max_per_variant prepara buffer flat (offsets +
dx_flat/dy_flat/bins_flat) e bg per scala.

Default batch_top=False perche su benchmark realistici (Linux 13 core,
72-180 varianti) ThreadPoolExecutor + kernel singolo che rilascia GIL
e gia ottimale. Path batch_top=True utile come opzione per scenari
con n_vars >>> n_threads o overhead chiamate JIT dominante.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 15:35:51 +02:00
Adriano 4419c237b2 feat: greediness param con early-exit kernel JIT
Nuovo kernel _jit_score_bitmap_greedy: per ogni pixel scorre N feature
ed esce non appena hits + remaining < greediness * min_score * N.
Esposto in find() come greediness in [0..1], default 0 (backward compat).

Sostituisce il kernel rescored al top-level quando attivo: salta il
rescore background ma early-exit pixel impossibili. Util su template
con molte feature (>100) e scena con pochi pattern competitivi.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 15:33:39 +02:00
Adriano f00cf9b621 feat: cache features template per _refine_angle
Cache LRU (chiave: angolo arrotondato a 0.05deg, scale) di
(fx, fy, fb) per evitare warpAffine + gradient + extract ripetuti
durante golden-search refine. Bucket condiviso tra match della stessa
find() e tra find() consecutive sulla stessa ricetta.

Cache invalidata in train(): il template puo essere cambiato.
Limite 256 entry (sufficiente per 32 candidati x 8 valutazioni).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 15:31:37 +02:00
Adriano 4b7271094b feat: refine_pose_joint - Nelder-Mead 3D su (cx, cy, angle)
Alternativa al refine angolare 1D + subpixel quadratico: ottimizza
simultaneamente posizione e angolo con Nelder-Mead 3D inline (no
scipy). Default off (refine_pose_joint=False) per backward compat.

Vantaggio Halcon-style: un singolo iter LM/simplex stila il match a
precisione sub-pixel + sub-step in modo congiunto invece di alternare
assi. Convergenza tipica ~24 valutazioni vs ~15 (golden+quadratico)
ma piu robusto su template asimmetrici dove pose e angolo sono
fortemente correlati.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 15:30:20 +02:00
Adriano 746d1668c6 feat: NCC verify lazy con skip per shape-score alto
ncc_skip_above (default 0.85): se lo score shape e gia molto alto,
salta la verifica NCC (costosa: warp + corr per ogni match). I match
borderline 0.6-0.85 vengono comunque verificati.

Comportamento Halcon-style: NCC come tie-breaker per casi ambigui,
non come gate generalizzato. Su scene con molti match netti riduce
sensibilmente il costo della fase post-NMS.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 15:28:24 +02:00
Adriano d9a40952c4 feat: angle_step auto adattivo a dimensione template
Halcon-style: angle_step_deg=0 attiva derivazione automatica
step = atan(2/max_side) deg, clampato [0.5, 10]. Template grande
ottiene step fine, piccolo step grosso. auto_tune emette il valore
calcolato direttamente.

_refine_angle ora usa _effective_angle_step() per coerenza con
training quando la modalita auto e attiva.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 15:27:35 +02:00
Adriano 6db2086ead feat: pyramid_propagate - candidati top-level guidano full-res
Top-level ritorna top-K picchi locali invece di solo max. Fase full-res
valuta solo crop locali attorno ai picchi propagati (margine =
sf_top + spread + nms_radius/2) invece di scansionare intera scena.

Su scene 1920x1080 con pochi candidati: ~20-30% piu veloce mantenendo
identici match. Vantaggio cresce con scene piu grandi e meno candidati.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 15:26:29 +02:00
Adriano 27a0ef1a45 feat: coarse_stride per sub-sampling top-level
Nuovo kernel JIT _jit_score_bitmap_rescored_strided: valuta solo
pixel su griglia stride x stride al top della piramide. NMS + fase
full-res recuperano precisione. Speed-up ~stride^2 sulla fase coarse,
specie su scene grandi (1920x1080).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 15:24:44 +02:00
Adriano ba4024d252 feat: search_roi parametro find() per limitare area di ricerca
Equivalente a Halcon set_aoi: matching opera su crop locale, coord
output ri-traslate al sistema scena. Costo proporzionale a w*h del
ROI invece di W*H scena intera.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 15:22:43 +02:00
root 89b59b3ea3 perf: Fase 2 speed (3x baseline) - fuse JIT + LRU + sub-pixel lazy
Ottimizzazioni cumulative (225s -> 73s sul bench suite, 3.07x):

pm2d/line_matcher.py:
- Sub-pixel + plateau centroid spostati DOPO il pre-NMS (prima: 58k chiamate
  per clip_preciso anche su candidati poi scartati dalla NMS; ora solo sui
  ~75 preliminary sopravvissuti). Coordinate intere OK per la decisione
  reject, dato che nms_radius >= 8 px.
- Usa nuovo kernel fuso score+rescore (no allocazione intermedia).
- Adaptive plateau_radius + propagazione train_mask per NCC coerente.
- Local crop NCC (diag template invece di intera scena).
- Fallback adattivo se bg_rescore azzera tutti gli score top-level.

pm2d/_jit_kernels.py:
- Nuovo kernel _jit_score_bitmap_rescored: fonde scoring bitmap e rescore
  (score - bg) / (1 - bg) in un singolo pass parallelo. Evita allocazione
  e passata aggiuntiva (era ~15% del tempo find sul preciso).

pm2d/auto_tune.py:
- LRU cache in-memory sui risultati auto_tune (chiave md5 ROI + mask):
  richiamate successive con stessa ROI sono O(1).
- Downsample a 128px prima della correlazione rotazionale
  (O(n_angles * H * W) -> insensibile su sample moderati).
- Soglie weak/strong da percentili reali (p55/p85) senza clamp a 100,
  con clamp massimo 400 per evitare saturazione su template ad alto contrasto.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 21:21:59 +00:00
Adriano 3e4c20ecf5 feat: upload file nella cartella IMAGES_DIR
POST /upload_to_folder: sanitizza nome, valida estensione e contenuto
via cv2.imdecode, auto-rename su collisione.
Toolbar UI: bottone 'Carica file', dopo upload ricarica picker.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 14:45:16 +02:00
Adriano cc7d035f66 feat: scale_penalty - score riflette dimensione oltre a forma
Shape matching e invariante scala per design: 3 ruote dentate di dim
diverse avevano tutte score 1.00 confondendo l operatore.

Parametro scale_penalty [0..1]: score_final = score * max(0, 1 - penalty * |scale - 1|)
UI dropdown 'Peso dimensione nel score' con preset 0 / 0.3 / 0.5 / 0.8.

Test rings con penalty 0.5: 1.00 -> 1.00, 0.95 -> 0.97, 0.80 -> 0.90.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 14:37:36 +02:00
Adriano 37b718e45e perf: Fase 1 speed+precision (V1 V11 P1 P5)
V1 Coarse-to-fine angolare:
  - Al top-level valuta solo 1 variante ogni coarse_angle_factor (default 2)
  - Espande ai vicini nel full-res per preservare accuracy
  - Safe anche per template allungati (factor=2 non perde match)

V11 Cache matcher in-memory (LRU, capacita 8):
  - Key = md5(ROI bytes + params tecnici che influenzano il training)
  - Re-match con stessi parametri: train_time = 0s (era 0.5-1.5s)
  - OrderedDict LRU con _cache_get_matcher / _cache_put_matcher

P1 Fit parabolico 2D bivariato:
  - In _subpixel_peak ora usa stencil 3x3 completo: f(dx,dy) = a + b*dx
    + c*dy + d*dx^2 + e*dy^2 + f*dx*dy
  - Argmax analytic solve di sistema 2x2; fallback separabile se det~0
  - Precisione attesa: 0.1-0.3 px (era 0.5 px separabile)

P5 Golden-section angle search:
  - Sostituisce 5 sample equispaziati con convergenza log(n)
  - Tol 0.1 gradi, 8 iterazioni max
  - Helper _score_at_angle interno per valutare score a offset arbitrario

P2 Weighted centroid plateau:
  - Peso = (score - (max-0.01))^2 per enfatizzare top del plateau

Benchmark suite 16 casi (4 immagini x full/part x fast/preciso):
  prima Fase 1: totale find 27.3s
  dopo  Fase 1: totale find 25.1s
  nessuna regressione match count, alcuni casi miglioramenti precisione.

ROADMAP.md aggiornato con checklist Fase 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 11:35:40 +02:00
Adriano b83e577eab feat: thumbnail picker custom per selezione modello/scena
- GET /folder_image/{filename}?w=N: PNG ridotto cache 1h
- Frontend: 2 thumb-picker al posto dei select (thumb + nome + caret)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 11:10:35 +02:00
Adriano 2bca68d700 feat: 'Filtro falsi positivi' preset user-friendly (era verify_ncc)
Rinomina il parametro tecnico verify_threshold in un preset semantico
che operatore/cliente capisce senza leggere docs:

  off      -> 0.00 (tutti i match shape-based passano)
  leggero  -> 0.20 (tollera illuminazione/riflessi)
  medio    -> 0.35 (consigliato, default)
  forte    -> 0.50 (massima selettivita, scarta mismatch intensita)

UI: dropdown etichettato 'Filtro falsi positivi (verifica intensita colori)'
accanto a precisione angolare. Override tecnico (numerico) resta in
sezione Avanzate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 10:52:26 +02:00
Adriano 1671a151da feat: selezione immagini da cartella IMAGES_DIR via .env
- .env con IMAGES_DIR=Test
- server: _load_env legge .env senza dip extra
- GET /images lista file, POST /load_from_folder carica per nome
- frontend: file picker sostituiti con 2 select popolati all avvio

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 10:50:37 +02:00
Adriano 1954bc6ffd fix: allineamento preciso match (skip refine saturo + plateau centroid)
Bug: modello == scena non sovrapponeva perfettamente.

1. refine_angle trovava angoli spurious -2.5 deg con score saturo 1.0
   perche' parabolic fit su picco saturo estrapola rumore.
   Fix: skip refine quando original_score >= 0.99

2. Subpixel peak su plateau (spread_radius=5 satura picco su area)
   sceglieva pixel random via cv2.minMaxLoc.
   Fix: se >1 pixel a score >= max-0.01 nel raggio 10 usa CENTROIDE
   del plateau invece del parabolic fit.

Test self-match tooth_rim foro piccolo:
  prima:  pos=(355, 111.50) delta=(0, -3.50) ang=-2.5 deg
  dopo:   pos=(355, 115.00) delta=(0, +0.00) ang=+0.0 deg

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 10:12:26 +02:00
Adriano 45e3a29ff0 feat: simmetria 'invariante' per oggetti circolari (1 variante angolare)
Test tooth_rim foro grande: 12x piu veloce (0.14s vs 1.77s) perche
angle_max=0 genera 1 sola variante angolare invece di 72.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 10:02:32 +02:00
Adriano e1a1b956fd fix: persistenza immagini su disco (sopravvive restart server)
Bug: _IMAGES era dict in-memory, restart server → browser con id cached
riceveva 404 'Immagini non trovate'.

Fix: scrittura PNG in /tmp/pm2d_cache/{id}.png al upload, _load_image()
prova cache memory prima di leggere disco.

Rimossa funzione _store_image duplicata.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 10:00:54 +02:00
Adriano 9fba46d7f7 fix: default score 0.65 + verify 0.25 nel simple match
Default precedenti scartavano match validi con variazione intensita
attorno al foro (verify NCC 0.4 troppo stretto). Nuovo: 4/5 fori
corona dentata trovati con default.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 09:58:15 +02:00
Adriano d35bb574ef ui: parametri user-friendly (tipo/simmetria/scala/precisione)
Nascosti i parametri tecnici (num_features, weak/strong_grad, spread,
pyramid) incomprensibili per operatori. Sostituiti da scelte semantiche:

- Tipo modello: intero | parziale
- Simmetria: nessuna | bilaterale (180) | rotazionale 3/4/6/8x
- Variazione scala: fissa | 10% | 25% | 50%
- Precisione: veloce 10 | normale 5 | preciso 2
- Score minimo: slider
- Max match: input

Server: nuovo endpoint POST /match_simple. Deriva tecnici via
_simple_to_technical(roi) che analizza la ROI:
- weak/strong_grad da percentili
- num_features da densita edge x tipo
- pyramid_levels da min(h,w) ROI
- spread_radius proporzionale

Frontend: select + slider, sezione Avanzate collassabile per override.

Test rings_and_nuts preset intero/nessuna/medio/normale: 3/3 ruote in 2.14s

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 09:56:34 +02:00
Adriano fd7585acc5 feat: interfaccia web HTML (FastAPI + canvas JS)
Sostituisce GUI cv2/tkinter con webapp standalone:

Server (pm2d/web/server.py):
- FastAPI + uvicorn
- Endpoint: GET /, POST /upload, POST /match, POST /auto_tune,
  GET /image/{id}/raw
- In-memory image store (uuid-based)
- Rendering annotated server-side via opencv (overlay bbox + edges
  template warpati)

Frontend (pm2d/web/static/):
- index.html: layout 3 colonne (MODELLO | SCENA | PARAMETRI) + footer
  legenda
- style.css: tema dark, CSS grid responsive
- app.js: canvas HTML5 per visualizzazione scalata fit,
  ROI selection con drag mouse, form parametri live,
  MATCH button, Auto-tune button

Parametri modificabili INLINE (niente dialog separata).
Enter su qualsiasi campo triggera MATCH.
Legenda match in fondo con pallino colorato + dati.

main.py ora lancia il server webapp. Deprecato ingresso GUI cv2
(pm2d/gui.py resta importable per backward compat).

Test: /match su rings_and_nuts: 3/3 ruote in 1.14s (train 0.36s + find 0.77s).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 09:06:25 +02:00
Adriano 4ddda1ec62 ui: layout fisso 1600x900 con pannelli SX/DX, scena scalata
- Finestra dimensione fissa: scena scalata fit-to-box mantenendo aspect
  ratio (anche immagini piccole riempiono il layout)
- Pannello sinistro: MODELLO thumbnail + RISULTATI legenda numerata
- Pannello destro: PARAMETRI sempre visibili (train/find time evidenziati)
  + HOTKEY
- Rimossi parametri duplicati da pannello sinistro

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 08:59:06 +02:00
Adriano ba54b42fdc perf: spread bitmap uint8 + pre-NMS prima refine (3.5x globale, 49x worst case)
Due ottimizzazioni chiave:

1. Spread bitmap uint8 invece di response map (N_BINS, H, W) float32
   - 32x meno memoria, cache-friendly
   - Nuovi kernel Numba: _jit_score_bitmap, _jit_popcount_density
   - Formato: spread[y,x] bit b = bin b attivo nel raggio di spread
   - _refine_angle usa slicing su bitmap con mask & bit

2. Pre-NMS prima di refine_angle/verify_ncc
   - Problema: loop 'for raw in candidati' applicava refine+verify A OGNI
     candidato prima del check NMS → 2000+ refine chiamati per ~25 match
   - Fix: pre-NMS su (cx, cy) subpixel, limita a max_matches*3 candidati,
     poi refine + verify solo su quelli
   - Esempio worst case: lama_full_fast 55.9s → 1.13s (49x)

Benchmark suite 16 scenari (4 immagini x full/part x fast/preciso):
  prima: totale find 94.6s
  dopo:  totale find 27.3s (3.5x globale)
  casi peggiori <5s (prima erano >50s)

ROI parziali (solo metà oggetto) funzionano in tutti i casi.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 02:11:33 +02:00
Adriano d27676cfe6 fix: cap adattivo al 50% varianti + form e finestra risultati ridimensionabili
- max_vars_full = max(max_matches*8, n_variants // 2): protegge perf con
  molte scale mantenendo metà delle varianti al full-res (vs intero senza cap
  che dava 22s su 864 varianti, vs 80s screenshot utente)
- Dialog tkinter: resizable, minsize 360x420, Entry col peso 2 espandibile
- Finestra risultati cv2: WINDOW_NORMAL con resizeWindow iniziale 1600x900

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 01:57:20 +02:00
Adriano 9a0da7aac8 fix: bg_map per-scala + rimosso cap varianti full-res
Problema: in scenari con molte scale (ring detection), il matcher perdeva
istanze a scale estreme:
1. Cap max_vars_full (default max_matches*8) escludeva la pose corretta
2. bg_map usava box fissa = template_size, penalizzando varianti a scala
   grande dove il template reale è più grande del box

Fix:
- Rimosso cap hard sul numero di varianti full-res (Numba compensa velocità)
- bg_map PER-SCALA: cache {scale: bg_map} con box size scalata
  appropriatamente (tw*scale, th*scale). Calcolato una volta per scala
  unica, poi ogni variante usa il suo bg_map

Benchmark rings_and_nuts (template ruota grande, 3 ruote nella scena a
dimensioni diverse):
  prima:  2/3 match (persa la grande)
  dopo:   3/3 match score 1.0 a scale 1.00, 0.95, 0.80

Regression:
  clip→clip: 13/13 invariato (0.93s)
  ring→clip FP: 3 (era 1 con bg fisso, era 10 senza bg)
  compromesso ragionevole: verify_threshold=0.5 elimina gli ultimi FP

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 01:48:40 +02:00
Adriano faebccb69e feat: background locale + verify NCC per eliminare falsi positivi
Problema: matcher linemod con solo orientamento gradient può dare score alto
su texture dense/rumore che per caso accumulano orientamenti compatibili.
Esempio: template ruota dentata su scena clip → match a score 0.9 (errati).

Fix in 2 livelli:

1. Background score LOCALE nel find()
   - _bg_map(resp, box_size) = densità media bin attivi in bbox template
   - Rinormalizza score: s' = max(0, (s - bg) / (1 - bg))
   - Annulla contributo di zone sature ma preserva pattern puliti

2. Verify NCC post-hoc
   - _verify_ncc(): warpa template alla pose (cx, cy, angle, scale) e
     calcola NCC classico su intensità con la scena sottostante
   - Threshold di default 0.4 elimina FP con edge orientati casualmente
   - Parametro esposto in GUI (verify_threshold)

Rimossa penalty di saturazione nel response_map (ridondante).

Test regression (ruote dentate vs clip, clip vs ruote dentate):
  no verify:  12+ falsi positivi con score ~0.7
  verify 0.4: 1-2 falsi positivi rimanenti, true positive invariati
  verify 0.5: 0 falsi positivi, 1 TP scale piccola perso

Benchmark clip→clip (13 istanze):
  full pipeline (Numba + threads + refine + subpix + verify): 1.12s

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 01:37:01 +02:00
Adriano b20b11c029 perf: Numba JIT kernel per score_by_shift (2.1x speedup)
- Nuovo modulo pm2d/_jit_kernels.py con _jit_score_by_shift Numba njit
  parallel + fastmath + boundscheck=False
- Parallelizzazione per riga output (no race condition su acc)
- Fallback automatico numpy se numba non installato
- Warmup automatico al module import (evita JIT lag al 1 match)

Benchmark clip.png (13 istanze):
  prima (numpy + threads): 1.55s
  dopo (numba + threads):  0.72s
  speedup: 2.1x

Pipeline totale full (refine+subpix): 0.80s

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 01:30:31 +02:00
Adriano 075b014bd7 perf: piramide al training, refinement sub-step, multithreading
LineShapeMatcher:
- Feature piramidate precomputate al training (_LevelFeatures per livello
  piramide, dedup risolto una volta)
- Refinement angolare: 5 offset ±step/2 + parabolic fit → precisione ~0.5°
  con angle_step=5° (10x fine rispetto a step training)
- Subpixel posizione: parabolic fit 2D sul picco → frazione pixel
- Multithreading: n_threads auto=CPU-1, parallelizza top-level pruning e
  full-res matching tramite ThreadPoolExecutor (numpy/cv2 rilasciano GIL)

GUI:
- Dialog edit_params con bottone Auto-tune
- Legenda numerata match con pallino colore (#i, coords, angle, scala, score)
- Hotkey finestra: r=params, o=nuovo ROI, m=nuovo modello, s=nuova scena
- Pannello con train/find time + HOTKEY in basso

auto_tune.py:
- Analisi template: soglie grad da percentili, num_features da densità
  edge, pyramid_levels da min_side, min_score da entropia orientation,
  rilevazione simmetria rotazionale (soglia 0.75 NCC su magnitude)

Benchmark clip.png (13 istanze, 72 varianti angolari):
  prima: 5.84s, precisione 5° (step training)
  ora:   1.67s, precisione ~0.5°, subpixel posizione
  speed-up: 3.5x, precisione angolare 10x

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 01:22:56 +02:00
Adriano b9a4d51fac feat: PM2D standalone shape-based matcher
Programma standalone Pattern Matching 2D con GUI cv2/tk + algoritmo
puro riusabile. Due backend:

- LineShapeMatcher (default): porting Python di line2Dup (linemod-style)
  - Gradient orientation quantized 8-bin modulo π + spreading
  - Feature sparse top-magnitude con spacing minimo
  - Score via shift-add vettorizzato numpy (O(N_features·H·W))
  - Piramide multi-risoluzione con pruning varianti al top-level
  - Supporto mask binaria per modello non-rettangolare

- EdgeShapeMatcher (fallback): Canny + matchTemplate multi-rotazione

GUI separata da algoritmo. Benchmark clip.png (13 istanze):
  - Edge backend:  84s, 6/13 score ~0.3
  - Line backend:  4.1s, 13/13 score 0.98-1.00

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 00:46:59 +02:00