rough playable version finished
This commit is contained in:
51
locate_finders.py
Normal file
51
locate_finders.py
Normal file
@@ -0,0 +1,51 @@
|
||||
from PIL import Image
|
||||
import numpy as np
|
||||
from numpy.lib.stride_tricks import sliding_window_view
|
||||
|
||||
def load_bw(path):
|
||||
# Black=1, White=0
|
||||
im = Image.open(path).convert("L")
|
||||
bw = (np.array(im) < 128).astype(np.uint8)
|
||||
return bw
|
||||
|
||||
def finder_template(box_size=2):
|
||||
# 7x7 finder: outer black, inner white (5x5), center black (3x3)
|
||||
F = np.array([
|
||||
[1,1,1,1,1,1,1],
|
||||
[1,0,0,0,0,0,1],
|
||||
[1,0,1,1,1,0,1],
|
||||
[1,0,1,1,1,0,1],
|
||||
[1,0,1,1,1,0,1],
|
||||
[1,0,0,0,0,0,1],
|
||||
[1,1,1,1,1,1,1],
|
||||
], dtype=np.uint8)
|
||||
# upscale to pixels
|
||||
return np.kron(F, np.ones((box_size, box_size), dtype=np.uint8))
|
||||
|
||||
def count_finders(img_path, box_size=2, max_mismatch=0):
|
||||
bw = load_bw(img_path)
|
||||
T = finder_template(box_size=box_size)
|
||||
h, w = T.shape
|
||||
# slide 14x14 window over the image
|
||||
win = sliding_window_view(bw, (h, w))
|
||||
# Hamming distance to template per window
|
||||
mismatches = (win ^ T).sum(axis=(-2, -1))
|
||||
hits = mismatches <= max_mismatch
|
||||
# Optional: suppress overlapping duplicates by non-maximum suppression on exact matches
|
||||
ys, xs = np.where(hits)
|
||||
# Convert to center coordinates
|
||||
centers = [(int(y + h/2), int(x + w/2)) for y, x in zip(ys, xs)]
|
||||
|
||||
# Greedy dedup within ~half a finder width
|
||||
deduped = []
|
||||
r = max(2, h//2)
|
||||
for cy, cx in centers:
|
||||
if all((abs(cy - y) > r) or (abs(cx - x) > r) for y, x in deduped):
|
||||
deduped.append((cy, cx))
|
||||
|
||||
return len(deduped), deduped
|
||||
|
||||
if __name__ == "__main__":
|
||||
n, centers = count_finders("./scrambled_test_qr_code.png", box_size=2, max_mismatch=0)
|
||||
print("Finder count:", n, "centers:", centers, "Exactly three?", n == 3)
|
||||
|
||||
Reference in New Issue
Block a user