IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 图像算法:带源码OpenCV实现Halcon中的权重迭代直线拟合,减少异常点干扰 -> 正文阅读

[人工智能]图像算法:带源码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);
}

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

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-11-16 18:49:57  更:2021-11-16 18:50:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 6:16:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码