二值图像分析–直线拟合与极值点寻找

2023-11-23 08:50

本文主要是介绍二值图像分析–直线拟合与极值点寻找,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在图像的处理中,会遇到一种情况,根据给定的点集(比如轮廓)拟合出一条直线的情景。

1.最小二乘法拟合直线

最小二乘法多项式直线拟合,根据给定的点,求出它的函数 y = f ( x ) y=f(x) y=f(x),当然求得准确的函数是不太可能的,但是我们能够求出它的近似曲线 y = φ ( x ) y=φ(x) y=φ(x)

原理:
假如有点I = 1,2,3,……n,求近似曲线 y = φ ( x ) y=φ(x) y=φ(x),并且使得 y = φ ( x ) y=φ(x) y=φ(x) y = f ( x ) y=f(x) y=f(x)的平方偏差和最小偏差:

现在有点( x 1 , y 1 x_1,y_1 x1,y1),( x 2 , y 2 x_2,y_2 x2,y2)···( x n , y n x_n,y_n xn,yn)
设: 拟合多项式为: y = a x + b y=ax+b y=ax+b
平方偏差和如下:
e 2 = ∑ i = 1 n ( y i − y ) 2 = ∑ i = 1 n ( y i − ( a x + b ) ) 2 e^2=\sum_{i=1}^{n}(y_i-y)^2 =\sum_{i=1}^{n}(y_i-(ax+b))^2 e2=i=1n(yiy)2=i=1n(yi(ax+b))2

其中我们要找到一组最好的a和b,“最好的”就是要使选出的a b能使得所有的误差达到最小化。所以上面得到的 e 2 = ∑ i = 1 n ( y i − ( a x + b ) ) 2 e^2=\sum_{i=1}^{n}(y_i-(ax+b))^2 e2=i=1n(yi(ax+b))2就是一个关于a和b的函数。

2.多元函数极值与最值问题的理论依据

二元函数取极值的必要条件(类比一元函数)。

可以看到最小二乘法对各个变量求偏导,使得偏导值为0,即可得到最小值,因为e是关于a、b的函数,导数为0的点必定是最小值。
分别对a、b求偏导:
在这里插入图片描述
在这里插入图片描述

OpenCV中的API

  • 说明
    使线拟合2D或者3D点集。

    函数fitLine通过最小化 ∑ i ρ ( r i ) \sum_i \rho(r_i) iρ(ri)将线拟合到2维或3维点,其中 r i r_i ri是第 i t h i^{th} ith个点之间的距离,该线和 ρ ( r ) \rho(r) ρ(r)是一个距离函数。

    该算法基于M-estimator技术,该技术使用加权最小二乘算法迭代拟合直线。每次迭代后,权重 w i w_i wi被调整 ρ ( r i ) \rho(r_i) ρ(ri)

  • 声明

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

    points用于拟合直线的输入点集,可以是2维或者3维点向量。保存在std::vector<>或者Mat中。
    line输出的直线。对于二维直线而言,类型为cv::Vec4f;对于三维直线类型,则为cv::Vec6f。输出参数的前半部分给出的是直线的方向,而后半部分给出的是直线上的一点(即通常所说的点斜式直线)。
    distType距离类型。拟合直线时,要使输入点到拟合直线的距离和最小化,可供选择的距离类型如下, r i r_i ri表示的是输入的点到直线的距离。
    param某些距离类型的数值参数(C)。跟所选的距离类型有关,值可以设置为0,cv::fitLine()函数本身会自动选择最优化的值如果为0。
    reps半径的足够精度(坐标原点和直线之间的距离)。
    aeps角度精度足够。对于reps和aeps,0.01将是一个很好的默认值。
    distType类型

    ① DIST_L2
    ρ ( r ) = r 2 / 2 (the simplest and the fastest least-squares method) \rho(r) = r^2/2 \quad \text{(the simplest and the fastest least-squares method)} ρ(r)=r2/2(the simplest and the fastest least-squares method)
    ② DIST_L1
    ρ ( r ) = r \rho (r) = r ρ(r)=r
    ③ DIST_L12
    ρ ( r ) = 2 ⋅ ( 1 + r 2 2 − 1 ) \rho (r) = 2 \cdot ( \sqrt{1 + \frac{r^2}{2}} - 1) ρ(r)=2(1+2r2 1)
    ④ DIST_FAIR
    ρ ( r ) = C 2 ⋅ ( r C − log ⁡ ( 1 + r C ) ) where C = 1.3998 \rho \left (r \right ) = C^2 \cdot \left ( \frac{r}{C} - \log{\left(1 + \frac{r}{C}\right)} \right ) \quad \text{where} \quad C=1.3998 ρ(r)=C2(Crlog(1+Cr))whereC=1.3998
    ⑤ DIST_WELSCH
    ρ ( r ) = C 2 2 ⋅ ( 1 − exp ⁡ ( − ( r C ) 2 ) ) where C = 2.9846 \rho \left (r \right ) = \frac{C^2}{2} \cdot \left ( 1 - \exp{\left(-\left(\frac{r}{C}\right)^2\right)} \right ) \quad \text{where} \quad C=2.9846 ρ(r)=2C2(1exp((Cr)2))whereC=2.9846
    ⑥ DIST_HUBER
    ρ ( r ) = { r 2 / 2 i f r < C C ⋅ ( r − C / 2 ) o t h e r w i s e where C = 1.345 \rho (r)= \begin{cases} r^2/2 &if \ \ r < C \\ C \cdot (r-C/2) &otherwise \end{cases} \quad \text{where} \quad C=1.345 ρ(r)={r2/2C(rC/2)if  r<CotherwisewhereC=1.345

应用

void apprixiLine() {//创建一个用于绘图的空白图Mat src = Mat::zeros(480, 640, CV_8UC3);//输入需要拟合的点vector<Point> points;points.push_back(Point(48, 58));points.push_back(Point(105, 98));points.push_back(Point(155, 160));points.push_back(Point(212, 220));points.push_back(Point(248, 260));points.push_back(Point(320, 300));points.push_back(Point(350, 360));points.push_back(Point(412, 400));//将拟合点画到空白画板上for (size_t i = 0; i < points.size(); i++){circle(src, points[i], 5, Scalar(0, 0, 255));}imshow("src", src);Vec4f line_para;fitLine(points, line_para, DIST_L2, 0, 1e-2, 1e-2);cout << "line_para: " << line_para << endl;Point point0;point0.x = line_para[2];point0.y = line_para[3];cout << "point0:[" << point0.x << "," << point0.y << "]" << endl;double k = line_para[1] / line_para[0];cout << "k=" << k << endl;//计算直线的端点Point point1, point2;point1.x = 0;point1.y = k * (0 - point0.x) + point0.y;point2.x = 640;point2.y = k * (640 - point0.x) + point0.y;cout << "point1:[" << point1.x << "," << point1.y << "]" << endl;cout << "point2:[" << point2.x << "," << point2.y << "]" << endl;line(src, point1, point2, Scalar(0, 255, 0), 2);imshow("dst", src);
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. 事例二
void findFitLine(Mat& src) {//1. 转化灰度图像Mat gray;cvtColor(src, gray, COLOR_BGR2GRAY);//2. 二值化Mat binary;threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);//3. 获得二维点集vector<Point> point_para;Point point_temp;for (size_t i = 0; i < src.rows; i++){for (size_t j = 0; j < src.cols; j++){if (binary.at<unsigned char>(i, j) < 255) {point_temp.x = j;point_temp.y = i;point_para.push_back(point_temp);}}}//4.直线拟合//拟合结果为4元素的容器,比如Vec4f-(vx,vy,x0,y0)//(vx、vy)是直线的方向向量//(x0、y0)是直线上的一个点Vec4f fitline;fitLine(point_para, fitline, DIST_L2, 0, 0.01, 0.01);//4.2 求出直线上的两个点double k = fitline[1] / fitline[0];Point p1(0, k * (0 - fitline[2]) + fitline[3]);Point p2(src.cols - 1, k * ((src.cols - 1) - fitline[2]) + fitline[3]);//4.3 显示拟合出的直线方程cout << "y-" << fitline[3] << "=" << k << "(x-" << fitline[2] << ")" << endl;line(src, p1, p2, Scalar(0, 0, 255), 2);imshow("dst", src);
}int main() {Mat src = imread("D:/test/fitline.png");if (src.empty()) {cout << " input the image error!" << endl;}imshow("src", src);findFitLine(src);waitKey(0);return 0;}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

学习:

直线拟合——cv::fitLine()详解
【算法+OpenCV】基于opencv的直线和曲线拟合与绘制(最小二乘法)
opencv学习——最小二乘法拟合直线
OpenCV—直线拟合fitLine
【OpenCV3】直线拟合–FitLine()函数详解

这篇关于二值图像分析–直线拟合与极值点寻找的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/416755

相关文章

Nginx分布式部署流程分析

《Nginx分布式部署流程分析》文章介绍Nginx在分布式部署中的反向代理和负载均衡作用,用于分发请求、减轻服务器压力及解决session共享问题,涵盖配置方法、策略及Java项目应用,并提及分布式事... 目录分布式部署NginxJava中的代理代理分为正向代理和反向代理正向代理反向代理Nginx应用场景

Redis中的有序集合zset从使用到原理分析

《Redis中的有序集合zset从使用到原理分析》Redis有序集合(zset)是字符串与分值的有序映射,通过跳跃表和哈希表结合实现高效有序性管理,适用于排行榜、延迟队列等场景,其时间复杂度低,内存占... 目录开篇:排行榜背后的秘密一、zset的基本使用1.1 常用命令1.2 Java客户端示例二、zse

Redis中的AOF原理及分析

《Redis中的AOF原理及分析》Redis的AOF通过记录所有写操作命令实现持久化,支持always/everysec/no三种同步策略,重写机制优化文件体积,与RDB结合可平衡数据安全与恢复效率... 目录开篇:从日记本到AOF一、AOF的基本执行流程1. 命令执行与记录2. AOF重写机制二、AOF的

MyBatis Plus大数据量查询慢原因分析及解决

《MyBatisPlus大数据量查询慢原因分析及解决》大数据量查询慢常因全表扫描、分页不当、索引缺失、内存占用高及ORM开销,优化措施包括分页查询、流式读取、SQL优化、批处理、多数据源、结果集二次... 目录大数据量查询慢的常见原因优化方案高级方案配置调优监控与诊断总结大数据量查询慢的常见原因MyBAT

分析 Java Stream 的 peek使用实践与副作用处理方案

《分析JavaStream的peek使用实践与副作用处理方案》StreamAPI的peek操作是中间操作,用于观察元素但不终止流,其副作用风险包括线程安全、顺序混乱及性能问题,合理使用场景有限... 目录一、peek 操作的本质:有状态的中间操作二、副作用的定义与风险场景1. 并行流下的线程安全问题2. 顺

MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决

《MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决》MyBatis默认开启一级缓存,同一事务中循环调用查询方法时会重复使用缓存数据,导致获取的序列主键值均为1,... 目录问题原因解决办法如果是存储过程总结问题myBATis有如下代码获取序列作为主键IdMappe

Java中最全最基础的IO流概述和简介案例分析

《Java中最全最基础的IO流概述和简介案例分析》JavaIO流用于程序与外部设备的数据交互,分为字节流(InputStream/OutputStream)和字符流(Reader/Writer),处理... 目录IO流简介IO是什么应用场景IO流的分类流的超类类型字节文件流应用简介核心API文件输出流应用文

Android 缓存日志Logcat导出与分析最佳实践

《Android缓存日志Logcat导出与分析最佳实践》本文全面介绍AndroidLogcat缓存日志的导出与分析方法,涵盖按进程、缓冲区类型及日志级别过滤,自动化工具使用,常见问题解决方案和最佳实... 目录android 缓存日志(Logcat)导出与分析全攻略为什么要导出缓存日志?按需过滤导出1. 按

Linux中的HTTPS协议原理分析

《Linux中的HTTPS协议原理分析》文章解释了HTTPS的必要性:HTTP明文传输易被篡改和劫持,HTTPS通过非对称加密协商对称密钥、CA证书认证和混合加密机制,有效防范中间人攻击,保障通信安全... 目录一、什么是加密和解密?二、为什么需要加密?三、常见的加密方式3.1 对称加密3.2非对称加密四、

MySQL中读写分离方案对比分析与选型建议

《MySQL中读写分离方案对比分析与选型建议》MySQL读写分离是提升数据库可用性和性能的常见手段,本文将围绕现实生产环境中常见的几种读写分离模式进行系统对比,希望对大家有所帮助... 目录一、问题背景介绍二、多种解决方案对比2.1 原生mysql主从复制2.2 Proxy层中间件:ProxySQL2.3