这篇博客的来源
笔者在技术群里看到了 OpenCV入门笔记(七) 文字区域的提取 这篇博客,确实解决文字区域的提取有很大的帮助,但是这篇博客是python来写的算法,笔者是专职C++的程序猿,python固然能够看懂,但能够用C++来实现,既提高了个人的改写算法的能力,也能提高算法的运行效率,何乐而不为啊。多的就不多说了,整个算法的流程,笔者均是按照上面提到的这篇博客来做的C++化,再详细的大家可以参考上面这边博客,笔者在这里还是直接贴代码吧。
代码区
const string IMAGEPATH = "demo2.jpg";//图像路径
int _tmain(int argc, _TCHAR* argv[])
{
Mat textImageSrc = imread(IMAGEPATH);
detect(textImageSrc);
return 0;
}
Mat preprocess(Mat gray)
{
//1.Sobel算子,x方向求梯度
Mat sobel;
Sobel(gray, sobel, CV_8U, 1, 0, 3);
//2.二值化
Mat binary;
threshold(sobel, binary, 0, 255, THRESH_OTSU + THRESH_BINARY);
//3.膨胀和腐蚀操作核设定
Mat element1 = getStructuringElement(MORPH_RECT, Size(30, 9));
//控制高度设置可以控制上下行的膨胀程度,例如3比4的区分能力更强,但也会造成漏检
Mat element2 = getStructuringElement(MORPH_RECT, Size(24, 4));
//4.膨胀一次,让轮廓突出
Mat dilate1;
dilate(binary, dilate1, element2);
//5.腐蚀一次,去掉细节,表格线等。这里去掉的是竖直的线
Mat erode1;
erode(dilate1, erode1, element1);
//6.再次膨胀,让轮廓明显一些
Mat dilate2;
dilate(erode1, dilate2, element2);
//7.存储中间图片
imwrite("binary.jpg", binary);
imwrite("dilate1.jpg", dilate1);
imwrite("erode1.jpg", erode1);
imwrite("dilate2.jpg", dilate2);
return dilate2;
}
vector<RotatedRect> findTextRegion(Mat img)
{
vector<RotatedRect> rects;
//1.查找轮廓
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(img, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE, Point(0, 0));
//2.筛选那些面积小的
for (int i = 0; i < contours.size(); i++)
{
//计算当前轮廓的面积
double area = contourArea(contours[i]);
//面积小于1000的全部筛选掉
if (area < 1000)
continue;
//轮廓近似,作用较小,approxPolyDP函数有待研究
double epsilon = 0.001*arcLength(contours[i], true);
Mat approx;
approxPolyDP(contours[i], approx, epsilon, true);
//找到最小矩形,该矩形可能有方向
RotatedRect rect = minAreaRect(contours[i]);
//计算高和宽
int m_width = rect.boundingRect().width;
int m_height = rect.boundingRect().height;
//筛选那些太细的矩形,留下扁的
if (m_height > m_width * 1.2)
continue;
//符合条件的rect添加到rects集合中
rects.push_back(rect);
}
return rects;
}
void detect(Mat img)
{
//1.转化成灰度图
Mat gray;
cvtColor(img, gray, CV_BGR2GRAY);
//2.形态学变换的预处理,得到可以查找矩形的轮廓
Mat dilation = preprocess(gray);
//3.查找和筛选文字区域
vector<RotatedRect> rects = findTextRegion(dilation);
//4.用绿线画出这些找到的轮廓
for each (RotatedRect rect in rects)
{
Point2f P[4];
rect.points(P);
for (int j = 0; j <= 3; j++)
{
line(img, P[j], P[(j + 1) % 4], Scalar(0,255,0), 2);
}
}
//5.显示带轮廓的图像
imshow("img", img);
imwrite("imgDrawRect.jpg", img);
waitKey(0);
}
成果区
这里,笔者给出上面所说的博客的图像的处理效果,另外笔者随意在网页上截了两张图,一共三个演示实例
【原图1】来自上面所说的博客截图
【二值图1】
【初次膨胀图1】
【初次腐蚀图1】
【二次膨胀图1】
【最终结果图1】
【原图2】来自任意搜索后的网页截图
【二值图2】
【初次膨胀图2】
【初次腐蚀图2】
【二次膨胀图2】
【最终结果图2】
【原图3】有倾角的截图
【二值图3】
【初次膨胀图3】
【初次腐蚀图3】
【二次膨胀图3】
【最终结果图3】