golang识别身份证号

使用go做身份证号码识别

1.本实例主要是学习使用image库
2.实现思路:
(1).获取图片
(2).对图片指定区域进行裁剪
(3).将图片进行二值化,使用黑白两色作为区分
(4).去掉图片无用的边缘
(5).将数字进行裁剪为一张一张的小图片
(6).将图片使用0和1来进行数据化
(7).使用提前准备的指纹库进行数据相似度对比

实例图片请添加图片描述
实现代码
package main

import (
	"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 := 0
	num := ""
	for n, sign := range numSign {
		tmpSimilarity := 0
		signArr := strings.Split(sign, "")
		for k, s := range imgBinarySign {
			if s == signArr[k] {
				tmpSimilarity++
			}
		}
		if maxSimilarity < tmpSimilarity {
			maxSimilarity = tmpSimilarity
			num = 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 := 0
	nowCutEndX := 0
	for x := 0; x <= rect.Dx(); x++ {
		lxflag := true
		for y := 0; y < rect.Dy(); y++ {
			// 获取颜色
			r, _, _, _ := img.At(x, y).RGBA()
			if r == 0x0000 {
				continue
			} else {
				// 读取到最新一个白点作为截取结束x坐标
				nowCutEndX = x
				lxflag = false
				break
			}
		}
		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 := 0
	for x := 0; x < rect.Dx(); x++ {
		lxflag := false
		for y := 0; y < rect.Dy(); y++ {
			// 获取颜色
			r, _, _, _ := img.At(x, y).RGBA()
			if r == 0xFFFF {
				lxflag = true
				break
			}
		}
		if lxflag {
			leftStartX = x
			break
		}
	}
	// 开始y坐标
	leftStartY := 0
	for y := 0; y < rect.Dy(); y++ {
		lyflag := false
		for x := 0; x < rect.Dx(); x++ {
			// 获取颜色
			r, _, _, _ := img.At(x, y).RGBA()
			if r == 0xFFFF {
				lyflag = true
				break
			}
		}
		if lyflag {
			leftStartY = y
			break
		}
	}
	// 结束x坐标
	rightEndX := 0
	for x := rect.Dx(); x > 0; x-- {
		rxflag := false
		for y := rect.Dy(); y > 0; y-- {
			// 获取颜色
			r, _, _, _ := img.At(x, y).RGBA()
			if r == 0xFFFF {
				rxflag = true
				break
			}
		}
		if rxflag {
			rightEndX = x
			break
		}
	}
	// 结束y坐标
	rightEndY := 0
	for y := rect.Dy(); y > 0; y-- {
		ryflag := false
		for x := rect.Dy(); x > 0; x-- {
			// 获取颜色
			r, _, _, _ := img.At(x, y).RGBA()
			if r == 0xFFFF {
				ryflag = true
				break
			}
		}
		if ryflag {
			rightEndY = y
			break
		}
	}
	// 创建新的图片
	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))
		}
	}
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值