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