C++ image processing based on opencv (Hough line detection and least squares line fitting)

foreword

Based on the c++ interface of opencv, it realizes standard Hough line detection, Hough line detection based on statistical probability, and least square method line fitting.

Related opencv interface analysis

CV_EXPORTS_W 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 );

This function implements the standard or standard multiscale Hough transform algorithm for line detection. See http://homepages.inf.ed.ac.uk/rbf/HIPR2/hough.htm for a good explanation of the Hough transform.
@param image 8-bit single-channel binary source image. This function modifies the image. Output vector of
@param lines lines. Each line is represented by a 2 or 3 element vector (rho, theta) or (rho, theta, votes). rho is the distance from the coordinate origin (0,0) (upper left corner of the image). theta is the angle of rotation of the line in radians. votes is the value of the accumulator.
@param rho The distance resolution of the accumulator in pixels.
@param theta The angular resolution of the accumulator in radians.
@param threshold Accumulator threshold parameter. Return only those rows that get enough votes.
@param srn For the multiscale Hough transform, it is the divisor of the distance resolution rho. The coarse accumulator distance resolution is rho and the fine accumulator resolution is rho/srn. If srn=0 and stn=0, the classical Hough transform is used. Otherwise, both parameters should be positive numbers.
@param stn is the divisor of the distance resolution theta for the multiscale Hough transform.
@param min_theta For standard and multiscale Hough transforms, the minimum angle to check for lines. Must be between 0 and max_theta.
@param max_theta For standard and multiscale Hough transforms, the maximum angle to check for lines.
Must be between min_theta and CV_PI.

CV_EXPORTS_W void HoughLinesP( InputArray image, OutputArray lines,
                               double rho, double theta, int threshold,
                               double minLineLength = 0, double maxLineGap = 0 );

This function implements the probabilistic Hough transform algorithm for line detection.
@param image 8-bit single-channel binary source image. This function modifies the image. Output vector of
@param lines lines. Each line is represented by a 4-element vector (x_1, y_1, x_2, y_2), where (x_1,y_1) and (x_2, y_2) are each detected end line segment.
@param rho The distance resolution of the accumulator in pixels.
@param theta The angular resolution of the accumulator in radians.
@param threshold Accumulator threshold parameter. Return only those rows that get enough votes ({threshold}).
@param minLineLength minimum line length. Line segments shorter than this are rejected.
@param maxLineGap The maximum gap allowed between points on the same line to link them.

CV_EXPORTS_W bool solve(InputArray src1, InputArray src2,
                        OutputArray dst, int flags = DECOMP_LU);

The function cv::solve solves a linear system or a least squares problem (the latter can use SVD or QR methods, or by specifying the flag #DECOMP_NORMAL)
@param src1 The input matrix to the left of the system.
@param src2 The input matrix on the right side of the system.
@param dst output solution.
@param flags solution (matrix inversion) method (#DecompTypes)

//! matrix decomposition types
enum DecompTypes {
    
    
    /** Gaussian elimination with the optimal pivot element chosen. */
    DECOMP_LU       = 0,
    /** singular value decomposition (SVD) method; the system can be over-defined and/or the matrix
    src1 can be singular */
    DECOMP_SVD      = 1,
    /** eigenvalue decomposition; the matrix src1 must be symmetrical */
    DECOMP_EIG      = 2,
    /** Cholesky \f$LL^T\f$ factorization; the matrix src1 must be symmetrical and positively
    defined */
    DECOMP_CHOLESKY = 3,
    /** QR factorization; the system can be over-defined and/or the matrix src1 can be singular */
    DECOMP_QR       = 4,
    /** while all the previous flags are mutually exclusive, this flag can be used together with
    any of the previous; it means that the normal equations
    \f$\texttt{src1}^T\cdot\texttt{src1}\cdot\texttt{dst}=\texttt{src1}^T\texttt{src2}\f$ are
    solved instead of the original system
    \f$\texttt{src1}\cdot\texttt{dst}=\texttt{src2}\f$ */
    DECOMP_NORMAL   = 16
};

sample code

lines.h

#pragma once
#include <iostream>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>

using namespace std;
using namespace cv;
#define PROCESS_IMG_SUCESS 0
#define PROCESS_IMG_FAIL 1

namespace ImgLocate
{
    
    
	//寻找直线
	class FindLines
	{
    
    
	public:
		FindLines() {
    
     cout << "FindLines is being created" << endl; } // 这是构造函数声明
		~FindLines() {
    
     cout << "FindLines is being deleted" << endl; } // 这是析构函数声明
		int StandardHoughLineDetect(cv::Mat srcImage, cv::Mat &dstImage, double rhoStep, double thetaStep, int threshold);//标准的霍夫直线检测
		int StatisticalProbabilityHoughLineDetect(cv::Mat srcImage, cv::Mat &dstImage, double rhoStep, double thetaStep, int threshold, double minLineLength, double maxLineGap);//统计概率的霍夫直线检测
		int LeastSquaresLineFit(cv::Mat srcImage, cv::Mat &dstImage, vector<Point> points, Mat &result);//最小二乘法直线拟合:y=kx+b
																									
	};
}

lines.cpp

#include"lines.h"

int ImgLocate::FindLines::StandardHoughLineDetect(cv::Mat srcImage, cv::Mat &dstImage, double rhoStep, double thetaStep, int threshold)
{
    
    
	//判断图像是否加载成功
	if (srcImage.empty())
	{
    
    
		cout << "图像加载失败!" << endl;
		return 1;
	}
	dstImage = srcImage.clone();
	cv::cvtColor(dstImage, dstImage, COLOR_GRAY2BGR);
	//Mat houghMat = srcImage.clone();
	// 标准的霍夫变换
	vector<Vec2f> lines;
	HoughLines(srcImage, lines, rhoStep, thetaStep, threshold, 0, 0);
	std::cout << "直线数量:" << lines.size() << std::endl;
	for (size_t i = 0; i < lines.size(); i++)
	{
    
    
		// 根据直线参数表达式绘制相应检测结果
		float rho = lines[i][0], theta = lines[i][1];
		Point pt1, pt2;
		double a = cos(theta), 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));
		line(dstImage, pt1, pt2, Scalar(0, 0, 255), 3, 8);
	}
	//cv::namedWindow("houghMat", 0);
	//cv::imshow("houghMat", dstImage);
	return 0;
}

int ImgLocate::FindLines::StatisticalProbabilityHoughLineDetect(cv::Mat srcImage, cv::Mat &dstImage, double rhoStep, double thetaStep, int threshold, double minLineLength, double maxLineGap)
{
    
    
	//判断图像是否加载成功
	if (srcImage.empty())
	{
    
    
		cout << "图像加载失败!" << endl;
		return 1;
	}
	dstImage = srcImage.clone();
	cv::cvtColor(dstImage, dstImage, COLOR_GRAY2BGR);
	// 统计概率的霍夫变换
	vector<Vec4i> lines;
	HoughLinesP(srcImage, lines, rhoStep, thetaStep, threshold, minLineLength, maxLineGap);
	std::cout << "直线数量:" << lines.size() << std::endl;
	for (size_t i = 0; i < lines.size(); i++)
	{
    
    
		Vec4i l = lines[i];
		// 绘制线检测结果
		line(dstImage, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 3, 8);
	}
	return 0;
}

int ImgLocate::FindLines::LeastSquaresLineFit(cv::Mat srcImage, cv::Mat &dstImage, vector<Point> points, Mat &result)
{
    
    
	dstImage = srcImage.clone();
	//cv::cvtColor(dstImage, dstImage, COLOR_GRAY2BGR);
	for (int i = 0; i < points.size(); i++)
	{
    
    
		//在原图上画出点
		circle(dstImage, points[i], 3, Scalar(255, 0, 0), 1, 8);
	}
	//构建A矩阵 
	int N = 2;
	Mat A = Mat::zeros(N, N, CV_64FC1);

	for (int row = 0; row < A.rows; row++)
	{
    
    
		for (int col = 0; col < A.cols; col++)
		{
    
    
			for (int k = 0; k < points.size(); k++)
			{
    
    
				A.at<double>(row, col) = A.at<double>(row, col) + pow(points[k].x, row + col);
			}
		}
	}
	//构建B矩阵
	Mat B = Mat::zeros(N, 1, CV_64FC1);
	for (int row = 0; row < B.rows; row++)
	{
    
    

		for (int k = 0; k < points.size(); k++)
		{
    
    
			B.at<double>(row, 0) = B.at<double>(row, 0) + pow(points[k].x, row)*points[k].y;
		}
	}
	//A*X=B
	Mat X;
	//cout << A << endl << B << endl;
	solve(A, B, X, DECOMP_LU);
	cout << "[k;b]=" << X << endl;
	result = X;
	vector<Point>lines;
	for (int x = 0; x < srcImage.size().width; x++)
	{
    
    				// y = b + ax;
		double y = X.at<double>(0, 0) + X.at<double>(1, 0)*x;
		printf("(%d,%lf)\n", x, y);
		lines.push_back(Point(x, y));
	}
	polylines(dstImage, lines, false, Scalar(0, 0, 255), 1, 8);
	//namedWindow("srcImageLine",0);
	//imshow("srcImageLine", dstImage);

	return 0;

}

test.cpp

#include"lines.h"

ImgLocate::FindLines ImgFindLine;

int main()
{
    
    
	// 读取源图像及判断
	cv::Mat srcImage = cv::imread("building.jpg", 0);
	if (!srcImage.data)
	{
    
    
		return 1;
	}
	cv::namedWindow("原始图", 0);
	cv::imshow("原始图", srcImage);
	// 转化为灰度图像
	cv::Mat srcGray;
	if (srcImage.channels() == 3)
	{
    
    
		cv::cvtColor(srcImage, srcGray, COLOR_RGB2GRAY);
	}
	else
	{
    
    
		srcGray = srcImage.clone();
	}
	cv::namedWindow("灰度图", 0);
	cv::imshow("灰度图", srcGray);

	cv::Mat edgeMat;
	// Canny边缘检测 二值图像
	Canny(srcGray, edgeMat, 50, 200, 3);
	cv::namedWindow("edgeMat", 0);
	cv::imshow("edgeMat", edgeMat);
	标准的霍夫直线检测
	Mat standardLineImage;
	ImgFindLine.StandardHoughLineDetect(edgeMat, standardLineImage, 3, CV_PI / 180, 600);
	cv::namedWindow("标准的霍夫直线检测", 0);
	cv::imshow("标准的霍夫直线检测", standardLineImage);

	//统计概率的霍夫直线检测
	Mat statisticalImage;
	ImgFindLine.StatisticalProbabilityHoughLineDetect(edgeMat, statisticalImage, 3, CV_PI / 180, 600,50,10);
	cv::namedWindow("统计概率的霍夫直线检测", 0);
	cv::imshow("统计概率的霍夫直线检测", statisticalImage);

	//最小二乘法直线拟合:y=kx+b
	vector<Point>points;
	//(27 39) (8 5) (8 9) (16 22) (44 71) (35 44) (43 57) (19 24) (27 39) (37 52)
	points.push_back(Point(27, 39));
	points.push_back(Point(8, 5));
	points.push_back(Point(8, 9));
	points.push_back(Point(16, 22));
	points.push_back(Point(44, 71));
	points.push_back(Point(35, 44));
	points.push_back(Point(43, 57));
	points.push_back(Point(19, 24));
	points.push_back(Point(27, 39));
	points.push_back(Point(37, 52));
	Mat src = Mat::zeros(400, 400, CV_8UC3);
	Mat dstImage,result;
	ImgFindLine.LeastSquaresLineFit(src, dstImage,  points, result);
	cv::namedWindow("最小二乘直线拟合", 0);
	cv::imshow("最小二乘直线拟合", dstImage);
	cv::waitKey(0);

	return 0;

}

Result display

insert image description here

Guess you like

Origin blog.csdn.net/qq_40118285/article/details/127091730