// Package vision 提供帧差指纹、图片编码与(可选的)本地检测接口。 package vision import ( "image" "golang.org/x/image/draw" ) // Fingerprint 是用于判断"画面有没有变化"的感知哈希。 type Fingerprint struct { AHash uint64 // 均值哈希 DHash uint64 // 差分哈希 Mean uint8 // 平均亮度 } // grayGrid 把图像缩放到 w×h 的灰度图。 func grayGrid(src image.Image, w, h int) *image.Gray { dst := image.NewGray(image.Rect(0, 0, w, h)) draw.ApproxBiLinear.Scale(dst, dst.Bounds(), src, src.Bounds(), draw.Src, nil) return dst } // Of 计算图像指纹。 func Of(img image.Image) Fingerprint { if img == nil { return Fingerprint{} } small := grayGrid(img, 8, 8) var sum, n int for _, v := range small.Pix { sum += int(v) n++ } avg := sum / max(n, 1) mean := uint8(min(avg, 255)) var aHash uint64 for i, v := range small.Pix { if int(v) > avg { aHash |= 1 << uint(i) } } wide := grayGrid(img, 9, 8) var dHash uint64 for y := 0; y < 8; y++ { for x := 0; x < 8; x++ { l := wide.GrayAt(x, y).Y r := wide.GrayAt(x+1, y).Y if l > r { dHash |= 1 << uint(y*8+x) } } } return Fingerprint{AHash: aHash, DHash: dHash, Mean: mean} } // Distance 返回两个指纹的汉明距离(取两种哈希的较大值,偏向灵敏)。 func (f Fingerprint) Distance(o Fingerprint) int { return max(bitsSet(f.AHash^o.AHash), bitsSet(f.DHash^o.DHash)) } // Changed 判断画面是否发生了足以触发提问的变化。 func (f Fingerprint) Changed(o Fingerprint, threshold int) bool { if threshold <= 0 { threshold = 5 } return f.Distance(o) > threshold } func bitsSet(v uint64) int { n := 0 for v != 0 { v &= v - 1 n++ } return n }