OpenCv-C++-小案例实战-直线检测(以及霍夫直线检测代码)

对于一份试卷,我现在需要检测到填空题上面的横线。如下图:
在这里插入图片描述
很多人第一反应是霍夫直线检测,包括我也是想到用霍夫直线检测。然而事实并不尽如人意。
因为在我的博客中并没有放上霍夫直线检测这一部分,所以,我用霍夫直线算法来检测试卷上的横线。

霍夫直线检测:

#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>

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<Vec4i> 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值=50:
在这里插入图片描述

threshold值=100:
在这里插入图片描述

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<Vec4i> 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<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>

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<Vec4i> 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<Vec4i> 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);
}

猜你喜欢

转载自blog.csdn.net/Daker_Huang/article/details/85039349