身份证号码简易识别

master
dustoair 3 years ago
commit d1818b16b2

3
.gitignore vendored

@ -0,0 +1,3 @@
.idea
go.sum
*.jpg

@ -0,0 +1,22 @@
https://www.bilibili.com/video/BV19L4y1T7sE
https://www.bilibili.com/video/BV19L4y1T7sE?p=6
https://gist.github.com/ohko/5fd4f294c89d4f11ede58255c5f625aa
【golang】身份证号码识别
最关键的定位和识别 没有深度,图片可能位置不一样有失真,变形。角度不可能和照片垂直,所以图像不可能这样简单被定位出来
大致的思路就是1.二值化 2.腐蚀(让黑的地方变粗、变粗、变粗) ,就会形成一些黑块 3.找到长宽比例是身份证长宽比例的黑块 4.把这个黑块切割出来。
```go
var Signs = map[string]string{
"0": "0000000001000010000000000000000000000000000000000100001000011000",
"1": "0000000000000000010000000100000001000000010010100100001001100000",
"2": "0000000000000100000000011000100100000000000100000100000000100000",
"3": "0000000000000000000000000001000000010000010000000100101000000100",
"5": "0000000001100000000000000000000000000000000100100000110000000100",
"9": "0010000001000000000010000000000000000000000011000100100000000000",
"6": "0000000000001010000100000000000001000000000000000000101000000000",
}
```

@ -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…
Cancel
Save