当前位置: 首页 > news >正文

身份证号识别案例

代码实现:

import cv2
import numpy as np
import argparse
import myutils
'''
-i shenfenzheng.jpg
-t moban2.png
'''
ap= argparse.ArgumentParser()
ap.add_argument("-i","--image", required=True,help="path to input image")
ap.add_argument("-t","--template", required=True,help="path to template 0cR-A image")
args = vars(ap.parse_args())def cv_show(name,img):cv2.imshow(name,img)cv2.waitKey(0)''' --------模板图像中数字的定位处理----------- '''
img = cv2.imread(args["template"])
cv_show('img',img)
ref =cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv_show('ref',ref)
ref = cv2.threshold(ref,10,255,cv2.THRESH_BINARY_INV)[1]
cv_show('ref',ref)
_,refCnts, hierarchy = cv2.findContours(ref, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img,refCnts,-1,(0,0,255),3)
cv_show('img',img)
refCnts = myutils.sort_contours(refCnts,method="left-to-right")[0]
digits = {}
for(i,c)in enumerate(refCnts):(x,y,w,h)=cv2.boundingRect(c)roi = ref[y:y + h, x:x + w]roi =cv2.resize(roi,(57,88))cv_show('ro',roi)digits[i]= roi
print(digits)
''' --------身份证的图像处理----------- '''
img=cv2.imread(args["image"])
cv_show("img", img)
img=myutils.resize(img,width=600)
cv_show("resize", img)
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv_show("gray", gray)
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))
squareKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
tophat=cv2.morphologyEx(gray,cv2.MORPH_TOPHAT,rectKernel)
#
cv_show("tophat", tophat)
closeX=cv2.morphologyEx(gray,cv2.MORPH_CLOSE,rectKernel)
cv_show("closeX", closeX)
# #
thresh111=cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
cv_show("thresh", thresh111)#
thresh=cv2.morphologyEx(thresh111,cv2.MORPH_CLOSE,squareKernel)
cv_show("thresh1", thresh)
#
_,threshCnts,h=cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts=threshCnts
cur_img=img.copy()
cv2.drawContours(cur_img,cnts,-1,(0,0,255),3)
# cv_show("cur_img", cur_img)
locs=[]
for (i, cnt) in enumerate(cnts):(x, y, w, h) = cv2.boundingRect(cnt)ar=w/float(h)if y>310 and y<320:if x>210:locs.append((x, y, w, h))
locs = sorted(locs , key=lambda x: x[0])
print(locs)
output = []
# 遍历每一个轮廓中的数字
for (x,y,w,h) in locs:roi = thresh111[y:y + h, x:x + w]roi = cv2.resize(roi, (57, 88))'''--------使用模板匹配,计算匹配得分-----------'''scores = []# 在模板中计算每一个得分for (digit, digitROI) in digits.items():result = cv2.matchTemplate(roi, digitROI, cv2.TM_CCOEFF)(_, score, _, _) = cv2.minMaxLoc(result)scores.append(score)output.append(str(np.argmax(scores)))# 画出来cv2.rectangle(img, (x - 5, y - 5), (x + w + 5, y + h + 5), (0, 0, 255), 1)# cv2.putText()是OpenCV库中的一个函数,用于在图像上添加文本。cv2.putText(img, str(np.argmax(scores)), (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)# 得到结果 将一个列表的元素添加到另一个列表的末尾。
# # 打印结果print("shenfenzhenghao #: {}".format("".join(output)))
cv2.imshow("Image", img)
cv2.waitKey(0)

这段代码是一个基于 OpenCV 的身份证号码识别程序,核心逻辑是通过模板匹配识别身份证上的数字。整体流程分为两大部分:模板图像预处理(提取数字模板)和身份证图像预处理 + 数字识别。下面分步骤解析:

一、初始化与参数配置

import cv2
import numpy as np
import argparse
import myutils  # 自定义工具函数(含之前提到的resize、sort_contours等)# 解析命令行参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="身份证图像路径")
ap.add_argument("-t", "--template", required=True, help="数字模板图像路径")
args = vars(ap.parse_args())  # 将参数转为字典格式# 自定义图像显示函数(封装imshow+waitKey,方便调试)
def cv_show(name, img):cv2.imshow(name, img)cv2.waitKey(0)  # 等待按键输入后关闭窗口

作用:导入依赖库,通过命令行接收输入图像(身份证)和模板图像的路径,定义便捷的图像显示函数。

使用时需通过命令行传入参数,例如:python script.py -i shenfenzheng.jpg -t moban2.png

二、模板图像处理(提取数字模板)

这部分的目的是从模板图像中提取 0-9 的数字轮廓,作为后续识别的 "标准模板"。

# 读取模板图像
img = cv2.imread(args["template"])
cv_show('img', img)  # 显示原始模板图像# 转为灰度图(去除颜色干扰)
ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv_show('ref', ref)# 二值化处理(THRESH_BINARY_INV:黑底白字,数字为白色,背景为黑色)
ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]
cv_show('ref', ref)# 查找模板中的轮廓(数字的边缘)
_, refCnts, hierarchy = cv2.findContours(ref, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 在原图上绘制轮廓(红色,线宽3),直观查看模板中的数字轮廓
cv2.drawContours(img, refCnts, -1, (0, 0, 255), 3)
cv_show('img', img)# 按从左到右排序轮廓(确保模板数字顺序为0-9)
refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0]# 存储数字模板(键:数字0-9,值:对应的图像ROI)
digits = {}
for (i, c) in enumerate(refCnts):# 获取轮廓的边界矩形(x,y:左上角坐标;w,h:宽高)(x, y, w, h) = cv2.boundingRect(c)# 裁剪数字区域(ROI)roi = ref[y:y + h, x:x + w]# 统一调整大小为(57,88)(与后续身份证数字区域尺寸一致,便于匹配)roi = cv2.resize(roi, (57, 88))cv_show('ro', roi)  # 显示单个数字模板digits[i] = roi  # 存储:digits[0]对应数字0的模板,digits[1]对应数字1,以此类推print(digits)  # 打印模板字典(调试用)

核心逻辑:通过预处理(灰度化、二值化)突出模板中的数字,提取数字轮廓并排序,最终得到 0-9 的标准数字模板,用于后续匹配。

三、身份证图像处理(定位并识别号码)

这部分是核心,通过预处理定位身份证号码区域,再用模板匹配识别每个数字。

# 读取身份证图像
img = cv2.imread(args["image"])
cv_show("img", img)  # 显示原始身份证图像# 调整图像大小(宽度600,保持比例),统一尺寸便于处理
img = myutils.resize(img, width=600)
cv_show("resize", img)# 转为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv_show("gray", gray)# 定义形态学操作的结构元素(用于增强数字特征)
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))  # 9x3矩形(适合水平方向特征)
squareKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))  # 5x5正方形(适合填充空洞)# 顶帽变换(突出比背景亮的区域,如身份证上的黑色数字在浅色背景上)
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)
cv_show("tophat", tophat)# 闭运算(连接相邻的数字区域,让数字轮廓更完整)
closeX = cv2.morphologyEx(gray, cv2.MORPH_CLOSE, rectKernel)
cv_show("closeX", closeX)# 二值化处理(THRESH_BINARY_INV:数字为白色,背景为黑色;OTSU自动计算阈值)
thresh111 = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
cv_show("thresh", thresh111)# 二次闭运算(填充数字内部的小空洞,优化轮廓)
thresh = cv2.morphologyEx(thresh111, cv2.MORPH_CLOSE, squareKernel)
cv_show("thresh1", thresh)# 查找二值化图像中的轮廓(数字区域的边缘)
_, threshCnts, h = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = threshCnts  # 保存所有轮廓# 在原图上绘制所有轮廓(红色,线宽3),查看轮廓检测效果
cur_img = img.copy()
cv2.drawContours(cur_img, cnts, -1, (0, 0, 255), 3)
# cv_show("cur_img", cur_img)  # 可选:显示带轮廓的图像# 筛选身份证号码所在的轮廓(根据位置特征)
locs = []  # 存储符合条件的轮廓位置
for (i, cnt) in enumerate(cnts):(x, y, w, h) = cv2.boundingRect(cnt)  # 获取轮廓的边界矩形# 筛选条件:根据身份证号码的大致位置(y在310-320之间,x>210)# 注:这是针对特定身份证图像的经验值,不同图像可能需要调整if y > 310 and y < 320:if x > 210:locs.append((x, y, w, h))  # 保存符合条件的轮廓位置# 按x坐标排序(确保数字顺序从左到右,与实际号码一致)
locs = sorted(locs, key=lambda x: x[0])
print(locs)  # 打印筛选后的轮廓位置(调试用)

核心逻辑:通过一系列预处理( resize、灰度化、形态学操作、二值化 )增强身份证上的数字特征,再根据号码的大致位置筛选出目标轮廓,为后续识别做准备。

注意:y>310 and y<320x>210是硬编码的位置条件,依赖于输入图像的尺寸和角度,实际使用时可能需要根据身份证图像调整。

四、模板匹配识别数字

output = []  # 存储识别结果# 遍历每个筛选出的数字区域
for (x, y, w, h) in locs:# 裁剪数字区域的ROI(从二值化图像中提取)roi = thresh111[y:y + h, x:x + w]# 调整尺寸为(57,88)(与模板大小一致,确保匹配准确性)roi = cv2.resize(roi, (57, 88))# 模板匹配:计算当前ROI与每个数字模板的匹配得分scores = []for (digit, digitROI) in digits.items():# 使用TM_CCOEFF方法进行模板匹配(得分越高,匹配度越高)result = cv2.matchTemplate(roi, digitROI, cv2.TM_CCOEFF)(_, score, _, _) = cv2.minMaxLoc(result)  # 获取最高得分scores.append(score)  # 存储与每个数字模板的匹配得分# 取得分最高的模板对应的数字作为识别结果output.append(str(np.argmax(scores)))# 在原图上绘制结果:画矩形框住数字,并标注识别出的数字cv2.rectangle(img, (x - 5, y - 5), (x + w + 5, y + h + 5), (0, 0, 255), 1)  # 红色边框cv2.putText(img, str(np.argmax(scores)), (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)  # 红色文本# 输出最终识别结果
print("身份证号码: {}".format("".join(output)))# 显示标注后的身份证图像
cv2.imshow("Image", img)
cv2.waitKey(0)

核心逻辑:对每个筛选出的数字区域,与之前提取的 0-9 模板进行匹配,通过比较匹配得分确定数字内容,最后将结果绘制在原图上并输出。

总结

整个程序的流程是:

  1. 处理模板图像,提取 0-9 的数字模板;
  2. 预处理身份证图像,通过形态学操作和二值化增强数字特征;
  3. 根据位置特征筛选出身份证号码所在的轮廓;
  4. 用模板匹配识别每个数字,输出最终结果。

注意事项:位置筛选条件(y 和 x 的范围)是经验值,需根据实际身份证图像调整;

模板匹配的准确性依赖于预处理效果(数字轮廓是否清晰)和模板质量;

若身份证图像有倾斜,需先进行矫正,否则可能导致轮廓筛选失败。


文章转载自:

http://XQAi4vYn.pngdc.cn
http://PRGoWiAD.pngdc.cn
http://WdE1H4bo.pngdc.cn
http://7EzMf82z.pngdc.cn
http://FAAoiklV.pngdc.cn
http://qLFwWYlX.pngdc.cn
http://7Dm4bIeX.pngdc.cn
http://y4uVR9aq.pngdc.cn
http://TdpoqNph.pngdc.cn
http://HoW9Pwm7.pngdc.cn
http://ChuHjcRk.pngdc.cn
http://0qLTEbkg.pngdc.cn
http://SRzexpxp.pngdc.cn
http://Qo7Z9F7k.pngdc.cn
http://uHQYsKEK.pngdc.cn
http://Z7dD3ChM.pngdc.cn
http://3XRBw3VG.pngdc.cn
http://zbbcCyes.pngdc.cn
http://QEZUQWCf.pngdc.cn
http://UJu7ewxE.pngdc.cn
http://BkMFPjHc.pngdc.cn
http://BaJbtxbe.pngdc.cn
http://2XE426Zu.pngdc.cn
http://V5qYrCWO.pngdc.cn
http://PHx8USnF.pngdc.cn
http://n6W9oRCz.pngdc.cn
http://ucSxUtKD.pngdc.cn
http://HqQLDib8.pngdc.cn
http://wxqxlwx3.pngdc.cn
http://1hDaPaiM.pngdc.cn
http://www.dtcms.com/a/372991.html

相关文章:

  • 对口型视频创作指南:AI如何让“假唱”变成真艺术?
  • [免费]基于Python的协同过滤电影推荐系统(Django+Vue+sqlite+爬虫)【论文+源码+SQL脚本】
  • Spark RDD转DataFrame的三种方式
  • Gradio全解10——Streaming:流式传输的音频应用(7)——ElevenLabs:高级智能语音技术
  • 通义万相wan2.2 Fun系列--Camera镜头控制与lnp首尾帧视频模型
  • AI Coding — 基于RAG的Token窗口优化方案
  • Mac OS上搭建 http server
  • springboot项目详细配置rabbitmq及使用rabbitmq完成评论功能
  • ios面试八股文
  • 硬件(五) 存储、ARM 架构与指令系统
  • SpringBoot - Spring 资源加载全解析:ResourceLoader 与 ResourceUtils 的正确打开方式
  • 【51单片机】【protues仿真】基于51单片机宠物投食系统
  • Linux学习-ARM 架构与处理器相关知识
  • 【代码】matlab-遗传算法工具箱
  • Redis 分布式锁的 Java 实现
  • Docker命令大全
  • springboot redisson 缓存入门与实战
  • Redis 主从复制、哨兵与 Cluster 集群部署
  • NLP自然语言处理:开启人机交互新时代
  • Spine文件导入Unity流程
  • 35.Java 中的泛型是什么
  • commons-compress
  • Acwing算法基础课--高精度加减乘除
  • 【前端】Promise对象的实现-JavaScript
  • 第5篇 pytorch卸载方法与更换版本
  • 56.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--新增功能--实现手机邮箱找回密码
  • 月2期学习笔记
  • [新启航]新启航激光频率梳方案:击穿光学遮挡壁垒,以 2μm 精度实现 130mm 深孔 3D 轮廓测量
  • 51单片机驱动数码管
  • 51单片机基础结构及编程要点