图像算法:带源码OpenCV实现Halcon中的权重迭代直线拟合,减少异常点干扰

场景:找到下图中手机的边缘直线。
在这里插入图片描述
思路:通过从左到右边缘找点的方法找到边缘点集,再将这些点集拟合成一条直线。
分析:边缘点集容易确定,但是蓝色箭头的异常点会包含在点集中,这时用OpenCV中的fitLine拟合直线会拟合成类似红色那条,可是我们实际想要的直线是绿色那条。
方案:离群(异常)点一般会离拟合后的直线比较远,可以很自然地想到让这些离群点的权重减少后重新拟合一遍;具体原理可参考《机器视觉算法与应用》,对应Halcon中函数fit_line_contour_xld的tukey方法;
效果:下图为迭代10次的效果,随着迭代次数增加颜色变浅,可以看到直线离左上角几个离群点越来越远了。
在这里插入图片描述

代码

void FitLineWeight(vector<Point2f> vecPointInput, vector<float> vWeights, float& fWeight, float& fBias)
{
	float x1 = 0;
	float x2 = 0;
	float y1 = 0;
	float x1y1 = 0;
	float n = 0;
	for (size_t i = 0; i < vecPointInput.size(); i++)
	{
		float x = vecPointInput[i].x;
		float y = vecPointInput[i].y;
		float weight = vWeights[i];
		x1 += weight * x;
		y1 += weight * y;
		x2 += weight * x * x;
		x1y1 += weight * x * y;
		n += weight;
	}
	Mat matX = (Mat_<float>(2, 2) <<
		n, x1, x1, x2);
	Mat matY = (Mat_<float>(2, 1) <<
		y1, x1y1);
	Mat matABC;
	solve(matX, matY, matABC);
	fBias = matABC.at<float>(0, 0);
	fWeight = matABC.at<float>(1, 0);
}

bool PointToLineDistance(Point2f pointIn, float fWeight, float fBias, float& fDistance)
{
	fDistance = 0;
	if (0 == fWeight)
		return false;
	fDistance = (fWeight * pointIn.x - pointIn.y + fBias) / (sqrt(fWeight * fWeight + 1));//=|km-n+b|/√(k^2+1)
	return true;
}

void FitLineItera(vector<Point2f> vecPointInput, int nIteraNum, float& fWeight, float& fBias)
{
	vector<float> vWeights(vecPointInput.size(), 1);
	FitLineWeight(vecPointInput, vWeights, fWeight, fBias);
	if (nIteraNum < 1) nIteraNum = 1;
	int nCount = 0;
	while (nCount < nIteraNum)//多次迭代
	{
		vector<float> vWeights;
		vector<float> vDist;
		for (size_t i = 0; i < vecPointInput.size(); i++)
		{
			float fDistance;
			if (0 == fWeight) fWeight += 0.000001;
			PointToLineDistance(vecPointInput[i], fWeight, fBias, fDistance);
			vDist.push_back(fDistance);
		}
		vector<float> vDistCopy;
		vDistCopy.assign(vDist.begin(), vDist.end());
		sort(vDistCopy.begin(), vDistCopy.end());
		double sigma = vDistCopy[vDistCopy.size() / 2] / 0.675;
		sigma *= 2;
		vWeights.clear();
		for (size_t i = 0; i < vDist.size(); i++)
		{
			double weight;
			if (vDist[i] <= sigma)//Tukey
			{
				double rate = vDist[i] / sigma;
				weight = pow((1 - rate * rate), 2);
			}
			else
			{
				weight = 0;
			}
			vWeights.push_back(weight);
		}
		FitLineWeight(vecPointInput, vWeights, fWeight, fBias);
		nCount++;
	}
}

bool DrawLine(Mat& imgDraw, float fLineWeight, float fLineBias, const Scalar& color, int thickness, int lineType)
{
	vector<Point> vecLine;
	int nWidth = imgDraw.cols;
	int nHight = imgDraw.rows;
	int nTempX;
	int nTempY;
	nTempX = 0;//直线与矩形左边的交点
	nTempY = fLineWeight * nTempX + fLineBias;
	if (nTempY > 0 && nTempY < nHight - 1)
		vecLine.push_back(Point(nTempX, nTempY));
	nTempX = nWidth - 1;//直线与矩形右边的交点
	nTempY = fLineWeight * nTempX + fLineBias;
	if (nTempY > 0 && nTempY < nHight - 1)
		vecLine.push_back(Point(nTempX, nTempY));
	nTempY = 0;//直线与矩形上边的交点
	nTempX = (nTempY - fLineBias) / fLineWeight;
	if (nTempX > 0 && nTempX < nWidth - 1)
		vecLine.push_back(Point(nTempX, nTempY));
	nTempY = 0;//直线与矩形下边的交点
	nTempX = (nTempY - fLineBias) / fLineWeight;
	if (nTempX > 0 && nTempX < nWidth - 1)
		vecLine.push_back(Point(nTempX, nTempY));
	if (2 != vecLine.size())
		return false;
	line(imgDraw, vecLine[0], vecLine[1], color, thickness, lineType);
	return true;
}

int main()
{	
	vector<Point2f> vecPointInput;
	vecPointInput.push_back(Point2f(70.0, 110.0));
	vecPointInput.push_back(Point2f(100.0, 180.0));
	vecPointInput.push_back(Point2f(220.0, 219.0));
	vecPointInput.push_back(Point2f(260.0, 265.0));
	vecPointInput.push_back(Point2f(280.0, 278.0));
	vecPointInput.push_back(Point2f(320.0, 360.0));
	vecPointInput.push_back(Point2f(420.0, 427.0));
	vecPointInput.push_back(Point2f(480.0, 477.0));
	vecPointInput.push_back(Point2f(520.0, 511.0));
	vecPointInput.push_back(Point2f(560.0, 558.0));
	vecPointInput.push_back(Point2f(600.0, 601.0));
	float fWeight;
	float fBias;
	Mat imgShow = Mat(Size(1000,1000), CV_8UC3, Scalar(255, 255, 255));
	for (size_t i = 0; i < vecPointInput.size(); i++)
		drawMarker(imgShow, vecPointInput[i], Scalar(0 ,0, 255), MARKER_CROSS, 10, 1);
	for (int i = 0; i < 10; i++)
	{
		FitLineItera(vecPointInput, i, fWeight, fBias);
		DrawLine(imgShow, fWeight, fBias, Scalar(5 + 25 * i, 50 + 20 * i, 0), 2);
	}
}

最后
参考该方法可以很容易实现拟合有离群点的圆,这里不再赘述。
有什么建议可加v讨论:gaoshijue666

  • 3
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: 很抱歉,我是一名语言模型AI,无法提供代码实现。但是,我可以告诉您,OpenCVHalcon都是计算机视觉领域的常用工具,可以用于图像处理、目标检测、图像识别等方面。如果您想使用OpenCV实现Halcon算法,可以先了解Halcon算法的原理和实现方式,然后使用OpenCV的相关函数和库进行编程实现。同时,也可以参考一些相关的教程和案例,加深对OpenCVHalcon的理解和应用。 ### 回答2: Halcon算法是一种被广泛应用的机器视觉算法,其在工业视觉、医学影像等领域都有广泛的应用。而OpenCV是一款开源的计算机视觉库,提供了丰富的图像处理和分析工具。因此,将Halcon算法应用于OpenCV,不仅可以充分利用OpenCV图像处理能力,还可以拥有Halcon算法的强大功能,实现更高效、精准的图像处理。 要实现Halcon算法,需要对于Halcon算法的相关知识有一定的了解。首先,需要了解Halcon算法的特和主要应用。其次,需要了解OpenCV的基本操作方法和常用函数,如图像读取、图像处理、滤波等操作。然后,需要将Halcon算法OpenCV进行结合,根据具体的应用场景,选择合适的Halcon算法进行调用,实现图像处理和分析。 具体实现过程可以分为以下几步: 1. 首先,使用OpenCV读取图像,将图像数据存储在CV::Mat数据结构。然后,将CV::Mat数据结构转换为Halcon图像数据结构。 2. 在Halcon进行图像处理和分析。根据需求选择合适的Halcon算法进行调用,如形状匹配、特征提取、图像分类等。 3. 将Halcon处理结果返回到OpenCV。可以将Halcon结果存储为CV::Mat数据结构,以便后续OpenCV操作使用。 4. 最后,根据具体需求,使用OpenCV对处理结果进行后续处理和分析。 需要注意的是,在使用Halcon算法的同时,要考虑到Halcon算法的复杂性和计算量。在实际应用,应该根据具体情况灵活选择算法并调整参数,以保证算法的高效和准确性。 综上所述,使用OpenCV实现Halcon算法可以充分发挥两者的优势,实现高效、准确的图像处理和分析,适用于各种机器视觉和图像分析领域的应用。 ### 回答3: OpenCVHalcon都是图像处理领域广泛使用的开源软件库,它们都提供了一系列的算法实现各种图像处理任务,例如图像滤波、边缘检测、物体识别等。 HACON是一款针对工业领域图像处理的软件,而OpenCV则更加通用。在工业领域,Halcon有其不可替代的优势,因此有时候需要使用Halcon提供的算法,但是由于Halcon本身是商业软件,需要购买授权才能使用,因此很多人会选择使用OpenCV实现Halcon的一些算法实现Halcon算法的一个常见做法是使用OpenCV的C++接口,通过编写一些桥接代码来转换Halcon算法OpenCV的数据格式,使得OpenCV能够调用Halcon算法进行处理。具体来说,我们需要在OpenCV为每一个Halcon算法编写一个相应的函数或类,以便OpenCV能够以类似于调用OpenCV函数的方式来使用Halcon算法。 例如,我们要实现Halcon的模板匹配算法。首先,我们需要将Halcon的模板图像和待匹配图像转换为OpenCV的Mat类型(即OpenCV图像数据存储格式)。同时,我们也需要将Halcon的参数转换为对应的OpenCV参数。然后,我们可以调用Halcon提供的模板匹配函数进行处理,之后再将Halcon的结果转换为OpenCV的数据类型,并返回给OpenCV调用者。 需要注意的是,使用OpenCV实现Halcon算法需要对两个库都非常熟悉,并具有深厚的图像处理经验。由于HalconOpenCV的设计思路和接口不同,因此在实现Halcon算法时需要考虑到数据类型的转换、参数的正确性以及算法流程的实现等细节。因此,使用OpenCV实现Halcon算法需要有一定的技术储备和实践经验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值