4步OpenCV-----扫秒身份证号

这段代码用 OpenCV 做了一份"数字模板字典",然后在银行卡/身份证照片里自动找到身份证号那一行,把每个数字切出来跟模板比对,最终输出并高亮显示出完整的身份证号码,下面是代码解释:

模块 1 工具箱(通用函数)

目的:

  • cv_show:调试时弹窗查看中间图像

  • sort_contours:按指定顺序(左→右、上→下等)排列轮廓,避免 OpenCV 随机顺序

代码

复制代码
def cv_show(name, image):
    cv2.imshow(name, image)
    cv2.waitKey(0)

def sort_contours(cnts, method='left-to-right'):
    reverse = False
    i = 0
    if method in ('right-to-left', 'bottom-to-top'):
        reverse = True
    if method in ('top-to-bottom', 'bottom-to-top'):
        i = 1
    boundingBoxes = [cv2.boundingRect(c) for c in cnts]
    (cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
                                        key=lambda b: b[1][i],
                                        reverse=reverse))
    return cnts, boundingBoxes

注意

  • 返回值为元组,后续用 [0] 取排序后的轮廓

  • 若数字多行,可将 method 改为 'top-to-bottom'


模块 2 模板制作(生成 0-9 标准模板)

目的

从干净模板图中切出单个数字 → 统一尺寸(57×88)→ 白底黑字,供后续模板匹配

步骤

  1. 读图

    复制代码
    img = cv2.imread("picture/TP.png")
    gray = cv2.imread("picture/TP.png", 0)
  2. 二值化(数字变白)

    复制代码
    ref = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY_INV)[1]
  3. 找轮廓并排序

    复制代码
    _, refCnts, _ = cv2.findContours(ref, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    refCnts = sort_contours(refCnts, method='left-to-right')[0]
  4. 生成模板字典

    复制代码
    digits = {}
    for (i, c) in enumerate(refCnts):
        x, y, w, h = cv2.boundingRect(c)
        roi = ref[y-2:y+h+2, x-2:x+w+2]
        roi = cv2.resize(roi, (57, 88))
        roi = cv2.bitwise_not(roi)  # 白底黑字
        digits[i] = roi

注意

  • 模板图需无粘连、无干扰

  • 若含小数点/空格,需额外过滤以保证 digits 长度为 10


模块 3 输入图预处理(定位身份证号区域)

目的

在整幅银行卡/身份证中,仅保留"身份证号"水平条带,减少误检

步骤

  1. 读图

    复制代码
    img = cv2.imread('picture/card_id.jpg')
    gray = cv2.imread('picture/card_id.jpg', 0)
  2. 二值化

    复制代码
    ref = cv2.threshold(gray, 120, 255, cv2.THRESH_BINARY_INV)[1]
  3. 找轮廓

    复制代码
    _, refCnts, _ = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
  4. 几何过滤(针对当前图写死坐标)

注意

  • 330/360/220 为经验值,换图需调整

  • 光照不均时建议自适应阈值或亮度归一化


模块 4 单字符切割 + 模板匹配识别

目的

将单行 ROI 切成单个字符,与模板库 0-9 匹配,得分最高者即为识别结果,并绘制边框与文字

步骤

  • 遍历每个候选矩形

    复制代码
    output = []
    for (i, (gX, gY, gW, gH)) in enumerate(locs):
        group = gray[gY-2:gY+gH+2, gX-2:gX+gW+2]
        group = cv2.threshold(group, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
        roi = cv2.resize(group, (57, 88))
  • 模板匹配打分

    复制代码
    scores = []
    for (digit, digitROI) in digits.items():
        result = cv2.matchTemplate(roi, digitROI, cv2.TM_CCOEFF)
        (_, score, _, _) = cv2.minMaxLoc(result)
        scores.append(score)
    jieguo = str(np.argmax(scores))
    output.append(jieguo)
  • 绘制结果

    复制代码
    cv2.rectangle(imgg, (gX-5, gY-5), (gX+gW+5, gY+gH+5), (0, 0, 255), 1)
    cv2.putText(imgg, jieguo, (gX, gY-15), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)
  • 打印整串号码

    复制代码
    print("Card ID #: {}".format("".join(output)))
    cv2.imshow("Image", imgg)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

注意

  • 若印刷为黑底白字,需再次 bitwise_not

  • 仅支持数字 0-9;含字母/X 需扩展模板或改用 CNN

  • 连体数字需先投影分割再识别

相关推荐
闲人编程1 小时前
自动化文件管理:分类、重命名和备份
python·microsoft·分类·自动化·备份·重命名·自动化文件分类
Jonathan Star2 小时前
用Python轻松提取视频音频并去除静音片段
开发语言·python·音视频
AKAMAI2 小时前
Fermyon推出全球最快边缘计算平台:WebAssembly先驱携手Akamai云驱动无服务器技术新浪潮
人工智能·云计算·边缘计算
云雾J视界2 小时前
TMS320C6000 VLIW架构并行编程实战:加速AI边缘计算推理性能
人工智能·架构·边缘计算·dsp·vliw·tms320c6000
想ai抽3 小时前
基于AI Agent的数据资产自动化治理实验
人工智能·langchain·embedding
刘火锅3 小时前
Java 17 环境下 EasyPoi 反射访问异常分析与解决方案(ExcelImportUtil.importExcelMore)
java·开发语言·python
小马过河R4 小时前
AIGC视频生成之Deepseek、百度妙笔组合实战小案例
人工智能·深度学习·计算机视觉·百度·aigc
june-Dai Yi4 小时前
免费的大语言模型API接口
人工智能·语言模型·自然语言处理·chatgpt·api接口
Hi202402174 小时前
Qt+Qml客户端和Python服务端的网络通信原型
开发语言·python·qt·ui·网络通信·qml
王哈哈^_^4 小时前
【数据集】【YOLO】【目标检测】农作物病害数据集 11498 张,病害检测,YOLOv8农作物病虫害识别系统实战训推教程。
人工智能·深度学习·算法·yolo·目标检测·计算机视觉·1024程序员节