程序求助:基于C++opencv的身份证数字识别程序

是这样的,我是大一学生,我们期末有一项要求需要每个人想一个实用的程序项目并去实现,我想到的一个主题是身份证数字识别,具体是读取一张身份证图片,程序自动给出身份证数字。我的程序已经基本上写好了,但是不知道为什么识别的很不准确(识别的方法是使用matchtemplate函数),比如5会识别成3,我看了别人使用相同的方法但是识别很准确(悲)。有大佬可以帮忙看一下吗,真的非常感谢

#include <iostream>
#include <opencv2/opencv.hpp>
#include <vector>
#define DEFAULT_CARD_WIDTH 640
#define DEFAULT_CARD_HEIGHT 400
#define FIX_IDCARD_SIZE Size(DEFAULT_CARD_WIDTH, DEFAULT_CARD_HEIGHT)
#define FIX_TEMPLATE_SIZE Size(153, 28)
using namespace std;
using namespace cv;
int main() {
    Mat src = imread("C:\\Users\\86188\\Desktop\\1.png");//先载入一张身份证图像
    //处理身份证
    Mat src_img = src;
    //1、无损压缩 640*400 (通用卡片类的处理方式)
    resize(src_img, src_img, FIX_IDCARD_SIZE);
    Mat dst_img;
    //2、灰度化
    Mat dst;
    cvtColor(src_img, dst, COLOR_BGR2GRAY);
    imshow("gray", dst);
    Mat temp;
    //3、二值化(降噪)
    threshold(dst, temp, 100, 255, THRESH_BINARY);
    Mat r;
    // 4.1 腐蚀、膨胀
    Mat erodeElement = getStructuringElement(MORPH_RECT, Size(20, 10));
    erode(temp, r, erodeElement);
    imshow("erode", r);
    //4、轮廓检测,把所有的连续的闭包用矩形包起来
    /*
     * 一个矩形用两个点表示,contours就包含了很多矩形
     */
    vector<vector<Point>> contours;
    vector<Rect> rects;

    findContours(r, contours, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
    for (size_t i = 0; i < contours.size(); i++)
    {
        // 基于两点构建矩形
        Rect rect = boundingRect(contours.at(i));
        // 绘制矩形
        rectangle(r, rect, Scalar(0, 0, 255));
        imshow("contours", dst);
        // 对符合条件的图片进行筛选,宽高比大于1:9的
        if (rect.width > rect.height * 9)
        {
            cout << "找到了" << endl;
            rects.push_back(rect);
            rectangle(r, rect, Scalar(0, 0, 255));
        }
    }
    // 如果只找到了一个矩形,说明这个就是,如果多个就找出纵坐标最低的矩形
    if (rects.size() == 1)
    {
        Rect rect = rects.at(0);
        dst_img = temp(rect);
    }
    else
    {
        int lowPoint = 0;
        Rect finalRect;

        for (size_t i = 0; i < rects.size(); ++i)
        {
            Rect rect = rects.at(i);
            Point p = rect.tl();
            if (rect.tl().y > lowPoint)
            {
                lowPoint = rect.tl().y;
                finalRect = rect;
            }
        }
        rectangle(r, finalRect, Scalar(255, 255, 0));
        dst_img = temp(finalRect);//在'temp'上绘制所需要的身份证数字区域矩形
    }   
    bitwise_not(dst_img, dst_img);//我这里将白底黑字反色 
    //GaussianBlur(dst_img, dst_img, Size(1, 1), 0);//高斯模糊
    //Mat erodeElement1 = getStructuringElement(MORPH_RECT, Size(2, 2));
    //erode(dst_img, dst_img, erodeElement1);//以上两行为腐蚀操作
    //threshold(dst_img, dst_img, 100, 255, THRESH_BINARY);//二值化,图像一下子由模糊变清晰
    //float dilationSize = 0.9; // 膨胀的尺寸
    //Mat element = getStructuringElement(MORPH_RECT, Size(2 * dilationSize + 1, 2 * dilationSize + 1), Point(dilationSize, dilationSize));
    //dilate(dst_img, dst_img, element);//上三行都是用来膨胀的,本来的字符太细了
    //以上都是可以对dst_img再进行改变的一系列操作
    imshow("身份证数字模块", dst_img);
    double width = dst_img.cols; // 获取图像宽度
    double height = dst_img.rows; // 获取图像高度
    double digitWidth = width / 19; // 这里的digitWidth是用来重新改变模板大小所用的参数
    vector<string> matchedNumbers; // 存储匹配的数字
    vector<vector<Point>> edges;//用来存储边缘,用于后面的按边缘分割数字
    vector<Rect> reps;//存储轮廓
    findContours(dst_img, edges, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    for (size_t i = 0; i < edges.size(); i++)
    {
        // 获取当前数字的轮廓
        Rect reps = boundingRect(edges.at(i));
        // 计算当前数字的起始横坐标
        double x = reps.x;
        // 提取当前数字的图像
        Mat digitImg = dst_img(reps);
        //resize(digitImg, digitImg, Size(240, 360));
        //GaussianBlur(digitImg, digitImg, Size(3, 3), 0);
        //threshold(digitImg, digitImg, 100, 255, THRESH_BINARY);//二值化,图像一下子由模糊变清晰
        //Mat erodeElement1 = getStructuringElement(MORPH_RECT, Size(3,6));
        //erode(digitImg, digitImg, erodeElement1);
        imshow("依据边缘轮廓切割后的数字" + to_string(i), digitImg);
        // 进行模板匹配
        double maxMatchVal = 0;
        string maxMatchNum;
        for (int j = 0; j < 10; j++) {
            string templatePath = "C:\\Users\\86188\\Desktop\\numbers\\" + to_string(j) + ".png";
            Mat templateImg = imread(templatePath, IMREAD_GRAYSCALE);
            resize(templateImg, templateImg, Size(digitWidth, height));
            //imshow("处理后的模板" + to_string(j), templateImg);//在循环里展示要用to_string()语句,实际上是给每个窗口赋不同名称
            Mat result;
            matchTemplate(digitImg, templateImg, result, TM_CCORR_NORMED);
            double matchVal;
            minMaxLoc(result, nullptr, &matchVal, nullptr, nullptr);
            if (matchVal > maxMatchVal) {
                maxMatchVal = matchVal;
                maxMatchNum = to_string(j);
            }//这里都是索引算法,用来循环寻找最合适的匹配
        }
        matchedNumbers.push_back(maxMatchNum); // 将匹配的数字添加到容器中
    }
    // 输出匹配的数字
    cout << "匹配的数字:";
    string idNumber;
    for (const string& num : matchedNumbers) {
        cout << num << " ";
        idNumber = idNumber+num;
    }
    Mat bg(src.rows, src.cols * 2, CV_8UC3, Scalar(255, 255, 255));
    Mat sho(bg, Rect(0, 0, src.cols, src.rows));
    src.copyTo(sho);
    putText(bg, idNumber, Point(src.cols, 0.9*src.rows), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 0), 2);
    namedWindow("身份证信息", WINDOW_NORMAL);
    imshow("身份证信息", bg);
    waitKey();
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值