OpenCV_(Fit Line with points)用直线拟合一组点

 

 // 5. 用直线拟合一组点------------------------------------------------------

	cv::Mat image = cv::imread("../../aTestImage/road2.jpg", 0);//Building
	cv::Mat contours;

	//阈值1:确定应该包含所有认为是属于明显图像轮廓的边缘像素
	//阈值2:定义属于所有重要边缘,剔除异常值(不连续边缘点)
	//磁滞阈值化
	cv::Canny(image, contours, 125, 350);//主体为白色
	cv::namedWindow("contours", 1);
	cv::imshow("contours", contours);
	LinesFinder  finder;
	finder.setLineLengthAndGap(100, 20);
	finder.setMinVote(80);

	//cv::Vec4i : (x0,y0, x1,y1)
	std::vector<cv::Vec4i> lines = finder.findLines(contours);

	int n = 1;//选择contours中的一条线: 如第2条
	cv::Mat oneline(contours.size(), CV_8U, cv::Scalar(0));

	cv::line(oneline, cv::Point(lines[n][0], lines[n][1]),
		cv::Point(lines[n][2], lines[n][3]), cv::Scalar(255), 10);

	cv::bitwise_and(contours, oneline, oneline);// 跟轮廓contours作 与 运算

	cv::namedWindow("oneline", 1);
	cv::imshow("oneline", oneline);

	//将oneline中的点放入到cv::points集合中
	std::vector<cv::Point> points;
	for (int y = 0; y < oneline.rows; y++)
	{
		uchar *rowPtr = oneline.ptr<uchar>(y);
		for (int x = 0; x < oneline.cols; x++)
		{
			if (rowPtr[x])
			{
				points.push_back(cv::Point(x, y));
			}
		}
	}
	//使用cv::fitline函数 将点数组 拟合成直线
	cv::Vec4f line;  //(cos, sin, x0,y0)
	cv::fitLine(cv::Mat(points), line, CV_DIST_L2, 0, 0.01, 0.01);
	std::cout << "line: (" << line[0] << "," << line[1] << ")(" << line[2] << "," << line[3] << ")\n";
	int x0 = line[2];
	int y0 = line[3];
	int x1 = x0 - 200 * line[0];
	int y1 = y0 - 200 * line[1];
	//在图像image上标记出该直线 设定长度100,颜色黑,宽度3
	cv::line(image, cv::Point(x0, y0), cv::Point(x1, y1), cv::Scalar(0), 3);
	cv::namedWindow("imageL", 1);
	cv::imshow("imageL", image);

	cv::waitKey(0);
	return 0;

linesFinder类 .h:

#pragma once
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <iostream>
#define  PI 3.1415926
class LinesFinder
{
public:
	LinesFinder() :
		deltaRho(1), deltaTheta(PI / 180),minVote(10),minLength(0.),maxGap(0.) {}  //初始化


	~LinesFinder();
	//设置累加器的分辨率
	void setAccResolution(double dRho, double dTheta)
	{
		deltaRho = dRho;
		deltaTheta = dTheta;
	}
	//设置最小投票数
	void setMinVote(int minv)
	{
		minVote = minv;
	}
	//设置缺口及长度
	void setLineLengthAndGap(double length, double gap)
	{
		minLength = length;
		maxGap = gap;
	}
	//使用概率霍夫变换
	std::vector<cv::Vec4i> findLines(cv::Mat &binary);
	//绘制线段
	void drawDetectLines(cv::Mat &image, cv::Scalar color = cv::Scalar(255, 255, 255));


private:
	cv::Mat img;
	std::vector<cv::Vec4i> lines; //向量中包含检查到直线的端点
	double deltaRho; //半径
	double deltaTheta;// 与垂直线之间的角度
	int minVote; //最小投票数
	double minLength; // 线段最小长度
	double maxGap; //沿直线方向最大缺口
};

 

 

linesFinder类 .cpp:

#include "stdafx.h"
#include "LinesFinder.h"




//LinesFinder::LinesFinder()
//{
//}




LinesFinder::~LinesFinder()
{
}


std::vector<cv::Vec4i> LinesFinder::findLines(cv::Mat & binary)
{
	lines.clear();
	cv::HoughLinesP(binary, lines, deltaRho, deltaTheta, minVote, minLength, maxGap);
	return lines;
}


void LinesFinder::drawDetectLines(cv::Mat & image, cv::Scalar color)
{
	std::vector<cv::Vec4i>::const_iterator it2 = lines.begin();
	while (it2 != lines.end())
	{
		cv::Point pt1((*it2)[0], (*it2)[1]);
		cv::Point pt2((*it2)[2], (*it2)[3]);
		cv::line(image, pt1, pt2, color);
		++it2;
	}
}

 

 

 

 

 

OpenCVSharp中,可以使用HoughLines方法进行直线检测,但是它只能得到直线的极坐标表示,而不是直线的参数。如果需要进行高精度直线拟合,可以使用RANSAC算法。 RANSAC(Random Sample Consensus)是一种随机抽样一致性算法,它可以从一组含有异常数据的观测数据中,估计出一个数学模型的参数,而不受异常数据的影响。 下面是使用OpenCVSharp和RANSAC算法进行直线拟合的示例代码: ```csharp using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using OpenCvSharp; namespace LineFitting { class Program { static void Main(string[] args) { Mat img = Cv2.ImRead("test.jpg", ImreadModes.GrayScale); Mat edges = new Mat(); Cv2.Canny(img, edges, 50, 200); // Detect lines using Hough transform LineSegmentPoint[] lines = Cv2.HoughLinesP(edges, 1, Math.PI / 180, 50, 50, 10); // Convert lines to points List<Point2f> points = new List<Point2f>(); foreach (var line in lines) { points.Add(new Point2f(line.P1.X, line.P1.Y)); points.Add(new Point2f(line.P2.X, line.P2.Y)); } // RANSAC line fitting int numIterations = 1000; float threshold = 1.0f; int numPointsToFit = 2; LineSegmentPoint bestLine = RansacLineFitting(points, numIterations, threshold, numPointsToFit); // Draw the line Cv2.Line(img, bestLine.P1, bestLine.P2, Scalar.Red, 2); Cv2.ImShow("Line Fitting", img); Cv2.WaitKey(); Cv2.DestroyAllWindows(); } static LineSegmentPoint RansacLineFitting(List<Point2f> points, int numIterations, float threshold, int numPointsToFit) { LineSegmentPoint bestLine = new LineSegmentPoint(); int bestScore = 0; for (int i = 0; i < numIterations; i++) { // Choose two random points Point2f p1 = points[new Random().Next(points.Count)]; Point2f p2 = points[new Random().Next(points.Count)]; // Fit line to these points LineSegmentPoint line = new LineSegmentPoint(p1, p2); // Calculate score for this line int score = 0; foreach (var point in points) { float distance = DistanceToLine(line, point); if (distance < threshold) score++; } // Check if this is the best line so far if (score > bestScore && score >= numPointsToFit) { bestLine = line; bestScore = score; } } return bestLine; } static float DistanceToLine(LineSegmentPoint line, Point2f point) { float px = line.P2.X - line.P1.X; float py = line.P2.Y - line.P1.Y; float something = px * px + py * py; float u = ((point.X - line.P1.X) * px + (point.Y - line.P1.Y) * py) / something; float x = line.P1.X + u * px; float y = line.P1.Y + u * py; float dx = x - point.X; float dy = y - point.Y; return (float)Math.Sqrt(dx * dx + dy * dy); } } } ``` 该代码首先使用Canny边缘检测算法检测输入图像的边缘。然后使用HoughLinesP方法从边缘图像中检测直线,并将直线转换为。接下来,使用RANSAC算法对这些进行直线拟合,找到最佳拟合直线。最后,使用OpenCVSharp的Line方法在输入图像中绘制该直线
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

惊鸿一博

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值