基于opencv-python的身份证识别(KNN与OCR两种算法)

        本文是学习opencv之初的一个阶段性小任务,主要做练习使用,并没有过多的追求准确率和高可用性,比如对输入身份证照片有要求,必须是完全的身份证照片,不能有背景,如需改进,可以通过增加轮廓检测透视变换来裁剪出身份证照片;还有对身份证号区域的检测,采用的是先裁剪出一个固定大小的模板,进行模板匹配,当时学的比较浅,所以直接草率的这样做了,其实也可以通过轮廓检测排序,从而查找到身份证号区域。

        另外,利用KNN算法做识别,也是我当时刚接触KNN算法,一时兴起做的,这算是我初次做算法模型训练,然后进行检测,也是为后来学习的各种深度学习算法打基础。效果并不是很好,因为我训练用到的数据集就是最后那一张图片(trainum.png),进行了少量的数据集增强。

KNN  train训练程序(train.py):

# -*-coding:utf-8-*-
# @Author: Phantom
# @编译环境:windows 10 + python3.8
# @IDE:Pycharm2021.1.3

import cv2.cv2 as cv
import numpy as np

def KNN():
    train = cv.imread("trainum.png", 0)
    # 24*32
    trainimgs = [train]
    # 腐蚀和膨胀,增强训练集
    for i in range(1,3):
        kernel = np.ones((i, i), np.uint8)
        j = cv.erode(train, kernel)
        trainimgs.append(j)
        r = cv.dilate(train, kernel)
        trainimgs.append(r)
    # 生成knn对象
    knn = cv.ml.KNearest_create()
    #训练knn模型
    for trainimg in trainimgs:
        cells = [np.hsplit(row, 30) for row in np.vsplit(trainimg, 11)]

        x = np.array(cells)
        # print(x[1][1])
        trn = x[:, :].reshape(-1,768).astype(np.float32)
        k = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
        train_label = np.repeat(k,30)
        knn.train(trn,cv.ml.ROW_SAMPLE,train_label)


    cell = [np.hsplit(row, 30) for row in np.vsplit(train, 11)]
    x = np.array(cell)
    # print(x[1][1])
    train = x[:, :].reshape(-1, 768).astype(np.float32)
    t = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
    train_label = np.repeat(t, 30)
    return knn,train,train_label

def main():
    knn ,train,train_label= KNN()

    test = train.copy()
    test_label = train_label.copy()
    ret, result, neighbours, dist = knn.findNearest(test, 3)
    right = 0
    for i in range(330):
        if result[i] == test_label[i]:
            right+=1
    # print(f'{len(test):}个测试数据识别正确{right:}个')
    #计算正确率
    ac = right/result.size
    print(f'正确率{ac*100:.2f}%')

if __name__ == '__main__':
    main()
    cv.waitKey(0)

KNN算法主程序:

# -*-coding:utf-8-*-
# @Author: Phantom
# @编译环境:windows 10 + python3.8
# @IDE:Pycharm2021.1.3

import cv2.cv2 as cv
import numpy as np
import train

# 读取图片和身份证号位置模板
idimg = cv.imread("033.jpg")
idimg = cv.resize(idimg, (509, 321), interpolation=cv.INTER_CUBIC)
template = cv.imread("position1.jpg", 1)
cv.imshow("idimg", idimg)
# 转灰度图
gray = cv.cvtColor(idimg, cv.COLOR_BGR2GRAY)
cv.imshow("gray", gray)
# 黑帽运算闭运算的卷积核
kernel1 = np.ones((15, 15), np.uint8)
# kernel2 = np.ones((1,1),np.uint8)
# 黑帽运算
cvblackhat = cv.morphologyEx(gray, cv.MORPH_BLACKHAT, kernel1)
cv.imshow("black", cvblackhat)
# 闭运算
cvclose1 = cv.morphologyEx(cvblackhat, cv.MORPH_CLOSE, kernel1)
cv.imshow("cvclose", cvclose1)
# 原图像二值化
ref = cv.threshold(cvclose1, 0, 255, cv.THRESH_OTSU)[1]
# 身份证号码区域二值化
twoimg = cv.threshold(cvblackhat, 0, 255, cv.THRESH_OTSU)[1]
cv.imshow("ref", ref)
# 为了模板匹配
cv.imwrite("ref.jpg", ref)
ref = cv.imread("ref.jpg", 1)
# 获取模板高和宽
h, w = template.shape[:2]
# 模板匹配(相关匹配)找身份证号码位置
res = cv.matchTemplate(ref, template, cv.TM_CCORR)
# 获得最匹配地方的左上角坐标
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)
top_left = max_loc
# 计算最匹配地方的右下角坐标
bottom_right = (top_left[0] + w, top_left[1] + h)
# 框出身份证号区域并展示
cv.rectangle(idimg, top_left, bottom_right, (0, 255, 0), 2)
cv.imshow("idimgOK", idimg)
# 展示身份证号码的二值图像
rectangleid = cv.resize(twoimg[top_left[1]:bottom_right[1], top_left[0]:bottom_right[0]], (432, 32),
                        interpolation=cv.INTER_CUBIC)
# rectangleid = cv.erode(rectangleid,kernel2)
cv.imshow("rectangleid", rectangleid)

# 划分获得每一个数字的图像
cells = [np.hsplit(row, 18) for row in np.vsplit(rectangleid, 1)]

# 转换成np.array类型
x = np.array(cells)
cv.imshow("cell9", x[0][9])
cv.imshow("cell10", x[0][10])
# 图像数据转换为特征矩阵
test = x[:, :].reshape(-1, 768).astype(np.float32)
# 获得训练好的knn模型
knn = train.KNN()
# 测试
ret, result, neighbours, dist = knn.findNearest(test, 2)
# 输出预测结果
result = np.uint8(result).reshape(-1, 18)[0]
id = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "X"]
idstr = ""
for i in result:
    idstr += id[i]
print(idstr)

cv.waitKey(0)

 OCR算法主程序 (这里改进为百度的paddleOCR识别率会更高)

# -*-coding:utf-8-*-
# @Author: Phantom
# @编译环境:windows 10 + python3.8
# @IDE:Pycharm2021.1.3

import cv2.cv2 as cv
import numpy as np
import pytesseract

# 读取图片和身份证号位置模板
idimg = cv.imread("0033.jpg")
idimg = cv.resize(idimg, (509, 321), interpolation=cv.INTER_CUBIC)
idimgok = idimg.copy()
template = cv.imread("position1.jpg", 1)
cv.imshow("idimg", idimg)
# 转灰度图
gray = cv.cvtColor(idimg, cv.COLOR_BGR2GRAY)
cv.imshow("gray", gray)
# 黑帽运算闭运算的卷积核
kernel1 = np.ones((15, 15), np.uint8)
# kernel2 = np.ones((1,1),np.uint8)
# 黑帽运算
cvblackhat = cv.morphologyEx(gray, cv.MORPH_BLACKHAT, kernel1)
cv.imshow("black", cvblackhat)
# 闭运算
cvclose1 = cv.morphologyEx(cvblackhat, cv.MORPH_CLOSE, kernel1)
cv.imshow("cvclose", cvclose1)
# 原图像二值化
ref = cv.threshold(cvclose1, 0, 255, cv.THRESH_OTSU)[1]
# 身份证号码区域二值化
twoimg = cv.threshold(cvblackhat, 0, 255, cv.THRESH_OTSU)[1]
cv.imshow("ref", ref)
# 为了模板匹配
cv.imwrite("ref.jpg", ref)
ref = cv.imread("ref.jpg", 1)
# 获取模板高和宽
h, w = template.shape[:2]
# 模板匹配(相关匹配)找身份证号码位置
res = cv.matchTemplate(ref, template, cv.TM_CCORR)
# 获得最匹配地方的左上角坐标
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)
top_left = max_loc
# 计算最匹配地方的右下角坐标
bottom_right = (top_left[0] + w, top_left[1] + h)
# 框出身份证号区域并展示
cv.rectangle(idimg, top_left, bottom_right, (0, 255, 0), 2)
cv.imshow("idimgOK", idimg)
# 展示身份证号码的二值图像
rectangleid = cv.resize(idimgok[top_left[1] - 2:bottom_right[1] + 2, top_left[0] - 2:bottom_right[0] + 2], (436, 36),
                        interpolation=cv.INTER_CUBIC)
# rectangleid = cv.erode(rectangleid,kernel2)
cv.imshow("rectangleid", rectangleid)
text = pytesseract.image_to_string(rectangleid)
print(text)

cv.waitKey(0)

 程序中所用到的图片         

0033.jpg为标准身份证照片

                                                                     position1.jpg

                                                                 trainum.png

<think>好的,我现在需要帮助用户找到使用JavaOpenCV实现身份证边缘检测的代码示例或者逻辑。首先,我需要回忆一下OpenCV在Java中的使用方法,以及身份证边缘检测的常见步骤。 用户之前提到了OCR图像预处理,引用的内容里也提到了Canny边缘检测,这可能相关。身份证边缘检测通常是为了在OCR之前定位身份证区域,所以流程可能包括读取图像、预处理、边缘检测、轮廓查找透视变换等步骤。 首先,用户需要的是Java代码示例,所以我要确保使用Java的OpenCV库,也就是JavaCV。根据引用[3],JavaCV提供了Canny边缘检测的支持,这可能是一个关键点。 接下来,步骤分解: 1. 读取图像:使用imread函数。 2. 转换为灰度图:减少计算量,使用cvtColor。 3. 高斯模糊:降噪,使用GaussianBlur。 4. 边缘检测:Canny算法,参数可能需要调整,比如低阈值高阈值。 5. 查找轮廓:使用findContours,找到最大的轮廓,假设身份证是图像中最大的轮廓。 6. 近似多边形:用approxPolyDP来近似轮廓,找到四个顶点的矩形。 7. 透视变换:如果检测到四边形,进行透视变换矫正。 需要注意的问题包括参数调整,比如Canny的阈值如何设置,轮廓查找时的模式方法,以及如何判断找到的轮廓是身份证。此外,身份证可能有背景干扰,可能需要形态学操作或者调整预处理步骤。 代码结构方面,应该包括这些步骤,并且可能需要依赖OpenCV的Java库。需要检查是否正确处理了图像的各步骤,比如颜色空间转换是否正确,轮廓的筛选逻辑是否合理。 然后,根据用户提供的引用,特别是引用[1][2]中的代码示例,可以参考其结构,但需要调整以适应身份证检测的具体需求。例如,在边缘检测之后,可能需要更多的步骤来定位提取身份证区域。 最后,确保代码示例正确,并且逻辑清晰,用户能够理解每个步骤的作用。可能还需要说明如何调整参数以适应不同的图像情况,比如光照、角度等。</think>以下是为您整理的Java版OpenCV身份证边缘检测实现方案及代码示例: ### Java+OpenCV身份证边缘检测步骤 1. **图像预处理**:灰度化、降噪、增强对比度 2. **边缘检测**:使用Canny算法提取边缘特征 3. **轮廓查找**:定位最大四边形轮廓(身份证主体) 4. **透视矫正**:对倾斜证件进行视角修正 ```java import org.bytedeco.opencv.opencv_core.*; import static org.bytedeco.opencv.global.opencv_imgcodecs.*; import static org.bytedeco.opencv.global.opencv_imgproc.*; public class IDCardEdgeDetection { public Mat detectIDCard(String imagePath) { // 1. 读取图像 Mat src = imread(imagePath); if (src.empty()) { System.out.println("图像加载失败"); return new Mat(); } // 2. 图像预处理 Mat gray = new Mat(); cvtColor(src, gray, COLOR_BGR2GRAY); // 灰度化[^3] Mat blur = new Mat(); GaussianBlur(gray, blur, new Size(5,5), 0); // 高斯降噪[^1] Mat edges = new Mat(); Canny(blur, edges, 50, 150); // Canny边缘检测[^3] // 3. 查找轮廓 Mat hierarchy = new Mat(); MatVector contours = new MatVector(); findContours(edges, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); // 4. 筛选最大四边形轮廓 double maxArea = 0; MatOfPoint maxContour = null; for (int i = 0; i < contours.size(); i++) { MatOfPoint contour = new MatOfPoint(contours.get(i)); double area = contourArea(contour); // 轮廓近似 MatOfPoint2f approx = new MatOfPoint2f(); MatOfPoint2f contour2f = new MatOfPoint2f(contour.toArray()); double epsilon = 0.02 * arcLength(contour2f, true); approxPolyDP(contour2f, approx, epsilon, true); if (approx.rows() == 4 && area > maxArea) { maxArea = area; maxContour = contour; } } // 5. 绘制检测结果 if (maxContour != null) { // 绘制轮廓 drawContours(src, new MatVector(maxContour), -1, new Scalar(0, 255, 0, 0), 3); // 透视变换(需要实现四点坐标提取变换) // ... 具体实现代码可参考OpenCV的getPerspectiveTransformwarpPerspective方法 } return src; } } ``` ### 关键参数说明 1. **高斯模糊**:核尺寸建议`(5,5)`,可根据图像分辨率调整 2. **Canny阈值**:低阈值50-100,高阈值150-200,根据图像质量调整 3. **轮廓筛选**:通过面积边数过滤非证件区域 ### 优化建议 1. 添加`自适应阈值处理`增强对比度 2. 使用`形态学操作`消除噪点 3. 采用`多尺度检测`适应不同拍摄距离 4. 添加`长宽比验证`(身份证标准比例约为1.58:1)
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值