-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
美团电影频道的数字都是通过在背景图片上进行偏移获得最终数字。
因为数字的图形是固定的,且每张都是10 * 16像素,可以实现爬取每个数字的图片保存在本地,然后通过爬取的内容根据偏移地址进行计算图片位置,进行切割,并与本地单张数字进行对比,即可获得当前数字。
后面的代码片段用的是go语言。如果用python的话,直接用pytesser进行数字识别。
解决方案
图片采集
先对美团的数字图片(保存名为meituan.png)进行切割并保存10个数字和一个小数点的图片。每张图片像素是10*16。
func main() {
img := loadImage("meituan.png")
n := 1
for x := 0; x < 100; x += 10 {
for y := 0; y < 96; y += 16 {
dd := img.(*image.NRGBA).SubImage(image.Rect(x, y, x+10, y+16))
saveImage(fmt.Sprintf("pic/%d.png", n), dd)
n++
}
}
}
func loadImage(path string) image.Image {
f, err := os.Open(path)
if err != nil {
log.Fatal(err)
}
img, _, err := image.Decode(f)
if err != nil {
log.Fatal(err)
}
return img
}
func saveImage(path string, img image.Image) {
i, _ := os.Create(path)
defer i.Close()
png.Encode(i, img)
}
分析
每个图片数字都是通过backgroud-position进行定位。所以我们只需要两部即可获得数字:
- 下载数字图片,图片并非固定 100 * 96 ,但是最终切割后的图片是 10 * 16
- 切割后和进行对比
切割后的照片,我们传入match函数即可获得最终数字结果:
func match(img image.Image) string {
for x:=0; x<=10; x++ {
i := loadImage(fmt.Sprintf("pic/%d.png", x))
d := diff(img, i)
if d > 0.9 {
if x == 10 {
return "."
}
return strconv.Itoa(x)
}
//log.Infof("%d diff:%f",x, d)
}
return ""
}
// 对比两张图片的相似度
func diff(i1, i2 image.Image) float64 {
r1 := i1.Bounds()
r2 := i2.Bounds()
minX := math.Min(float64(r1.Max.X), float64(r2.Max.X))
minY := math.Max(float64(r1.Max.Y), float64(r2.Max.Y))
c := 0
sum := 0
for x := 0; x < int(minX); x++ {
for y := 0; y < int(minY); y++ {
if i1.At(x, y) == i2.At(x, y) {
c++
}
sum++
}
}
//log.Info(c, sum, float64(c)/float64(sum))
return float64(c)/float64(sum)
}