本系列代码托管于:https://github.com/chintsan-code/opencv4-tutorials

本篇使用的项目为:hough_lines

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

using namespace cv;
using namespace std;

void hough_lines_demo(Mat &image);
void hough_linesp_demo(Mat &image);

int main(int argc, const char** argv) {
	Mat src1 = imread("../sample/lines.png");
	Mat src2 = imread("../sample/morph01.png");
	if (src1.empty() || src2.empty()) {
		cout << "could not load image..." << endl;
		return -1;
	}
	hough_lines_demo(src1);
	hough_linesp_demo(src2);

	waitKey(0);
	destroyAllWindows();
	return 0;
}

void hough_lines_demo(Mat &image) {
	// 二值化
	Mat gray, binary;
	cvtColor(image, gray, COLOR_BGR2GRAY);
	threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
	namedWindow("binary", WINDOW_AUTOSIZE);
	imshow("binary", binary);

	// 霍夫直线检测
	vector<Vec3f> lines;
	HoughLines(binary, lines, 1, CV_PI / 180.0, 100, 0, 0);

	// 绘制直线
	Point pt1, pt2;
	for (size_t i = 0; i < lines.size(); i++) {
		float rho = lines[i][0]; // 距离
		float theta = lines[i][1]; // 角度
		float acc = lines[i][2];// 累加值
		printf("rho: %.2f, theta : %.2f, acc: %.2f \n", rho, theta, acc);
		double a = cos(theta);
		double b = sin(theta);
		double x0 = a * rho, y0 = b * rho;
		pt1.x = cvRound(x0 + 1000 * (-b));
		pt1.y = cvRound(y0 + 1000 * (a));
		pt2.x = cvRound(x0 - 1000 * (-b));
		pt2.y = cvRound(y0 - 1000 * (a));
		int angle = round((theta / CV_PI) * 180);
		printf("angle : %d \n", angle);
		if (rho > 0) { // 右倾
			line(image, pt1, pt2, Scalar(0, 0, 255), 1, 8, 0);
			if (angle == 90) { // 水平线
				line(image, pt1, pt2, Scalar(0, 255, 255), 2, 8, 0);
			}
			if (angle <= 1) {// 垂直线
				line(image, pt1, pt2, Scalar(255, 255, 0), 4, 8, 0);
			}
		}
		else { // 左倾
			line(image, pt1, pt2, Scalar(255, 0, 0), 2, 8, 0);
		}
	}
	imshow("hough line detection", image);
}

void hough_linesp_demo(Mat &image) {
	Mat binary;
	Canny(image, binary, 80, 160, 3, false);
	imshow("binary", binary);

	vector<Vec4i> lines;
	HoughLinesP(binary, lines, 1, CV_PI / 180, 80, 200, 10);
	Mat result = Mat::zeros(image.size(), image.type());
	for (int i = 0; i < lines.size(); i++) {
		line(result, Point(lines[i][0], lines[i][1]), Point(lines[i][2], lines[i][3]), Scalar(0, 0, 255), 1, 8);
	}
	imshow("hough linesp demo", result);
}

直线在平面坐标(笛卡尔坐标系)有两个参数决定(截距B,斜率K);在极坐标空间两个参数决定(半径R,角度θ):

opencv4入门笔记(33):霍夫直线检测-萤火

HoughLines:霍夫直线检测

对噪声敏感,使用前需要降噪

void 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:输入8-bit单通道二值图,可能会被该函数修改
  • lines:输出直线vector(r,θ) 或 (r,θ,votes)
    • r是距坐标原点的距离
    • θ是以弧度表示的线旋转角度(0∼垂直直线,π/2∼水平直线)
    • votes 曲线交点累加计数
  • rho:以像素为单位的累加器的距离分辨率。 推荐用1.0。步长
  • theta:以弧度表示的累加器角度分辨率。 CV_PI/180。弧长
  • threshold:累加计数大于此阈值才返回 累加平面的阈值参数,int类型,超过设定阈值才被检测出线段,值越大,基本上意味着检出的线段越长,检出的线段个数越少。根据情况推荐先用100试试
  • srn:0
  • stn:0
  • min_theta:检查线条的最小角度。必须介于0和maxn_theta之间
  • max_theta:要检查线条的最大角度。必须介于min_theta和CV_PI之间。

HoughLinesP:霍夫线段检测

void HoughLinesP( InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLineLength = 0, double maxLineGap = 0 );
  • image:输入8-bit单通道二值图,可能会被该函数修改
  • lines:输入vector包含4个元素x1,x2,y1,y2,代表线段起点和终点坐标
  • rho:以像素为单位的累加器的距离分辨率。 推荐用1.0。步长
  • theta:以弧度表示的累加器角度分辨率。 CV_PI/180。弧长
  • threshold:累加计数大于此阈值才返回 累加平面的阈值参数,int类型,超过设定阈值才被检测出线段,值越大,基本上意味着检出的线段越长,检出的线段个数越少。根据情况推荐先用100试试
  • minLineLength:小于该值长度的线程会被过滤掉,单位像素
  • maxLineGap:线段中间可以断多少个像素