bg_w, bg_h, bg_ch, bg_rows = decode_png(bg_path)
bk_w, bk_h, bk_ch, bk_rows = decode_png(block_path)
if bg_ch != 3:
raise ValueError("background.png 需要是 RGB 图")
if bk_ch != 4:
raise ValueError("block.png 需要是 RGBA 图")
bg_gray = to_gray(bg_rows, bg_ch)
bk_gray = to_gray(bk_rows, bk_ch)
bk_mask = alpha_mask(bk_rows, bk_ch)
tpl_gray, tpl_mask = crop_by_mask(bk_gray, bk_mask)
bg_edges = edge_map(bg_gray)
tpl_edges = edge_map(tpl_gray)
x, y, score = find_best_position(bg_edges, tpl_edges, tpl_mask)
print(f"背景图尺寸: {bg_w}x{bg_h}")
print(f"滑块图尺寸: {bk_w}x{bk_h}")
print(f"缺口左上角坐标: ({x}, {y})")
print(f"建议滑动距离(像素): {x}")
print(f"匹配误差(越小越好): {score:.2f}")
if __name__ == "__main__":
main()
How it works
In essence: treat the slider image as a template, slide it across the background image and compare, then take the position with the smallest error.
The reference implementation lives in
main.py
Step by step, matching the images you see above
-
step_01Grayscale
Convert RGB to grayscale to cut down colour noise and keep only the brightness structure. -
step_02Alpha mask
Fromblock.png's alpha channel we take the valid pixels (opaque = 1, transparent = 0) so only meaningful areas are compared. -
step_03Background edge map
Apply a simple gradient to the grayscale background (difference against the left/upper pixel) to bring out the contours. -
step_04Template edge map
Run the same edge processing on the cropped slider template so both sides are compared on equal footing. -
Template matching (the key step)
For every candidate(x,y)position in the background, compute the SSE error over the masked pixels:
[
score(x,y)=\frac{1}{N}\sum (bg_edge[y+py][x+px]-tpl_edge[py][px])^2
]
Take thescoreposition with the smallest value as the gap location. -
step_05/step_06Visualisation
step_05draw the matching box;step_06overlay the slider semi-transparently on the matched position to verify the result visually.