commit
d1818b16b2
@ -0,0 +1,3 @@
|
||||
.idea
|
||||
go.sum
|
||||
*.jpg
|
||||
@ -0,0 +1,5 @@
|
||||
module IdSense
|
||||
|
||||
go 1.18
|
||||
|
||||
require github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||
@ -0,0 +1,259 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/nfnt/resize"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"image/jpeg"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var Signs = map[string]string{
|
||||
"0": "0011111001111111011100110110000101100001011000010011111100000110",
|
||||
"1": "0010000001100000011000000110000011111110111111100111111000000000",
|
||||
"2": "1000011010001110100011101001101010011010111100101111001001100010",
|
||||
"3": "0100001101000011010100110111000101111011011111110100111000000110",
|
||||
"4": "0000110000111100011111001110110011001110000111100001110000001000",
|
||||
"5": "0001000001110001011100010111000101111011010111110100111000001100",
|
||||
"7": "0100000001000000010001110100111101011100011110000111000001100000",
|
||||
"9": "0111000001111000110110111001111011011110111111001111100001110000",
|
||||
}
|
||||
|
||||
func main() {
|
||||
// 打开文件
|
||||
// 配合bilibili视频 https://www.bilibili.com/video/BV19L4y1T7sE
|
||||
f, _ := os.Open("id.jpg")
|
||||
defer f.Close()
|
||||
|
||||
// 解析图片
|
||||
img, err := jpeg.Decode(f)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
img = catImg(img)
|
||||
|
||||
img = bin01(img)
|
||||
|
||||
img = minImg(img)
|
||||
imgs := splitImg(img)
|
||||
showImgs(imgs)
|
||||
id := analyse(imgs)
|
||||
log.Println(id)
|
||||
|
||||
}
|
||||
|
||||
// 数字识别
|
||||
func analyse(srcs []image.Image) string {
|
||||
id := ""
|
||||
|
||||
for i := 0; i < len(srcs); i++ {
|
||||
// 获取图片的指纹
|
||||
|
||||
sign := ""
|
||||
for x := 0; x < srcs[i].Bounds().Dx(); x++ {
|
||||
for y := 0; y < srcs[i].Bounds().Dy(); y++ {
|
||||
r, _, _, _ := srcs[i].At(x, y).RGBA()
|
||||
//黑白灰阈值
|
||||
if r > 0x7777 {
|
||||
sign += "1"
|
||||
} else {
|
||||
sign += "0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 对比指纹
|
||||
mb := ""
|
||||
percent := 0.0
|
||||
for k, v := range Signs {
|
||||
sum := 0
|
||||
for i := 0; i < 64; i++ {
|
||||
if v[i:i+1] == sign[i:i+1] {
|
||||
sum++
|
||||
}
|
||||
}
|
||||
|
||||
if float64(sum)/64 > percent {
|
||||
mb = k
|
||||
percent = float64(sum) / 64
|
||||
}
|
||||
}
|
||||
|
||||
//log.Println("output-"+strconv.Itoa(i)+".jpg", sign, mb, percent)
|
||||
fmt.Println("output-"+strconv.Itoa(i)+".jpg", sign, mb, percent)
|
||||
id += mb
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
// 切割图片
|
||||
func splitImg(src image.Image) []image.Image {
|
||||
var dsts []image.Image
|
||||
|
||||
posx := 0
|
||||
for x := 0; x < src.Bounds().Dx(); x++ {
|
||||
|
||||
found := false
|
||||
for y := 0; y < src.Bounds().Dy(); y++ {
|
||||
r, _, _, _ := src.At(x, y).RGBA()
|
||||
if r == 0xFFFF {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
continue
|
||||
}
|
||||
|
||||
dst := image.NewGray16(image.Rect(0, 0, x-posx, src.Bounds().Dy()))
|
||||
draw.Draw(dst, dst.Bounds(), src, image.Point{X: posx, Y: 0}, draw.Src)
|
||||
|
||||
// 下一个起点
|
||||
for xx := x + 1; xx < src.Bounds().Dx(); xx++ {
|
||||
found := false
|
||||
for y := 0; y < src.Bounds().Dy(); y++ {
|
||||
r, _, _, _ := src.At(xx, y).RGBA()
|
||||
if r == 0xFFFF {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if found {
|
||||
posx = xx
|
||||
x = xx
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
//使用第三方库将图片重置为8**
|
||||
img := resize.Resize(8, 8, dst, resize.Lanczos3)
|
||||
dsts = append(dsts, img)
|
||||
}
|
||||
|
||||
return dsts
|
||||
}
|
||||
|
||||
// 去边
|
||||
func minImg(src image.Image) image.Image {
|
||||
// 第一个白点 和 最后一个白点的坐标
|
||||
rect := src.Bounds()
|
||||
|
||||
var (
|
||||
lt, rb image.Point
|
||||
)
|
||||
|
||||
// 左上角x
|
||||
for x := 0; x < rect.Dx(); x++ {
|
||||
for y := 0; y < rect.Dy(); y++ {
|
||||
r, _, _, _ := src.At(x, y).RGBA()
|
||||
if r == 0xFFFF {
|
||||
lt.X = x
|
||||
x = rect.Dx()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// 左上角y
|
||||
for y := 0; y < rect.Dy(); y++ {
|
||||
for x := 0; x < rect.Dx(); x++ {
|
||||
r, _, _, _ := src.At(x, y).RGBA()
|
||||
if r == 0xFFFF {
|
||||
lt.Y = y
|
||||
y = rect.Dy()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// 右下角x
|
||||
for x := rect.Dx() - 1; x > 0; x-- {
|
||||
for y := rect.Dy() - 1; y > 0; y-- {
|
||||
r, _, _, _ := src.At(x, y).RGBA()
|
||||
if r == 0xFFFF {
|
||||
rb.X = x + 1
|
||||
x = 0
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// 右下角y
|
||||
for y := rect.Dy() - 1; y > 0; y-- {
|
||||
for x := rect.Dx() - 1; x > 0; x-- {
|
||||
r, _, _, _ := src.At(x, y).RGBA()
|
||||
if r == 0xFFFF {
|
||||
rb.Y = y
|
||||
y = 0
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newRect := image.Rect(0, 0, rb.X-lt.X+1, rb.Y-lt.Y)
|
||||
log.Println(lt, rb)
|
||||
log.Println(src.Bounds(), newRect)
|
||||
dst := image.NewRGBA(newRect)
|
||||
draw.Draw(dst, dst.Bounds(), src, lt, draw.Over)
|
||||
return dst
|
||||
}
|
||||
|
||||
// 二值化
|
||||
func bin01(src image.Image) image.Image {
|
||||
dst := image.NewGray16(src.Bounds())
|
||||
draw.Draw(dst, dst.Bounds(), src, src.Bounds().Min, draw.Over)
|
||||
|
||||
rect := src.Bounds()
|
||||
for x := 0; x < rect.Dx(); x++ {
|
||||
for y := 0; y < rect.Dy(); y++ {
|
||||
r, _, _, _ := dst.At(x, y).RGBA()
|
||||
if r < 0x5555 {
|
||||
dst.Set(x, y, color.White)
|
||||
} else {
|
||||
dst.Set(x, y, color.Black)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// 预览图片
|
||||
func showImg(src image.Image) {
|
||||
dst, err := os.Create("output.jpg")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
jpeg.Encode(dst, src, nil)
|
||||
}
|
||||
|
||||
// 预览图片组
|
||||
func showImgs(srcs []image.Image) {
|
||||
for i := 0; i < len(srcs); i++ {
|
||||
dst, err := os.Create(fmt.Sprintf("output-%d.jpg", i))
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
jpeg.Encode(dst, srcs[i], nil)
|
||||
}
|
||||
}
|
||||
|
||||
// 号码定位
|
||||
func catImg(src image.Image) image.Image {
|
||||
rect := src.Bounds()
|
||||
// 左上角 w*100/290, h*150/180
|
||||
lt := image.Point{X: rect.Dx() * 100 / 290, Y: rect.Dy() * 150 / 180}
|
||||
// 右下角 w*260/290, h*170/180
|
||||
rb := image.Point{X: rect.Dx() * 260 / 290, Y: rect.Dy() * 165 / 180}
|
||||
newRect := image.Rectangle{
|
||||
Min: image.Point{X: 0, Y: 0},
|
||||
Max: image.Point{X: rb.X - lt.X, Y: rb.Y - lt.Y},
|
||||
}
|
||||
dst := image.NewRGBA(newRect)
|
||||
draw.Draw(dst, dst.Bounds(), src, lt, draw.Over)
|
||||
return dst
|
||||
}
|
||||
Loading…
Reference in new issue