本案例通过使用OpenCV中的霍夫直线检测HoughLinesP进行填空题区域检测(说白了就是进行直线检测),实现起来也很简单。
原图如图所示:
首先第一步先进行图像预处理,得到二值图像。
Mat gray;
cvtColor(src, gray, COLOR_BGR2GRAY);
Mat gaussian;
GaussianBlur(gray, gaussian, Size(3, 3), 0);
Mat thresh;
threshold(gaussian, thresh, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
通过使用大津阈值进行图像二值化处理,如下图所示,得到一幅二值图像。接下来,需要提取出二值图中直线部分。由图像特征可以看出,直线部分又长又细,所以可以使用形态学操作对图像进行腐蚀操作,仅保留直线部分。在这里我使用的是形态学开操作(先腐蚀,后膨胀)保证能完整的提取出直线部分。由于直线部分又长又细,所以我们在创建kernel时,Size(width,height),width尽可能大一些,height尽可能小一些。这里我使用的是Size(25, 3)大小的kernel。
经形态学开操作处理之后的效果如图所示:
Mat kernel = getStructuringElement(MORPH_RECT, Size(25, 3));
morphologyEx(thresh, thresh, MORPH_OPEN, kernel);
关于霍夫直线检测算法原理我在这里就不细说了,网上教程很多,解释的肯定也比我好。我在这里就简单介绍一下OpenCV中霍夫直线检测API使用。OpenCV中使用霍夫直线检测有两个API,一个是 cv::HoughLines() 标准和多尺度Hough变换;另一个是 cv::HoughLinesP() 渐进概率Hough变换。
void HoughLines(
InputArray image, //输入图像,必须是8位二值图像
OutputArray lines, //结果存放位置,可以是N x 1双通道数组,也可以是一个N项类型为Vec2f的std::vector<>向量,用于存储rho和theta值
double rho, //直线所需分辨率(即累加平面的分辨率),单位是像素
double theta, //直线所需分辨率(即累加平面的分辨率),单位是弧度
int threshold, //累加平面中算法用于判断线条属于一条直线的阈值
double srn = 0, //srn和stn用于控制称为“多尺度Hough变换”(MHT)的SHT算法扩展,不用于标准Hough变换
double stn = 0,
);
void HoughLinesP(
InputArray image, //输入图像,必须是8位二值图像
OutputArray lines, //结果存放位置,四通道(或Vec4i类型的向量),四通道分别是找出线段两端点坐标(x0,y0)和(x1,y1)(按顺序)
double rho, //直线所需分辨率(即累加平面的分辨率),单位是像素
double theta, //直线所需分辨率(即累加平面的分辨率),单位是弧度
int threshold, //累加平面中算法用于判断线条属于一条直线的阈值
double minLineLength = 0, //返回线段的最小长度
double maxLineGap = 0 //共线线段之间的最小间隔,防止算法把它们连成一条
);
这里我使用的是HoughLinesP进行直线检测,下面直接上源码。
#include
#include
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("test.jpg");
if (src.empty())
{
cout << "can not read the image..." << endl;
system("pause");
return -1;
}
Mat gray;
cvtColor(src, gray, COLOR_BGR2GRAY);
Mat gaussian;
GaussianBlur(gray, gaussian, Size(3, 3), 0);
Mat thresh;
threshold(gaussian, thresh, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
Mat kernel = getStructuringElement(MORPH_RECT, Size(25, 3));
morphologyEx(thresh, thresh, MORPH_OPEN, kernel);
vector<Vec4i>lines;
HoughLinesP(thresh, lines, 1, CV_PI / 180, 100, 50, 10);
for (int i = 0; i < lines.size(); i++)
{
line(src, Point(lines[i][0], lines[i][1]), Point(lines[i][2], lines[i][3]), Scalar(0, 0, 255), 2);
}
imshow("src", src);
waitKey(0);
destroyAllWindows();
system("pause");
return 0;
}
本文使用OpenCV C++ 进行填空题区域检测,其实原理很简单,主要操作有以下几点。
1、图像预处理,得到二值图像
2、霍夫直线检测,注意调参,参数不同,得到的结果也不太一样。