使用go做身份证号码识别
1.本实例主要是学习使用image库
2.实现思路:
(1).获取图片
(2).对图片指定区域进行裁剪
(3).将图片进行二值化,使用黑白两色作为区分
(4).去掉图片无用的边缘
(5).将数字进行裁剪为一张一张的小图片
(6).将图片使用0和1来进行数据化
(7).使用提前准备的指纹库进行数据相似度对比
实例图片
实现代码
package mainimport ("fmt""github.com/nfnt/resize""image""image/color""image/draw""image/jpeg""os""strconv""strings"
)// 指纹验证
var numSign = map[int]string{0: "0011111001111111111000111100000111000001110000010111111100111110",1: "0000000000110000001000000110000001100000011111111111111111111111",2: "0110001101100011110001111100010111001101110110010111100100110000",4: "0000010000001110000111100011011001100110111111110111111100000110",6: "0011111001111111010110011101000111010001110110010100111101001110",8: "0000011001111111011111011101100111011001110110010111111101110111",
}// 读取图片
func main() {// 打开图片imgFile, err := os.Open("./img/idcard.jpeg")if err != nil {panic(fmt.Sprintf("打开文件失败:%+v", err))}defer imgFile.Close()// 解析图片img, err := jpeg.Decode(imgFile)if err != nil {panic(fmt.Sprintf("解析图片失败:%+v", err))}locImg := imgLocation(img)binImg := imgBinarzation(locImg)imgCutSide := imgCutSide(binImg)imgCutSilce := imgCutSilce(imgCutSide)//imgView(imgCutSilce...)imgNum := imgDiscern(imgCutSilce)fmt.Println(imgNum)
}// 指纹验证
func imgSign(imgBinary string) string {if imgBinary == "" {return imgBinary}imgBinarySign := strings.Split(imgBinary, "")// 相似度maxSimilarity := 0num := ""for n, sign := range numSign {tmpSimilarity := 0signArr := strings.Split(sign, "")for k, s := range imgBinarySign {if s == signArr[k] {tmpSimilarity++}}if maxSimilarity < tmpSimilarity {maxSimilarity = tmpSimilaritynum = strconv.Itoa(n)}}return num
}// 图片识别 将图片转换为01的数据 进行验证
func imgDiscern(imgs []image.Image) string {signNum := make([]string, 0)for _, img := range imgs {tmpSignNum := make([]string, 0)rect := img.Bounds()for x := 0; x < rect.Dx(); x++ {for y := 0; y < rect.Dy(); y++ {// 获取颜色r, _, _, _ := img.At(x, y).RGBA()if r > 0x7788 {tmpSignNum = append(tmpSignNum, "1")} else {tmpSignNum = append(tmpSignNum, "0")}}}signNum = append(signNum, strings.Join(tmpSignNum, ""))}res := make([]string, 0)for _, v := range signNum {res = append(res, imgSign(v))}return strings.Join(res, "")
}// 图片切片 判断是否白色结束 黑色开始
func imgCutSilce(img image.Image) []image.Image {rect := img.Bounds()imgs := make([]image.Image, 0)// 记录当前x的位置nowCutStartX := 0nowCutEndX := 0for x := 0; x <= rect.Dx(); x++ {lxflag := truefor y := 0; y < rect.Dy(); y++ {// 获取颜色r, _, _, _ := img.At(x, y).RGBA()if r == 0x0000 {continue} else {// 读取到最新一个白点作为截取结束x坐标nowCutEndX = xlxflag = falsebreak}}if lxflag {// 当读取到x轴只有黑色时, 并且读取到白色为当前黑色前一个像素 则做处理if nowCutEndX == x-1 {// 创建新的图片rectangle := image.Rectangle{Min: image.Point{X: 0, Y: 0},Max: image.Point{X: x - nowCutStartX, Y: rect.Dy()},}newImg := image.NewGray(rectangle)draw.Draw(newImg, newImg.Bounds(), img, image.Point{X: nowCutStartX, Y: 0}, draw.Over)newResizeImg := resize.Resize(8, 8, newImg, resize.Lanczos3)imgs = append(imgs, newResizeImg)} else {// 记录x轴截取开始位置nowCutStartX = x + 1}}}return imgs
}// 删除边 判断边缘是否为白色
func imgCutSide(img image.Image) image.Image {rect := img.Bounds()// 开始x坐标leftStartX := 0for x := 0; x < rect.Dx(); x++ {lxflag := falsefor y := 0; y < rect.Dy(); y++ {// 获取颜色r, _, _, _ := img.At(x, y).RGBA()if r == 0xFFFF {lxflag = truebreak}}if lxflag {leftStartX = xbreak}}// 开始y坐标leftStartY := 0for y := 0; y < rect.Dy(); y++ {lyflag := falsefor x := 0; x < rect.Dx(); x++ {// 获取颜色r, _, _, _ := img.At(x, y).RGBA()if r == 0xFFFF {lyflag = truebreak}}if lyflag {leftStartY = ybreak}}// 结束x坐标rightEndX := 0for x := rect.Dx(); x > 0; x-- {rxflag := falsefor y := rect.Dy(); y > 0; y-- {// 获取颜色r, _, _, _ := img.At(x, y).RGBA()if r == 0xFFFF {rxflag = truebreak}}if rxflag {rightEndX = xbreak}}// 结束y坐标rightEndY := 0for y := rect.Dy(); y > 0; y-- {ryflag := falsefor x := rect.Dy(); x > 0; x-- {// 获取颜色r, _, _, _ := img.At(x, y).RGBA()if r == 0xFFFF {ryflag = truebreak}}if ryflag {rightEndY = ybreak}}// 创建新的图片rectangle := image.Rectangle{Min: image.Point{X: 0, Y: 0},Max: image.Point{X: rightEndX - leftStartX, Y: rightEndY - leftStartY},}newSideImg := image.NewGray(rectangle)draw.Draw(newSideImg, newSideImg.Bounds(), img, image.Point{X: leftStartX, Y: leftStartY}, draw.Over)return newSideImg
}// 二值化 去掉多余的颜色 使用黑白色进行图片渲染
func imgBinarzation(img image.Image) image.Image {binImg := image.NewGray16(img.Bounds())draw.Draw(binImg, binImg.Bounds(), img, img.Bounds().Min, draw.Over)rect := binImg.Bounds()// 遍历点像素点for x := 0; x < rect.Dx(); x++ {for y := 0; y < rect.Dy(); y++ {// 获取颜色r, _, _, _ := binImg.At(x, y).RGBA()if r < 0x7788 {binImg.Set(x, y, color.White)} else {binImg.Set(x, y, color.Black)}}}return binImg
}// 根据左上角 和 右下角的坐标来确定要截取生成新的图片
func imgLocation(img image.Image) image.Image {rect := img.Bounds()// 左上角的坐标 x: w(总宽度)*测量x轴的位置/测量总x的宽度// 左上角的坐标 y: h(总高度)*测量y轴的位置/测量总y的高度leftLoc := image.Point{X: rect.Dx() * 200 / 606, Y: rect.Dy() * 315 / 383}// 右下角的坐标 x: w(总宽度)*测量x轴的位置/测量总x的宽度// 右下角的坐标 y: h(总高度)*测量y轴的位置/测量总y的高度rightLoc := image.Point{X: rect.Dx() * 474 / 606, Y: rect.Dy() * 340 / 383}// 设置新生成图片的坐标位置rectangle := image.Rectangle{Min: image.Point{X: 0, Y: 0},Max: image.Point{X: rightLoc.X - leftLoc.X, Y: rightLoc.Y - leftLoc.Y},}// 新建图片locImg := image.NewNRGBA(rectangle)draw.Draw(locImg, locImg.Bounds(), img, leftLoc, draw.Over)return locImg
}// 图片预览
func imgView(img ...image.Image) {for i := 0; i < len(img); i++ {dts, err := os.Create(fmt.Sprintf("./view/cutImg%d.jpeg", i))if err != nil {panic(fmt.Sprintf("创建失败:%+v", err))}defer dts.Close()err = jpeg.Encode(dts, img[i], nil)if err != nil {panic(fmt.Sprintf("写入图片失败:%+v", err))}}
}