package vision import ( "image" "math" ) // MatchResult 模板匹配结果 type MatchResult struct { Point image.Point Score float64 // 相似度分数 (0.0 - 1.0) } // FindTemplate 在当前画布中查找子图 (模板匹配) // 使用简单的平方差和 (Sum of Squared Differences) 算法 func (c *Canvas) FindTemplate(template *Canvas) MatchResult { src := c.dc.Image() tpl := template.dc.Image() srcBounds := src.Bounds() tplBounds := tpl.Bounds() sw, sh := srcBounds.Dx(), srcBounds.Dy() tw, th := tplBounds.Dx(), tplBounds.Dy() if tw > sw || th > sh { return MatchResult{Score: 0} } bestPoint := image.Point{} minDiff := math.MaxFloat64 // 为了性能,在大图中进行步长采样 step := 1 if sw > 500 || sh > 500 { step = 2 } for y := 0; y <= sh-th; y += step { for x := 0; x <= sw-tw; x += step { diff := 0.0 // 简单的像素比较 for ty := 0; ty < th; ty += 2 { for tx := 0; tx < tw; tx += 2 { sr, sg, sb, _ := src.At(x+tx, y+ty).RGBA() tr, tg, tb, _ := tpl.At(tx, ty).RGBA() dr := float64(sr>>8) - float64(tr>>8) dg := float64(sg>>8) - float64(tg>>8) db := float64(sb>>8) - float64(tb>>8) diff += dr*dr + dg*dg + db*db } } if diff < minDiff { minDiff = diff bestPoint = image.Point{X: x, Y: y} } } } // 归一化分数 (1.0 为完美匹配) // 最大可能差异:(255*255 * 3) * (tw/2 * th/2) maxPossibleDiff := (255.0 * 255.0 * 3.0) * (float64(tw) / 2.0 * float64(th) / 2.0) score := 1.0 - (minDiff / maxPossibleDiff) if score < 0 { score = 0 } return MatchResult{ Point: bestPoint, Score: score, } }