-
Notifications
You must be signed in to change notification settings - Fork 2
/
search.go
80 lines (68 loc) · 1.98 KB
/
search.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package locateimage
import (
"context"
"image"
)
func foreachRGBA(ctx context.Context, canvas, sample *image.RGBA, tolerance float64, f func(m Match) error) error {
const pixSize = 4
strideCanv, strideSamp := canvas.Stride, sample.Stride
pixCanv, pixSamp := canvas.Pix, sample.Pix
// ocanv, osamp := canvas.Rect.Min, sample.Rect.Min
wcanv, hcanv, wsamp, hsamp := canvas.Rect.Dx(), canvas.Rect.Dy(), sample.Rect.Dx(), sample.Rect.Dy()
if wcanv < wsamp || hcanv < hsamp || wsamp == 0 || hsamp == 0 {
return nil
}
hcanv -= hsamp - 1
wcanv -= wsamp - 1
pixelTolerance := 2 * tolerance
pixelDiffThreshold := int64(3*256*pixelTolerance + 0.5)
maxTotalDiff := int64(wcanv) * int64(hcanv) * 3 * 255
totalDiffThreshold := int64(tolerance*float64(maxTotalDiff) + 0.5)
rowsampmax := strideSamp * hsamp
for y := 0; y < hcanv; y++ {
firstrowcanv := y * strideCanv
if err := ctx.Err(); err != nil {
return err
}
for x := 0; x < wcanv; x++ {
rowcanv := firstrowcanv + x*pixSize
matched := true
diff := int64(0)
matchLoop:
for rowsamp := 0; rowsamp < rowsampmax; rowsamp += strideSamp {
icanv := rowcanv
isamp := rowsamp
isampmax := rowsamp + pixSize*wsamp
for isamp < isampmax {
d0 := abs(int64(pixCanv[icanv+0]) - int64(pixSamp[isamp+0]))
d1 := abs(int64(pixCanv[icanv+1]) - int64(pixSamp[isamp+1]))
d2 := abs(int64(pixCanv[icanv+2]) - int64(pixSamp[isamp+2]))
delta := d0 + d1 + d2
if delta > pixelDiffThreshold {
matched = false
break matchLoop
}
diff += delta
if diff > totalDiffThreshold {
matched = false
break matchLoop
}
icanv += pixSize
isamp += pixSize
}
rowcanv += strideCanv
}
if matched {
pt := canvas.Rect.Min.Add(image.Point{x, y})
err := f(Match{
Rect: image.Rectangle{pt, pt.Add(image.Point{wsamp, hsamp})},
Similarity: 1 - float64(diff)/float64(maxTotalDiff),
})
if err != nil {
return err
}
}
}
}
return nil
}