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)) } } }