问题描述: 对于下面的一张图片,获取其中的直线部分。
能想到的有两种方式:
(1)先用canny检测边缘得到边缘图片,再用霍夫直线检测边缘图片中的直线
(2) 先将图像通过形态学操作腐蚀掉字母,然后在通过霍夫检测将直线展示出来
第一种方式的代码如下,然后用的trackbar拉动看来肯每个阈值对结果的影响。
事实这种方式,效果很差。
void detectline(int, void*) {
//canny 检测
Mat canny_out;
Canny(src, canny_out, threshold_value, threshold_value * 2, 3, false);
////霍夫直线检测
vector lines;
HoughLinesP(canny_out, lines,1, CV_PI / 180.0, 30, 30, 10);
cvtColor(canny_out, canny_out, COLOR_GRAY2BGR);
//最好是在canny检测出来的图像吧直线画出来,这样拉动track的时候才能看出线条的变化。
for (size_t t = 0; t < lines.size(); t++) {
Vec4i In = lines[t];
line(canny_out, Point(In[0], In[1]), Point(In[2], In[3]), Scalar(0, 0, 255), 2, 8, 0);
}
imshow(output_win, canny_out);
}
展示了三个阈值的结果,发现图片都糊掉了。受英文字母的影响,不能完整的检测出直线。
第二种方式的代码如下。
它的算法步骤:(1)二直化。(2)构建结构元素,消除字母。(3)膨胀处理,让直线更加明显。(4)霍夫直线检测。(5)记录直线的位置。
这里重点是:开操作中的size大小。
首先先腐蚀后膨胀的操作称之为开操作。它具有消除细小物体,在纤细处分离物体和平滑较大物体边界的作用。像字母这种有连接点的图像,消除的话用开操作比较合适。
一般提取水平直线用的是(n,1),提取垂直直线用的是(1,n)。
void morhpologyLines(int, void*) {
//先二直化图像,必须先转换成单通道的图像
Mat BinaryImage, morhpImage;
cvtColor(src, gray, COLOR_BGR2GRAY);
threshold(gray, BinaryImage, 0, 255, THRESH_BINARY_INV|THRESH_OTSU);
imshow("binary image", BinaryImage);
//构建结构元素,消除字母:重点在于kenerl中的size给的大小
Mat kernel = getStructuringElement(MORPH_RECT, Size(50, 1), Point(-1, -1));
morphologyEx(BinaryImage, morhpImage, MORPH_OPEN, kernel, Point(-1, -1));
imshow("morhpolopy image", morhpImage);
//膨胀操作,让直线更加的明显。
kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
dilate(morhpImage, morhpImage, kernel);
imshow("dilate image", morhpImage);
//获取直线
vector lines;
HoughLinesP(morhpImage, lines, 1, CV_PI / 180.0, 30, 20, 0);
Mat resultimage = src.clone();
for (size_t t = 0; t < lines.size(); t++) {
Vec4i In = lines[t];
line(gray, Point(In[0], In[1]), Point(In[2], In[3]), Scalar(0, 255, 255), 2, 8, 0);
}
imshow(output_win, gray);
}