基于Opencv的手写字识别

关于之前已经写过一篇文章了,是关于字符提取的与识别的,本篇文章与上次的文章内容大致一致,只是比对数据库变更了,并且不仅只通过轮廓,还可以通过模板图的方式来进行手写字提取!

函数介绍,以及轮廓提取和识别流程这里就不细说,详细的可以参考我的上一篇文章:使用Opencv进行轮廓检测,字符提取,简单的直方图字符识别!

首先比对要有数据库图,这里我们先手写几个字作为数据库模板


(JPG格式)

鼠标手写字有点不顺,写的有点丑,见笑了哈!

然后我们在手写两个字,注意必须是比对模板里有的

由于比对模板里只有中国两个手写字,所以这里就写上中国两个字:

基于Opencv的手写字识别_第1张图片

下面开始上代码进行手写字比对

(代码具体讲解参考上一篇博客)

结构体:

typedef struct p_image{
	char c_name[256];
	CvHistogram *img_zft;
}p_image;

main代码:

//打开要识别的图像    
	IplImage *image = cvLoadImage("d:\\1.jpg");
	if (image == NULL){
		printf("错误:无法打开该图像文件!");
	}
	//转换到灰度图    
	IplImage *img_gray = cvCreateImage(cvGetSize(image), image->depth, 1);
	cvCvtColor(image, img_gray, CV_BGR2GRAY);
	//二值化    
	IplImage *img_value = cvCreateImage(cvGetSize(img_gray), image->depth, 1);
	cvThreshold(img_gray, img_value, 100, 255, CV_THRESH_BINARY_INV);
	//寻找轮廓    
	CvMemStorage *pStorage = cvCreateMemStorage(0);
	CvSeq *pConInner = NULL;
	int num = cvFindContours(img_value, pStorage, &pConInner, sizeof(CvContour),
		CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
	IplImage* imgNo[9] = { NULL };
	IplImage *i1[9] = { NULL };
	//手写字提取    
	for (int i = 0; i < num; i++)
	{

		CvRect rc = cvBoundingRect(pConInner);
		//cvDrawRect(image, cvPoint(rc.x, rc.y), cvPoint(rc.x + rc.width, rc.y + rc.height), CV_RGB(255, 0, 0));    //为了防止裁剪时出现矩阵颜色,所以将这段代码屏蔽掉!    
		imgNo[i] = cvCreateImage(cvSize(rc.width, rc.height), IPL_DEPTH_8U, 3);
		cvSetImageROI(image, cvRect(rc.x, rc.y, rc.width, rc.height));//设置源图像ROI    
		cvCopy(image, imgNo[i]);    //裁剪    
		pConInner = pConInner->h_next;
	}
	//将获取到的手写字保存起来,在读取出来,分别存储到对应的模板img文件夹里
	//保存与读取      
	char name[256];
	for (int i = 0; i < num; ++i){
		sprintf(name, "d:\\img\\%d.jpg", i);
		cvSaveImage(name, imgNo[i]);
	}
	char b[256];
	for (int i = 0; i < num; ++i){
		sprintf(b, "d:\\img\\%d.jpg", i);
		imgNo[i] = cvLoadImage(b);
	}
	//灰度转换    
	for (int i = 0; i < num; ++i){
		i1[i] = cvCreateImage(cvSize(imgNo[i]->width, imgNo[i]->height), 8, 1);
		cvCvtColor(imgNo[i], i1[i], CV_BGR2GRAY);//CV_BGR2GRAY      
	}
	//计算原图的直方图    
	int arr_size = 255;                 //定义一个变量用于表示直方图行宽      
	float hranges_arr[] = { 0, 255 };       //图像方块范围数组      
	float *phranges_arr = hranges_arr;      //cvCreateHist参数是一个二级指针,所以要用指针指向数组然后传参      
	//创建直方图      
	CvHistogram *hist[9];
	for (int i = 0; i < num; ++i){
		hist[i] = cvCreateHist(1, &arr_size, CV_HIST_ARRAY, &phranges_arr, 1);//创建一个一维的直方图,行宽为255,多维密集数组,方块范围为0-255,bin均化      
	}
	//计算直方图    
	for (int i = 0; i < num; ++i){
		cvCalcHist(&i1[i], hist[i], 0, 0);
	}
	//手写字与图像关联    
	//加载模板图,图像存放在d盘img1文件夹中   
	IplImage* abcd_img[9] = { NULL };
	char img_name[256] = { 0 };
	for (int i = 0; i < num; ++i){
		sprintf(img_name, "d:\\img1\\%d.jpg", i);
		abcd_img[i] = cvLoadImage(img_name);
	}
	//转换灰度图    
	IplImage* abcd_img_hdt[9] = { NULL };
	for (int i = 0; i < num; ++i){
		abcd_img_hdt[i] = cvCreateImage(cvSize(abcd_img[i]->width, abcd_img[i]->height), 8, 1);
		cvCvtColor(abcd_img[i], abcd_img_hdt[i], CV_BGR2GRAY);//CV_BGR2GRAY      
	}
	//创建直方图      
	CvHistogram *hist_abcd[9];
	for (int i = 0; i < num; ++i){
		hist_abcd[i] = cvCreateHist(1, &arr_size, CV_HIST_ARRAY, &phranges_arr, 1);//创建一个一维的直方图,行宽为255,多维密集数组,方块范围为0-255,bin均化      
	}
	//计算模板图的直方图    
	for (int i = 0; i < num; ++i){
		cvCalcHist(&abcd_img_hdt[i], hist_abcd[i], 0, 0);
	}
	//关联图像    
	p_image *p[9] = { NULL };
	for (int i = 0; i <= num; ++i){
		p[i] = (p_image *)malloc(sizeof(p_image));
	}
	//手写字关联    
	char abcd[9][256] = { "中", "国"};    //定义一个二维字符数组,9行,每行256列(256个数据)
	for (int i = 0; i <= num; ++i){
		strcpy(p[i]->c_name,abcd[i]);
	}
	//直方图关联    
	for (int i = 0; i < num; ++i){
		p[i]->img_zft = hist_abcd[i];
	}
	//匹配图像    
	//用于结果    
	char j_c[9][256];
		for (int j = 0; j < num; ++j){
			double Compare = cvCompareHist(hist[j], p[j]->img_zft, 0);     //使用CV_COMP_CORREL方法进行对比    
			if (Compare >= 0.9){ //精准度达90%
				strcpy(j_c[j], p[j]->c_name);

			}
		}

	printf("检测到%d个手写字,分别是:\n", num);
	for (int i = 0; i < num; ++i){
		printf("%s\n", j_c[i]);
	}
	getchar();

运行结果:

基于Opencv的手写字识别_第2张图片

注意前面说过,直方图是利用图像中明暗程度进行比较的,像这种黑白图,白就代表明,黑就代表暗,所以识别起来重叠几率较高,不建议使用模板比对,建议使用其他方法进行比对!

你可能感兴趣的:(基于Opencv的手写字识别)