一、对于复杂背景中的文本提取
我测试用的简单的单行文本,如果非文本区多对二值化影响大,首先进行提取文本行,再对提取的文本行进行二值化。
实例图片:
图片中的文字区域从此视频帧中提取:
1、切取图片中的行
提取边缘信息,边缘图像进行水平投影,将每一行中的像素值相加,得到一个每行边缘信息的数组,
求数组的波谷,两个波谷直接的区间就为文本行。
求取波谷,我也没想到什么好的算法,因为数组是有波动的,只提取极小值也不对,会提取到特别多个波谷。
下一步想平滑后求极小值。
目前切行后为:
2、对文本行归一化到一定的高
按原来的宽高比对图片进行缩放,缩放到高为80个像素点(看论文里的经验值),便于文本的识别。
float ratioWH = (float)(image->width)/image->height; CvSize cv; cv.height = 80;//将文字行比例转换为高80 cv.width = 80*ratioWH; IplImage *norImage = cvCreateImage(cv,8,1); cvResize(image,norImage);
3、对归一化的文本行进行二值化
提取归一化文本行的边缘信息,因为文本现在占图像的主体,边缘点的特征跟文本的特征比较相似(对于渐变文本,边缘和
填充不一致的也没有考虑,只考虑简单的文本颜色比较单调的),根据边缘点的位置在归一化图上提取相应点的颜色特征,
在这里我又加了连通域分析,不过感觉没有什么改变。
IplImage *cannyImage = cvCreateImage(cvGetSize(norImage),8,1); cvCanny(norImage,cannyImage,50,150); CvMemStorage *pStor = cvCreateMemStorage(0);///创建目标轮廓存储空间; CvSeq *pCont = NULL;///无需释放内存 cvFindContours(cannyImage, pStor, &pCont,sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);//获取二值图像轮廓信息 cvDrawContours(cannyImage,pCont,cvScalarAll(255),cvScalarAll(255),0,CV_FILLED,8, cvPoint(0, 0)); int sum = 0; int num = 0; for(int i=0;i<norImage->height;i++){ for(int j=0;j<norImage->width;j++){ uchar data = *(cannyImage->imageData+i*cannyImage->widthStep+j); if(data!=0){ uchar data2 = *(norImage->imageData+i*norImage->widthStep+j); sum += data2; num++; } } } //二值化 float average =(float)(sum)/num; for(int i=0;i<norImage->height;i++){ for(int j=0;j<norImage->width;j++){ if((uchar)*(norImage->imageData+i*norImage->widthStep+j)>average){ *(norImage->imageData+i*norImage->widthStep+j) = 255; }else{ *(norImage->imageData+i*norImage->widthStep+j) = 0; } } }
二值化后图片:
背景还是有没有去掉的,根据上视频帧是曝光的原因,考虑均衡一下。
4、然后用二值化的图片再用tesseract识别。