#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
int max_count = 255;
int threshold_value = 100;
const char* output_lines = "Hough Lines";
Mat dst, src,roiImage;
void detectLines(int, void*);
void morhpologyLines(int, void*);
int main()
{
src = imread("E:\\Users\\opencvCoder\\image\\exam.png", IMREAD_GRAYSCALE);
if (src.empty())
{
printf("could not load image...\n");
return -1;
}
namedWindow("input image", WINDOW_AUTOSIZE);
imshow("imput image", src);
Rect roi = Rect(10, 10, src.cols - 20, src.rows - 20);
roiImage = src(roi);
namedWindow("ROI image", WINDOW_AUTOSIZE);
imshow("ROI image", roiImage);
namedWindow(output_lines, WINDOW_AUTOSIZE);
//常规直线检测,
/*createTrackbar("threshold:", output_lines, &threshold_value, max_count, detectLines);
detectLines(0, 0);*/
//通过图像形态学操作来寻找直线,霍夫获取位置信息并显示
morhpologyLines(0, 0);
waitKey(0);
return 0;
}
//常规直线检测
void detectLines(int, void*)
{
Canny(roiImage, dst, threshold_value, threshold_value * 2, 3, false);
//二值化做直线检测
//threshold(roiImage, dst, 0, 255, THRESH_BINARY | THRESH_OTSU);
vector<Vec4i>lines;
HoughLinesP(dst, lines, 1, CV_PI / 180.0, 30, 30.0, 0);
cvtColor(dst, dst, COLOR_GRAY2BGR);
for (size_t t = 0; t < lines.size(); t++)
{
Vec4i ln = lines[t];
line(dst, Point(ln[0], ln[1]), Point(ln[2], ln[3]), Scalar(0, 0, 255), 2, 8, 0);
}
imshow(output_lines, dst);
}
//通过图像形态学操作来寻找直线,霍夫获取位置信息并显示
void morhpologyLines(int, void*)
{
//binary image
Mat binaryImage, morhpImage;
//二值化图像
threshold(roiImage, binaryImage, 0, 255, THRESH_BINARY_INV| THRESH_OTSU);
imshow("binary image:", binaryImage);
//morphology operation掩码
Mat kernel = getStructuringElement(MORPH_RECT, Size(25, 1), Point(-1, -1));
//形态学处理morphologyEx函数
/*
第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。图像位深应该为以下五种之一:
CV_8U, CV_16U,CV_16S, CV_32F 或CV_64F。
第二个参数,OutputArray类型的dst,即目标图像,函数的输出参数,需要和源图片有一样的尺寸和类型。
第三个参数,int类型的op,表示形态学运算的类型,可以是如下之一的标识符:
MORPH_OPEN – 开运算(Opening operation
MORPH_CLOSE – 闭运算(Closing operation)
MORPH_GRADIENT -形态学梯度(Morphological gradient)
MORPH_TOPHAT - “顶帽”(“Top hat”)
MORPH_BLACKHAT - “黑帽”(“Black hat“)
第四个参数,InputArray类型的kernel,形态学运算的内核。若为NULL时,表示的是使用参考点位于中心3x3的核。
我们一般使用函数 getStructuringElement配合这个参数的使用。getStructuringElement函数会返回指定形状和尺寸的结构元素(内核矩阵)。
关于getStructuringElement我们上篇文章中讲过了,这里为了大家参阅方便,再写一遍:
其中,getStructuringElement函数的第一个参数表示内核的形状,我们可以选择如下三种形状之一:
矩形: MORPH_RECT
交叉形: MORPH_CROSS
椭圆形: MORPH_ELLIPSE
而getStructuringElement函数的第二和第三个参数分别是内核的尺寸以及锚点的位置。
我们一般在调用erode以及dilate函数之前,先定义一个Mat类型的变量来获得getStructuringElement函数的返回值。对于锚点的位置,有默认值Point(-1,-1),
表示锚点位于中心。且需要注意,十字形的element形状唯一依赖于锚点的位置。而在其他情况下,锚点只是影响了形态学运算结果的偏移。
*/
morphologyEx(binaryImage, morhpImage, MORPH_OPEN, kernel, Point(-1, -1));
imshow("morphology result", morhpImage);
kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
//膨胀
dilate(morhpImage, morhpImage, kernel);
imshow("morphology lines", morhpImage);
//hough lines
vector<Vec4i>lines;
/*
* 此函数在HoughLines的基础上末尾加了一个代表Probabilistic(概率)的P,表明它可以采用累计概率霍夫变换(PPHT)来找出二值图像中的直线。
第一个参数,InputArray类型的image,输入图像,即源图像,需为8位的单通道二进制图像,可以将任意的源图载入进来后由函数修改成此格式后,再填在这里。
第二个参数,InputArray类型的lines,经过调用HoughLinesP函数后后存储了检测到的线条的输出矢量,每一条线由具有四个元素的矢量(x_1,y_1, x_2, y_2) 表示,
其中,(x_1, y_1)和(x_2, y_2) 是是每个检测到的线段的结束点。
第三个参数,double类型的rho, 以像素为单位的距离精度。 另一种形容方式是直线搜索时的进步尺寸的单位半径。
第四个参数,double类型的theta,以弧度为单位的角度精度。另一种形容方式是直线搜索时的进步尺寸的单位角度。
第五个参数,int类型的threshold,累加平面的阈值参数,即识别某部分为图中的一条直线时它在累加平面中必须达到的值。
大于阈值 threshold 的线段才可以被检测通过并返回到结果中。
第六个参数,double类型的minLineLength,有默认值0,表示最低线段的长度,比这个设定参数短的线段就不能被显现出来。
第七个参数,double类型的maxLineGap,有默认值0,允许将同一行点与点之间连接起来的最大的距离。
*/
HoughLinesP(morhpImage, lines, 1, CV_PI / 180.0, 30, 20, 0.0);
Mat resultImage = roiImage.clone();
cvtColor(resultImage, resultImage, COLOR_GRAY2BGR);
for (size_t t = 0; t < lines.size(); t++)
{
Vec4i ln = lines[t];
line(resultImage, Point(ln[0], ln[1]), Point(ln[2], ln[3]), Scalar(0, 0, 255), 2, 8, 0);
}
imshow(output_lines, resultImage);
}