对于一份试卷,我现在需要检测到填空题上面的横线。如下图:
很多人第一反应是霍夫直线检测,包括我也是想到用霍夫直线检测。然而事实并不尽如人意。
因为在我的博客中并没有放上霍夫直线检测这一部分,所以,我用霍夫直线算法来检测试卷上的横线。
霍夫直线检测:
#include
#include
#include
using namespace cv;
using namespace std;
void houghlinedetect(int,void*); //定义霍夫检测直线的方法
Mat src,roiImg,dst,gray_dst;
int threshold_value = 50;
int max_value = 255;
const char* output_title = "detect lines";
int main(int argc, char** argv)
{
src = imread("D:/test/English exam.png",1);
if (src.empty())
{
cout << "图片未找到!" << endl;
return -1;
}
imshow("input image",src);
Rect roi = Rect(8, 8, src.cols - 10,src.rows - 10); //从左上角(8,8),选取这块ROI区域
roiImg = src(roi);
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
createTrackbar("threshold", output_title, &threshold_value, max_value, houghlinedetect);
houghlinedetect(0, 0);
imshow("roiImg", roiImg);
waitKey(0);
return 0;
}
void houghlinedetect(int, void *)
{
//使用边缘检测将图片二值化
Canny(roiImg, dst, threshold_value, 2 * threshold_value, 3, false);
//bitwise_not(dst, dst, Mat());
vector lines;//存储直线数据
HoughLinesP(dst,lines,1, CV_PI/180.0,30,30,0); //源图需要是二值图像,HoughLines也是一样
cvtColor(dst, gray_dst,COLOR_GRAY2BGR); //GRAY2BGR是转化为彩色图像的
for (size_t i = 0; i < lines.size(); i++)
{
Vec4i l = lines[i];
line(gray_dst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(186, 88, 255), 1, LINE_AA);
}
imshow(output_title, gray_dst);
}
threshold值=150:
可以看到,直线并没有被完全检测出来。所以理想跟现实确实是不一样的。
解决方法:
通过图像形态学操作来寻找直线,利用霍夫直线检测获取位置信息并显示。
形态学操作的具体原理及操作参考这2篇文章:
https://www.cnblogs.com/little-monkey/p/7236188.html
https://blog.csdn.net/huanghuangjin/article/details/80950004
步骤:
1、进行二值化操作:
//二值化操作
Mat binaryImage, morhpImage,resultImg,dilateImg;
cvtColor(roiImg, roiImg, CV_BGR2GRAY);
threshold(roiImg, binaryImage, 0, 255, THRESH_BINARY|THRESH_OTSU);//THRESH_BINARY|THRESH_OTSU 自动确定阈值
bitwise_not(binaryImage, binaryImage, Mat());//当然在threshold中可以使用THRESH_BINARY | THRESH_OTSU直接变成黑色背景
imshow("binary", binaryImage);
2、形态学开操作,去除除了横线以外的所有字:
//形态学操作,去除除了横线以外的所有字
Mat kernel = getStructuringElement(MORPH_RECT, Size(20, 1), Point(-1, -1));//结构元素,这里使用矩形结构元素,Size(30,1)保留横线,point(-1,-1)表示中心
morphologyEx(binaryImage, morhpImage, MORPH_OPEN, kernel, Point(-1, -1));
imshow("morphologyEx result",morhpImage);
3、膨胀操作,把结果变得更加明显:
//使用膨胀操作把直线变得更明显点
kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
dilate(morhpImage, dilateImg, kernel, Point(-1, -1));
imshow("dilateimg result",dilateImg);
4、霍夫直线检测:
vector lines;
resultImg = roiImg.clone();
HoughLinesP(dilateImg, lines, 1, CV_PI / 180.0, 20, 5, 0);
cvtColor(resultImg, resultImg, CV_GRAY2RGB);
for (size_t i = 0; i < lines.size(); i++)
{
Vec4i L=lines[i];
line(resultImg, Point(L[0], L[1]), Point(L[2], L[3]), Scalar(0, 0, 255), 2, 8, 0);
}
imshow("final result", resultImg);
现在放上所有代码(说明已加注释,用哪块就去除哪块注释)
#include
#include
#include
using namespace cv;
using namespace std;
void houghlinedetect(int,void*); //定义霍夫检测直线的方法
void morphlogy_houghline(int, void*);//定义形态学+霍夫直线变换的方法
Mat src,roiImg,dst,gray_dst;
int threshold_value = 50;
int max_value = 255;
const char* output_title = "detect lines";
int main(int argc, char** argv)
{
src = imread("D:/test/English exam.png",1);
if (src.empty())
{
cout << "图片未找到!" << endl;
return -1;
}
imshow("input image",src);
Rect roi = Rect(8, 8, src.cols - 10,src.rows - 10); //从左上角(8,8),选取这块ROI区域
roiImg = src(roi);
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
//createTrackbar("threshold", output_title, &threshold_value, max_value, houghlinedetect);
//houghlinedetect(0, 0);
morphlogy_houghline(0, 0);
imshow("roiImg", roiImg);
waitKey(0);
return 0;
}
void houghlinedetect(int, void *)
{
//使用边缘检测将图片二值化
Canny(roiImg, dst, threshold_value, 2 * threshold_value, 3, false);
//bitwise_not(dst, dst, Mat());
vector lines;//存储直线数据
HoughLinesP(dst,lines,1, CV_PI/180.0,30,30,0); //源图需要是二值图像,HoughLines也是一样
cvtColor(dst, gray_dst,COLOR_GRAY2BGR); //GRAY2BGR也是转化为灰度图像的,霍夫变换-直线检测需要使用这个,BGR2GRAY会报错。
for (size_t i = 0; i < lines.size(); i++)
{
Vec4i l = lines[i];
line(gray_dst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(186, 88, 255), 1, LINE_AA);
}
imshow(output_title, gray_dst);
}
void morphlogy_houghline(int, void*)
{
//二值化操作
Mat binaryImage, morhpImage,resultImg,dilateImg;
cvtColor(roiImg, roiImg, CV_BGR2GRAY);
threshold(roiImg, binaryImage, 0, 255, THRESH_BINARY|THRESH_OTSU);//THRESH_BINARY|THRESH_OTSU 自动确定阈值
bitwise_not(binaryImage, binaryImage, Mat());//当然在threshold中可以使用THRESH_BINARY | THRESH_OTSU直接变成黑色背景
imshow("binary", binaryImage);
//形态学操作,去除除了横线以外的所有字
Mat kernel = getStructuringElement(MORPH_RECT, Size(20, 1), Point(-1, -1));//结构元素,这里使用矩形结构元素,Size(30,1)保留横线,point(-1,-1)表示中心
morphologyEx(binaryImage, morhpImage, MORPH_OPEN, kernel, Point(-1, -1));
imshow("morphologyEx result",morhpImage);
//使用膨胀操作把直线变得更明显点
kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
dilate(morhpImage, dilateImg, kernel, Point(-1, -1));
imshow("dilateimg result",dilateImg);
//霍夫直线检测
vector lines;
resultImg = roiImg.clone();
HoughLinesP(dilateImg, lines, 1, CV_PI / 180.0, 20, 5, 0);
cvtColor(resultImg, resultImg, CV_GRAY2RGB);
for (size_t i = 0; i < lines.size(); i++)
{
Vec4i L=lines[i];
line(resultImg, Point(L[0], L[1]), Point(L[2], L[3]), Scalar(0, 0, 255), 2, 8, 0);
}
imshow("final result", resultImg);
}