Hough 变换可以提取图像中的直线。但是提取的直线的精度不高。而很多场合下,我们需要精确的估计直线的参数,这时就需要进行直线拟合。

直线拟合的方法很多,比如一元线性回归就是一种最简单的直线拟合方法。但是这种方法不适合用于提取图像中的直线。因为这种算法假设每个数据点的X 坐标是准确的,Y 坐标是带有高斯噪声的。可实际上,图像中的每个数据点的XY 坐标都是带有噪声的。

下面就来讲讲适用于提取图像中直线的直线拟合算法。

一个点 <script type="math/tex" id="MathJax-Element-140">(x_i, y_i)</script> 到直线的距离用 <script type="math/tex" id="MathJax-Element-141">r_i</script> 来表示。

所谓直线拟合,就是找到一条直线,使得:

<script type="math/tex; mode=display" id="MathJax-Element-582"> \sum \rho(r_i) </script>

最小。

<script type="math/tex" id="MathJax-Element-583">\rho(r)</script> 是距离函数。<script type="math/tex" id="MathJax-Element-584">\rho(r)</script> 函数取不同的形式,对应不同的直线拟合方法。OpenCV 中支持 6 种不同的<script type="math/tex" id="MathJax-Element-585">\rho(r)</script> 函数形式。分别是:

CV_DIST_L2

<script type="math/tex; mode=display" id="MathJax-Element-586"> \rho(r) = \frac{r^2}{2} </script>

这种方法是以距离平方和为拟合判据。也就是常见的最小二乘拟合算法,运行速度也最快。但是这个算法也有个很大的问题,就是当干扰点离直线较远时,一个干扰点就可能将整条拟合直线拉偏了。简单的说就是对干扰点的鲁棒性不够。所以后来又提出了其他的函数。

CV_DIST_L1

<script type="math/tex; mode=display" id="MathJax-Element-248"> \rho(r) = r </script>

CV_DIST_L12

<script type="math/tex; mode=display" id="MathJax-Element-249"> \rho(r) = 2 \left( \sqrt{1 + \frac{r^2}{2}} -1 \right ) </script>

CV_DIST_FAIR

<script type="math/tex; mode=display" id="MathJax-Element-250"> \rho(r) = C^2 \left( \frac{r}{C} - \log \left(1+\frac{r}{C}\right)\right ) </script>
其中 C = 1.3998

CV_DIST_WELSCH

<script type="math/tex; mode=display" id="MathJax-Element-251"> \rho(r) = \frac{C^2}{2} \left ( 1 - \exp\left( - \left(\frac{r}{C}\right)^2\right) \right ) </script>
其中 C = 2.9846

CV_DIST_HUBER

<script type="math/tex; mode=display" id="MathJax-Element-635"> \rho(r) =\begin{cases} \frac{r^2}{2}& if \ \ r

其中 C = 1.345

后面这 5 种函数我知道第一种,其他的不知道是怎么来的。OpenCV 的帮助文档给出了一个链接:M-estimator

但是这个页面也被墙了。

下面来说说 OpenCV 提供的直线拟合函数。函数原型如下:

void fitLine( InputArray points, OutputArray line, int distType,double param, double reps, double aeps );
  • 1

distType 指定拟合函数的类型,可以取 CV_DIST_L2、CV_DIST_L1、CV_DIST_L12、CV_DIST_FAIR、CV_DIST_WELSCH、CV_DIST_HUBER。

param 就是 CV_DIST_FAIR、CV_DIST_WELSCH、CV_DIST_HUBER 公式中的C。如果取 0,则程序自动选取合适的值。

reps 表示直线到原点距离的精度,建议取 0.01。
aeps 表示直线角度的精度,建议取 0.01。

计算出的直线信息存放在 line 中,为 cv::Vec4f 类型。line[0]、line[1] 存放的是直线的方向向量。line[2]、line[3] 存放的是直线上一个点的坐标。

如果直线用 <script type="math/tex" id="MathJax-Element-846">y = k x + b</script> 来表示,那么 k = line[1]/line[0],b = line[3] - k * line[2]。

如果直线用 <script type="math/tex" id="MathJax-Element-847">\rho = x \cos \theta+ y \sin \theta</script> 来表示, 那么 <script type="math/tex" id="MathJax-Element-848">\theta = \arctan k + \frac{\pi}{2} </script>

下面是个测试图像:

图像中有一条直线和一些干扰图案。

下面的代码可以从图像中提取出需要的坐标点。

std::vector<cv::Point> getPoints(cv::Mat &image, int value)
{int nl = image.rows; // number of linesint nc = image.cols * image.channels();std::vector<cv::Point> points;for (int j = 0; j < nl; j++){uchar* data = image.ptr<uchar>(j);for (int i = 0; i < nc; i++){if(data[i] == value){points.push_back(cv::Point(i, j));}}}return points;
}

下面的代码可以在图中画一条直线。

void drawLine(cv::Mat &image, double theta, double rho, cv::Scalar color)
{if (theta < PI/4. || theta > 3.*PI/4.)// ~vertical line{cv::Point pt1(rho/cos(theta), 0);cv::Point pt2((rho - image.rows * sin(theta))/cos(theta), image.rows);cv::line( image, pt1, pt2, cv::Scalar(255), 1);}else{cv::Point pt1(0, rho/sin(theta));cv::Point pt2(image.cols, (rho - image.cols * cos(theta))/sin(theta));cv::line(image, pt1, pt2, color, 1);}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

下面的代码是程序的主体。

int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);cv::Mat image = imread("c:\\line_test.png", cv::IMREAD_GRAYSCALE);std::vector<cv::Point> points = getPoints(image, 0);cv::Vec4f line;cv::fitLine(points,line,CV_DIST_HUBER   ,0,0.01,0.01);double cos_theta = line[0];double sin_theta = line[1];double x0 = line[2], y0 = line[3];double phi = atan2(sin_theta, cos_theta) + PI / 2.0;double rho = y0 * cos_theta - x0 * sin_theta;std::cout << "phi = " << phi / PI * 180 << std::endl;std::cout << "rho = " << rho << std::endl;drawLine(image, phi, rho, cv::Scalar(0));double k = sin_theta / cos_theta;double b = y0 - k * x0;double x = 0;double y = k * x + b;std::cout << k << std::endl;std::cout << b << std::endl;//cv::line(image, Point(x0,y0), Point(x,y), cv::Scalar(255), 1);imshow("", image);return a.exec();
}

如果直线拟合类型选择 CV_DIST_L2。那么效果就没这么好了。代码不贴了,就贴个结果。

OpenCV 学习(直线拟合)相关推荐

  1. OpenCV fitline直线拟合函数学习

    下图是OpenCV官方文档中,对直线拟合函数的详细介绍: fitLine()函数用于,对二维或三维空间中的点集进行直线拟合.共有六个参数: param 1:输入的点集,可以是Mat或者vector&l ...

  2. opencv学习——最小二乘法拟合直线

    最小二乘法拟合直线 概念:最小二乘法多项式直线拟合,根据给定的点,求出它的函数y=f(x),当然求得准确的函数是不太可能的,但是我们能求出它的近似曲线y=φ(x) 原理 假设有点  , I = 1,2 ...

  3. 关于opencv fitLine直线拟合得斜率及截距

    函数接口:C++: void fitLine(InputArray points, OutputArray line, int distType, double param, double reps, ...

  4. 【OpenCV】56 二值图像分析–直线拟合与极值点寻找

    56 二值图像分析–直线拟合与极值点寻找 代码 import cv2 as cv import numpy as npdef canny_demo(image):t = 80canny_output ...

  5. OpenCV直线拟合检测

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 本文转自:opencv学堂 OpenCV直线拟合检测 霍夫直线检测 ...

  6. [OpenCV]直线拟合

    OpenCV实现了直线的拟合. CV_IMPL void cvFitLine( const CvArr* array, int dist, double param,double reps, doub ...

  7. OpenCV—直线拟合fitLine

    本文的主要参考为官方文档OpenCV249-fitLine和博客-OpenCV 学习(直线拟合) 以及<Learning OpenCV 3>page425-426 OpenCV中提供的直线 ...

  8. 【学习OpenCV】基于opencv的直线和曲线拟合与绘制(最小二乘法)

    自动驾驶工具箱-车道保持辅助与车道检测 最小二乘法多项式曲线拟合,是常见的曲线拟合方法,有着广泛的应用,这里在借鉴最小二乘多项式曲线拟合原理与实现的原理的基础上,介绍如何在OpenCV来实现基于最小二 ...

  9. OpenCV | 直线拟合fitline函数(Python)

    简介 之前做直线拟合时,自己写了一个利用最小二乘做直线拟合的程序,但是由于直线检测的误差比较大,拟合的效果并不好.个人不知道是什么原因,因此想尝试更改一下直线拟合的算法,后来找到了OpenCV中的fi ...

最新文章

  1. WinForm下ComboBox获取绑定对象集的SelectedValue补充
  2. 苹果iCloud或在今年晚些时候支持游戏中心和苹果地图
  3. 面试的27个经典问题
  4. 1分钟了解协同过滤,pm都懂了
  5. 2022年Spark基础学习笔记目录
  6. 4.二叉搜索树转为有序双向链表(递归算法与非递归算法)
  7. php7 捕获语法错误,PHP7 method_exists未捕获错误:函数名称必须是字符串
  8. 梯度消失与梯度爆炸---解决方案(二)--杀手锏
  9. uniapp 生成二维码长按保存_工程设备巡检如何用二维码管理?
  10. 找到的The LEGEND of the DRAGON的新下载地址
  11. ExecutorService的四种线程池
  12. 第7章 PCA与梯度上升法 学习笔记中
  13. Xslt中的Xsl:copy与Xsl:copy-of的区别
  14. 锐捷客户端在Linux下的使用。
  15. 虚拟服务器内存性能指标,vSphere 虚拟环境中超额配置 CPU、 内存和存储的比例推荐及规划简述...
  16. echarts中国地图(省市两级经纬度版本)
  17. Matlab Gramm绘图工具箱
  18. U盘中毒文件被隐藏?U盘中毒了怎么恢复文件
  19. 第七周 项目4 - 队列数组
  20. 计算机操作日志文件,教你完全读懂Windows日志文件

热门文章

  1. java 如何获取本机所有ip地址呢?
  2. 将1亿以下阿拉伯数字转换为大写汉字
  3. 高级搜索技巧:site,link,inurl,allinurl,intitle,allintitle, allinanchor, allintext and other Google Keywords
  4. 大白话讲解卷积神经网络工作原理
  5. Qt基础之三十五:Qt中文乱码探索
  6. 助力产业碳中和 打造绿色低碳生活
  7. 计算机中一个汉字占用 存储空间,一个字母、数字、汉字所占用的内存空间
  8. php sku spu 商品开发,扩展知识 :产品 SKU和SPU
  9. python execjs详解_Python基于execjs运行js过程解析
  10. 网站维护的一个备份脚本