之前写了一篇,结果浏览器崩了,文字全无。这次直接上代码吧。

身份证号的识别过程:

#include<iostream>

#include<opencv2\opencv.hpp>

using namespace std;
using namespace cv;

int main()
{
	Mat img = imread("234.png");
	namedWindow("原图");
	imshow("原图", img);

	Mat temp, temp2, temp3;

	//灰度化
	cvtColor(img, temp, COLOR_BGR2GRAY);
	cvtColor(temp, img, COLOR_GRAY2BGRA);
	namedWindow("灰度化");
	imshow("灰度化", temp);



	//二值化
	threshold(temp, temp2, 60, 255, CV_THRESH_BINARY);
	namedWindow("二值化");
	imshow("二值化", temp2);

	//腐蚀
	Mat erodeElement = getStructuringElement(MORPH_RECT, Size(13, 13));
	erode(temp2, temp3, erodeElement);
	namedWindow("腐蚀");
	imshow("腐蚀", temp3);


	//轮廓检测
	vector<vector<Point> > contours;  //定义一个容器来存储所有检测到的轮廊
	vector<Vec4i> hierarchy;
	//轮廓检测函数
	Mat conv(temp3.size(), CV_8UC1);
	temp3.convertTo(conv, CV_8UC1);
	findContours(conv, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE, cvPoint(0, 0));
	int index = 0;
	long max_Index = static_cast<long>(contours.size());
	if (index < max_Index - 1) {
		++index;
	}
	//取出身份证号码区域
	vector<Rect> rects;
	Rect numberRect = Rect(0, 0, 0, 0);
	vector<vector<Point> >::const_iterator itContours = contours.begin();



	for (int i = 0; i <max_Index; ++i) {
		Rect rect = boundingRect(itContours[i]);
		numberRect = rect;

		Mat dst(numberRect.height, numberRect.width, CV_8UC4, numberRect.area());
		dst = img(numberRect);
		for (int i = 0; i <max_Index; ++i) {
			Rect rect = boundingRect(itContours[i]);
			numberRect = rect;

			Mat dst(numberRect.height, numberRect.width, CV_8UC4, numberRect.area());
			dst = img(numberRect);

			if (rect.y > img.rows / 2 && rect.width / rect.height > 6) {

				imshow("身份证号:", dst);
			}
		}

	}

	waitKey(0);
	cout << CV_MAJOR_VERSION << endl;
	return 0;
}

运行结果:

 

然后是基于hp开源谷歌维护的的ocr库,基于vs2015变异的库链接如下:https://download.csdn.net/download/qq_35054151/10765151

第二种方法是根据识别出来的身份证号矩形图,根据垂直投影进行字符分割,然后送入到训练好的数据集中进行识别。

首先,定义一个数组用来储存每一列像素中白色像素的个数。

    int perPixelValue;//每个像素的值
    int* projectValArry = new int[width];//创建一个用于储存每列白色像素个数的数组
    memset(projectValArry, 0, width*4);//必须初始化数组

然后,遍历二值化后的图片,将每一列中白色的(也就是数字区域)像素记录在数组中。

    //遍历每一列的图像灰度值,查找每一行255的值
    for (int col = 0; col < width; ++col)
    {
        for (int row = 0; row < height; ++row)
        {
            perPixelValue = binImg.at<uchar>(row, col);
            if (perPixelValue == 255)//如果是黑底白字
            {
                projectValArry[col]++;
            }
        }
    }

最后,根据数组里的灰度值画出投影图

    /*新建一个Mat用于储存投影直方图并将背景置为白色*/
    Mat verticalProjectionMat(height, width, CV_8UC1);
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            perPixelValue = 255;  //背景设置为白色。   
            verticalProjectionMat.at<uchar>(i, j) = perPixelValue;
        }
    }

    /*将直方图的曲线设为黑色*/
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < projectValArry[i]; j++)
        {
            perPixelValue = 0;  //直方图设置为黑色  
            verticalProjectionMat.at<uchar>(height - 1 - j, i) = perPixelValue;
        }
    }
    imshow("【投影】",verticalProjectionMat);
    delete[] projectValArry;//不要忘了删除数组空间

有了投影图做切割就很容易了,其实最主要的就是那个储存灰度值的数组,下面就需要根据这个数组的内容来找到相邻字符间的分割点。

    vector<Mat> roiList;//用于储存分割出来的每个字符
    int startIndex = 0;//记录进入字符区的索引
    int endIndex = 0;//记录进入空白区域的索引
    bool inBlock = false;//是否遍历到了字符区内
    for (int i = 0; i < srcImg.cols; ++i)
    {
        if (!inBlock && projectValArry[i] != 0)//进入字符区了
        {
            inBlock = true;
            startIndex = i;
            cout << "startIndex is " << startIndex << endl;
        }
        else if (projectValArry[i] == 0 && inBlock)//进入空白区了
        {
            endIndex = i;
            inBlock = false;    
            Mat roiImg = srcImg(Range(0,srcImg.rows),Range(startIndex,endIndex+1));
            roiList.push_back(roiImg);
        }
    }
效果图

对于分割后的字符的识别,可以参考博主博客:https://blog.csdn.net/qq_35054151/article/details/83685461

另外对于tesseract的识别,可以参考如下:

#include <baseapi.h>
#include <renderer.h>
#include <opencv2\highgui.hpp>
#include <opencv2\imgproc.hpp>
#include <iostream>

void main() {
	cv::Mat image = cv::imread("身份证号.jpg");
	cv::cvtColor(image, image, CV_BGR2GRAY);
	cv::imshow("原灰度图", image);

	// eng.traineddata所在路径
	//const char* datapath = "D:\\tesseract\\tessdata";

	// 新建tess基类
	tesseract::TessBaseAPI tess;

	// 初始化
	tess.Init(NULL, "eng", tesseract::OEM_DEFAULT);
	// 设置白名单
	tess.SetVariable("tessedit_char_whitelist", "0123456789");

	// 设置识别模式
	tess.SetPageSegMode(tesseract::PSM_SINGLE_BLOCK);
	// 设置识别图像
	tess.SetImage((uchar*)image.data, image.cols, 
		image.rows, image.step[1], image.step[0]);
	
	// 进行识别
	char* out = tess.GetUTF8Text();
	std::cout << out << std::endl;
	cv::waitKey();
}
#include <tesseract/baseapi.h> 
tesseract::TessBaseAPI tessearct_api;  
const char  *languagePath = "/usr/local/Cellar/tesseract/3.04.01_2/share/tessdata";    const char *languageType = "chi_sim";   
 int nRet = tessearct_api.Init(languagePath, languageType,tesseract::OEM_DEFAULT);   
 if (nRet != 0) {    
    printf("初始化字库失败!");   
     return -1;   
 }   
 tessearct_api.SetPageSegMode(tesseract::PSM_SINGLE_BLOCK);   
 tessearct_api.SetImage(seg_image.data, seg_image.cols, seg_image.rows, 1,seg_image.cols); 
 string out = string(tessearct_api.GetUTF8Text());  
 cout<<"the out result :"<<out<<endl; 


 

参考博客:https://blog.csdn.net/wx7788250/article/details/60139109

https://www.jianshu.com/p/3a5c08a14ddd

https://blog.csdn.net/u014389362/article/details/81390350?utm_source=blogxgwz8

https://blog.csdn.net/carloswc/article/details/76141587

GitHub 加速计划 / te / tesseract
60.1 K
9.29 K
下载
tesseract-ocr/tesseract: 是一个开源的光学字符识别(OCR)引擎,适用于从图像中提取和识别文本。特点是可以识别多种语言,具有较高的识别准确率,并且支持命令行和API调用。
最近提交(Master分支:1 个月前 )
bc490ea7 Don't check for a directory, because a symbolic link is also allowed. Signed-off-by: Stefan Weil <sw@weilnetz.de> 2 个月前
2991d36a - 3 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐