目录
1、HoughLines()函数
该函数在直线提取时只能检测出图像中是否存在符合要求的直线,以及直线的极坐标解析式,无法确定直线的准确位置
函数原型:
void cv::HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn = 0, double stn = 0, double min_theta = 0, double max_theta = CV_PI) //image:待检测直线的原图像,必须是CV_8U的单通道二值图像 //lines:活肤变换检测到的直线极坐标描述的系数,没一条直线都由两个参数表示,分别表示直线距离坐标原点的距离r和 //坐标原点到直线的垂线与x轴的夹角△ //rho:以像素为单位的距离分辨率,即距离r离散化时的单位长度 //threshold:累加器的阈值,即参数空间中离散化后的每个方格被通过的累计次数大于该阈值时将被识别为直线,否则不 //被识别为直线 //srn:对于多尺度霍夫变换算法,该参数表示距离分辨率的除数,粗略的累加器距离分辨率是第三个参数rho,精确的累加 //器分辨率是rho/srn。这个参数必须是非负数,,默认参数是0 //stn:对于多尺度霍夫变换算法,该参数表示角度分辨率的除数,粗略的累加器角度分辨率是第四个参数theta,精确的 //累加器分辨率是theta/stn。这个参数必须是非负数,默认参数为0。当这个参数与第六个参数srn同时为0时,此函数 //表示的是标准霍夫变换 //min_theta:检测直线的最小角度,默认参数为0 //max_theta:检测直线的最大角度,默认参数为CV_PI,即圆周率
应用举例:
#include <iostream> #include <opencv2/highgui.hpp> #include <opencv2/core.hpp> #include <opencv2/imgcodecs.hpp> #include <opencv2/opencv.hpp> using namespace cv; using namespace std; void drawLine(Mat& img, vector<Vec2f> lines, double rows, double cols, Scalar scalar, int n) { Point pt1, pt2; for (size_t i = 0; i < lines.size(); i++) { float rho = lines[i][0]; //直线距离坐标原点的距离 float theta = lines[i][1]; //直线与坐标原点的垂线与x轴的夹角 double a = cos(theta); //夹角的余弦 double b = sin(theta); //夹角的正弦 double x0 = a * rho, y0 = b * rho; //直线与过坐标原点的垂线的交点 double length = max(rows, cols); //图像高宽的最大值 //计算直线上的一点 pt1.x = cvRound(x0 - length * (-b)); pt1.y = cvRound(y0 - length * (a)); //计算直线上的另一点 pt2.x = cvRound(x0 + length * (-b)); pt2.y = cvRound(y0 + length * (a)); //两点绘制一条直线 line(img, pt1, pt2, scalar, n); } } int main() { Mat img = imread("F:\\图像处理\\图片\\字.jpg"); if (img.empty()) { cout << "请确认文件名称是否正确!" << endl; return -1; } Mat edge; //检测边缘图像二值化 Canny(img, edge, 80, 180, 3, false); threshold(edge, edge, 170, 255, THRESH_BINARY); //用不同的累加器检测直线 vector<Vec2f> lines1, lines2; HoughLines(edge, lines1, 1, CV_PI / 180, 50, 0, 0); HoughLines(edge, lines2, 1, CV_PI / 180, 150, 0, 0); //在原图中绘制直线 Mat img1, img2; img.copyTo(img1); img.copyTo(img2); drawLine(img1, lines1, edge.rows, edge.cols, Scalar(255), 2); drawLine(img2, lines2, edge.rows, edge.cols, Scalar(255), 2); //显示图像 imshow("edge", edge); imshow("img", img); imshow("img1", img1); imshow("img2", img2); waitKey(0); return 0; }
结果:
结果很明显,累加器较小时,较短的直线也可以被检测出来,累加器较大时,只能检测出较大的直线
2、HoughLinesP()函数
该函数可以得到图像中满足条件的直线或者线段的两个端点的坐标,进而确定直线的位置
函数原型:
void cv::HoughLinesP(InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLineLength = 0, double maxLineGap = 0) //image:待检测直线的原图像,必须是CV_8C的单通道二值图像 //lines:霍夫变换检测到的直线或者线段两个端点的坐标,每一条直线都由4个参数进行描述,分别是直线两个 //端点的坐标(x1, y1, x2, y2) //rho:以像素为单位的分辨率,即距离r离散化时的单位长度 //theta:以弧度为单位的角度分辨率,即夹角△离散化时的单位角度 //threshold:累加器的阈值,即参数空间中离散化后每个方格被通过累计次数大于阈值时被识别为直线,否则 //不被识别为直线 //minLineLength:直线的最小长度,当检测直线的长度小于该数字时将被剔除 //maxLineGap:同一直线上相邻的两个点之间的最大距离
应用举例:
#include <iostream> #include <opencv2/highgui.hpp> #include <opencv2/core.hpp> #include <opencv2/imgcodecs.hpp> #include <opencv2/opencv.hpp> using namespace cv; using namespace std; int main() { Mat img = imread("F:\\图像处理\\图片\\网.jpg"); if (img.empty()) { cout << "请确认文件名称是否有误!" << endl; return -1; } Mat edge; //检测边缘图像并二值化 Canny(img, edge, 80, 180, 3, false); threshold(edge, edge, 170, 255, THRESH_BINARY); //利用渐进概率式霍夫变换提取直线 vector<Vec4i> linesP1, linesP2; HoughLinesP(edge, linesP1, 1, CV_PI / 180, 150, 30, 10); //两个点的连接最大距离10 HoughLinesP(edge, linesP2, 1, CV_PI / 180, 150, 30, 30); //两个点的连接最大距离30 //绘制两个点连接最大距离10直线检测结果 Mat img1; img.copyTo(img1); for (size_t i = 0; i < linesP1.size(); i++) { line(img1, Point(linesP1[i][0], linesP1[i][1]), Point(linesP1[i][2], linesP1[i][3]), Scalar(255), 3); } //绘制两个点连接最大距离30直线检测结果 Mat img2; img.copyTo(img2); for (size_t i = 0; i < linesP2.size(); i++) { line(img2, Point(linesP2[i][0], linesP2[i][1]), Point(linesP2[i][2], linesP2[i][3]), Scalar(255), 3); } //显示图像 imshow("img1", img1); imshow("img2", img2); waitKey(0); return 0; }
结果:
3、HoughLinesPointSet()函数
在实际工程应用中,有可能得到的是一些点坐标,而不是一幅完整的图像,该函数就是能够在众多点中寻找是否存在直线的函数
函数原型:
void cv::HoughLinesPointSet(InputArray _point, OutputArray _lines, int lines_max, int threshold, double min_rho, double max_rho, double rho_step, double min_theta, double max_theta, double theta_step) //_point:输入点的集合,必须是平面内的二维坐标,数据类型必须是CV_32FC2或CV_32SC2 //_lines:在输入点集合中可能存在的直线,每一条直线都具有3个参数,分别是权值、直线 //距离坐标原点的距离r和坐标原点到直线的垂线与x轴的夹角△ //lines_max:检测直线的最大数目 //threshold:累加器的阈值,即参数空间中离散化后每个方格被通过累计次数大于阈值时被 //识别为直线,否则不被识别为直线 //min_rho:检测直线长度的最小距离,以像素为单位 //max_rho:检测直线长度的最大距离,以像素为单位 //rho_step:以像素为单位的距离分辨率,即距离r离散化时的单位距离 //min_theta:检测直线的最小角度,以弧度为单位 //max_theta:检测直线的最大角度值,以弧度为单位 //theta_step:以弧度为单位的角度分辨率,即夹角△离散化时的单位角度
应用举例:
#include <iostream> #include <opencv2/highgui.hpp> #include <opencv2/core.hpp> #include <opencv2/imgcodecs.hpp> #include <opencv2/opencv.hpp> using namespace cv; using namespace std; int main() { system("color F0"); Mat lines; //存放检测直线的结果 vector<Vec3d> line3d; //换一种结果存放形式 vector<Point2f> point; //待检测是否存在直线的所有点 const static float Points[20][2] = { {0.0f, 369.0f}, {10.0f, 364.0f}, {20.2f, 358.0f}, {30.0f, 352.0f}, {40.0f, 364.0f}, {50.0f, 341.0f}, {60.0f, 335.0f}, {70.0f, 329.0f}, {80.0f, 323.0f}, {90.0f, 318.0f}, {100.0f, 312.0f}, {110.0f, 306.0f}, {120.0f, 300.0f}, {130.0f, 295.0f}, {140.0f, 289.0f}, {150.0f, 284.0f}, {160.0f, 277.0f}, {170.0f, 271.0f}, {180.0f, 266.0f}, {190.0f, 260.0f} }; //将所有点存放在vector中,用于输入函数 for (int i = 0; i < 20; i++) { point.push_back(Point2f(Points[i][0], Points[i][1])); } //参数设置 double rhoMin = 0.0f; //最小长度 double rhoMax = 360.0f; //最大长度 double rhoStep = 1; //离散化单位长度 double thetaMin = 0.0f; //最小角度 double thetaMax = CV_PI / 2.0f; //最大角度 double thetaStep = CV_PI / 180.0f; //离散化单位角度 HoughLinesPointSet(point, lines, 20, 1, rhoMin, rhoMax, rhoStep, thetaMin, thetaMax, thetaStep); lines.copyTo(line3d); //输出结果 for (int i = 0; i < line3d.size(); i++) { cout << "votes:" << (int)line3d.at(i).val[0] << "," << "rho:" << line3d.at(i).val[1] << "," << "theta:" << line3d.at(i).val[2] << endl; } return 0; }
结果:
4、fitLine()函数
该函数为OpenCV中的直线拟合函数,利用的原理是最小二乘法
函数原型:
void cv::fitLine(InputArray points, OutputArray line, int distType, double param, double reps, double aeps) //points:输入待拟合直线的二维或者三维点集 //line:输出描述直线的参数,二维点集描述参数为Vec4f类型,三维点集描述参数为Vec6f类型 //distType:M-estimator算法使用的距离类型标志 //parpm:某些距离类型的数值参数。如果数值为0,那么自动选择最佳值 //reps:坐标原点与拟合直线之间的距离精度,数值0表示选择自适应参数,一般选择0.01 //aeps:拟合直线的角度精度,数值0表示选择自适应参数,一般选择0.01
关于函数中的param参数选择,可参考下面表格:
标志参数 简记 距离计算公式 DIST_L1 1 DIST_L2 2 DIST_L12 4 DIST_FAIR 5 ,其中C=1.3998
DIST_WELSCH 6 ,其中C=2.9846
DIST_HUBER 7 ,其中C=1.345
应用举例:
#include <iostream> #include <opencv2/highgui.hpp> #include <opencv2/core.hpp> #include <opencv2/imgcodecs.hpp> #include <opencv2/opencv.hpp> using namespace cv; using namespace std; int main() { system("color F0"); Vec4f lines; //存放拟合后的直线 vector<Point2f> point; //待检测是否存在直线的所有点 const static float Points[20][2] = { {0.0f, 0.0f}, {10.0f, 11.0f}, {21.0f, 20.0f}, {30.0f, 30.0f}, {40.0f, 42.0f}, {50.0f, 50.0f}, {60.0f, 60.0f}, {70.0f, 70.0f}, {80.0f, 80.0f}, {90.0f, 92.0f}, {100.0f, 100.0f}, {110.0f, 110.0f}, {120.0f, 120.0f}, {136.0f, 130.0f}, {138.0f, 140.0f}, {150.0f, 150.0f}, {160.0f, 163.0f}, {175.0f, 170.0f}, {181.0f, 180.0f}, {200.0f, 190.0f} }; //将所有点存放在vector中,用于输入函数 for (int i = 0; i < 20; i++) { point.push_back(Point2f(Points[i][0], Points[i][1])); } //参数设置 double param = 0; //距离类型中的数值参数 double reps = 0.01; //坐标原点与直线之间的距离精度 double aeps = 0.01; //角度精度 fitLine(point, lines, DIST_L1, param, reps, aeps); double k = lines[1] / lines[0]; //直线斜率 cout << "直线斜率:" << k << endl; cout << "直线上一点坐标x:" << lines[2] << ", y:" << lines[3] << endl; cout << "直线解析式:y=" << k << "(x-" << lines[2] << ")+" << lines[3] << endl; return 0; }
结果:
如果以上内容对你有所帮助,不妨给个3连,若有不足之处,请批评指教,感谢您的观看!