PS:要转载请注明出处,本人版权所有。

PS: 这个只是基于《我自己》的理解,

如果和你的原则及想法相冲突,请谅解,勿喷。

前置说明

  本文作为本人csdn blog的主站的备份。(BlogID=115)

环境说明

  无

前言


  提到IOU,如果接触过目标检测,应该是很熟悉的,这个东西简直就是标配了。但是我之前见到的求IOU都是求两个矩形的IOU,由于矩形的特殊性,其IOU可以很简单的求。

  突然有一天,我要求一个矩形和一个多边形的IOU,这就让我突然有点懵,参考原来求两个矩形的IOU方式,完全无解。经过了询问大佬以及网上冲浪后,在某不起眼的地方发现了一个思路,一个匿名网友貌似提供了一句MATLAB的代码,给了我不错的启发。

  因此本文用c++和opencv实现了这部分代码。下面将会从IOU概念,两矩形的IOU,以及任意多边形之间的IOU顺序进行讲解。

交并比(Intersection of Union,IOU)


  我们定义一个多边形的面积为Area0,另外一个多边形的面积为Area1。那么IOU的数学定义为\(IOU=\frac{Area_0 \cap Area_1}{Area_0 \cup Area_1}\)。

  下面我们用一个示例图清晰的表达这个概念:

  其中B类区域就是两个多边形的交集。IOU求的是B类区域在A,B,C类区域中的占比。注意这里是占比。

两个矩形之间的IOU求法


  两个矩形的IOU求法其实交简单,根据一些性质,我们可以直接求出交集区域的宽和高,然后直接得到交集面积即可,这些都是常规写法。详情见如下代码:

float IOU(const cv::Rect &r0, const cv::Rect &r1)
{ if (r0.x > r1.x + r1.width) return 0.f;//top-x r0 在r1右边
if (r0.y > r1.y + r1.height) return 0.f;//top-y r0 在r1下边
if (r0.x + r0.width < r1.x) return 0.f;//bottom-x r0 在r1左边
if (r0.y + r0.height < r1.y) return 0.f;//bottom-y r0 在r1上边 // 此时必定相交
float _overlap_w = std::min(r0.x + r0.width, r1.x + r1.width) - std::max(r0.x, r1.x);//得到相交矩形w float _overlap_h = std::min(r0.y + r0.height, r1.y + r1.height) - std::max(r0.y, r1.y);//得到相交矩形h // maybe overflow
return (_overlap_w * _overlap_h)/(float)((r0.width*r0.height) + (r1.width*r1.height)); }

  如上可知,可以直接根据相关面积,求出IOU。

两个多边形之间的IOU求法


  我们需要求两个多边形的IOU,这个时候我们根据两个矩形的思路想想,貌似不好弄。这个时候我们可以转变一下思路。

  我们首先肯定是知道两个多边形的最大外接矩形的,这个时候我们得到最大的外界矩形宽和高(注意,这里的宽和高一般是固定的,所以一般我们都不需要去求外接矩)。然后我们创建三个宽和高等于我们预设的一维矩阵M_A, M_B,M_C,并将其所有元素置为0。这个时候,我们分别将矩阵一用多边形P1来来填充M_A,在P1内的元素置为1,外的元素不变。对M_B用同样的方式去填充。这个时候我们去计算M_C,具体计算方法是将对应的M_A,M_B同一位置的元素相与后赋值给M_C(表达式为:\(M_C(x,y) = M_A(x,y) \& M_B(x,y)\))。这个时候我们去统计M_A,M_B,M_C中1的个数,其实就得到了对应的面积(也可以叫做像素面积),这个时候我们就可以方便的求出IOU,值得注意的是opencv中提供了我们所需要的所有操作。

  下面我们用c++来实现以上的流程(注意,以下代码是实现的是N个多边形和M个多边形的IOU,若自己的需求不一样,请修改为对应的场景,代码是随手写的,未仔细验证,原理是这样的)。

float IoU(const std::vector<std::vector<cv::Point>> &poly_array0, const std::vector<std::vector<cv::Point>> &poly_array1, int max_w, int max_h){

        cv::Mat _poly0 = cv::Mat::zeros(max_h, max_w, CV_8UC1);
cv::Mat _poly1 = cv::Mat::zeros(max_h, max_w, CV_8UC1);
cv::Mat _result; std::vector<cv::Point *> _pts0;
std::vector<int> _npts0; for(auto &_v:poly_array0){ if (_v.size() < 3)//invalid poly
return -1.f; _pts0.push_back((cv::Point *)&_v[0]);
_npts0.push_back((int)_v.size());
} std::vector<cv::Point *> _pts1;
std::vector<int> _npts1;
for(auto &_v:poly_array1){ if (_v.size() < 3)//invalid poly
return -1.f; _pts1.push_back((cv::Point *)&_v[0]);
_npts1.push_back((int)_v.size());
}
/* void cv::fillPoly ( Mat & img,
const Point ** pts,
const int * npts,
int ncontours,
const Scalar & color,
int lineType = LINE_8,
int shift = 0,
Point offset = Point()
)
*/
cv::fillPoly(_poly0, (const cv::Point **)&_pts0[0], &_npts0[0], _npts0.size(), cv::Scalar(1)); cv::fillPoly(_poly0, (const cv::Point **)&_pts1[0], &_npts1[0], _npts1.size(), cv::Scalar(1)); cv::bitwise_and(_poly0, _poly1, _result); int _area0 = cv::countNonZero(_poly0);
int _area1 = cv::countNonZero(_poly1);
int _intersection_area = cv::countNonZero(_result); // float _iou = (float)_intersection_area/(float)(_area0 + _area1 - _intersection_area);
float _iou = (float)_intersection_area/(float)_area1; return _iou;
}

  通过如上代码,我们用opencv就实现了我们预想的效果。

后记


  注意,这里需要延伸一点,求IOU,我们一般是用交集除以并集,但是有些时候,可能我们会用交集除以其中一个集合。比如:一个小矩形,一个大多边形的iou,其实按照标准写法来看,iou的数值不处理的话,不是那么可爱的。

  其实这里的几种用法还可以延伸出来,比如算两个立方体的重合度等等。

参考文献


打赏、订阅、收藏、丢香蕉、硬币,请关注公众号(攻城狮的搬砖之路)

PS: 请尊重原创,不喜勿喷。

PS: 要转载请注明出处,本人版权所有。

PS: 有问题请留言,看到后我会第一时间回复。

一种实用性较强的求IOU的算法(任意多边形之间的IOU)的更多相关文章

  1. Geotools求shapefile路网中任意两点之间最短路径的距离

    前言:之前在博问求助过这个问题.经过几天的思考,算是解决了(但仍有不足),另一方面对Geotools不是很熟,有些描述可能不正确,希望大家批评指正. 问题:作为一个新手,我并没有发现Geotools中 ...

  2. Java中四种引用:强、软、弱、虚引用

    这篇文章非常棒:http://alinazh.blog.51cto.com/5459270/1276173 Java中四种引用:强.软.弱.虚引用 1.1.强引用当我们使用new 这个关键字创建对象时 ...

  3. Java四种引用包括强引用,软引用,弱引用,虚引用。

    Java四种引用包括强引用,软引用,弱引用,虚引用. 强引用: 只要引用存在,垃圾回收器永远不会回收Object obj = new Object();//可直接通过obj取得对应的对象 如obj.e ...

  4. 不可访问内存 Java四种引用包括强引用,软引用,弱引用,虚引用

    小结: 1.不可访问内存是指一组没有任何可访问指针指向的由计算机程序进行动态分配的内存块. 2.垃圾收集器能决定是否一个对象还是可访问的:任何被确定不可访问的对象将会被释放. https://zh.w ...

  5. Trees in a Wood. UVA 10214 欧拉函数或者容斥定理 给定a,b求 |x|<=a, |y|<=b这个范围内的所有整点不包括原点都种一棵树。求出你站在原点向四周看到的树的数量/总的树的数量的值。

    /** 题目:Trees in a Wood. UVA 10214 链接:https://vjudge.net/problem/UVA-10214 题意:给定a,b求 |x|<=a, |y|&l ...

  6. [NetTopologySuite](2)任意多边形求交

    任意多边形求交: private void btnPolygon_Click(object sender, EventArgs e) { , , , , , , , , , , , , , }; , ...

  7. hdoj 2196 Computer【树的直径求所有的以任意节点为起点的一个最长路径】

    Computer Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  8. 链表插入和删除,判断链表是否为空,求链表长度算法的,链表排序算法演示——C语言描述

    关于数据结构等的学习,以及学习算法的感想感悟,听了郝斌老师的数据结构课程,其中他也提到了学习数据结构的或者算法的一些个人见解,我觉的很好,对我的帮助也是很大,算法本就是令人头疼的问题,因为自己并没有学 ...

  9. 列举两种不同类型的Java标识注释,并解释它们之间的区别。

    列举两种不同类型的Java标识注释,并解释它们之间的区别.

随机推荐

  1. 洛谷 P7516 - [省选联考 2021 A/B 卷] 图函数(Floyd)

    洛谷题面传送门 一道需要发现一些简单的性质的中档题(不过可能这道题放在省选 D1T3 中偏简单了?) u1s1 现在已经是 \(1\text{s}\)​ \(10^9\)​ 的时代了吗?落伍了落伍了/ ...

  2. fastq文件基本信息统计工具

    之前写的一个小工具,写的很简陋,名字取的也很随意就叫skr,哈哈.主要是fq转fa.合并多个染色体的vcf文件等,功能不多(主要是C写起来太操蛋了T_T),通常我也只用来统计fastq文件信息: 这里 ...

  3. 毕业设计之LNP+DISCUZ +分离的数据库操作

    环境介绍: CentOS6.9最小化安装 https://nginx.org/download/nginx-1.16.1.tar.gz https://www.php.net/distribution ...

  4. NFS FTP SAMBA的区别

    Samba服务 samba是一个网络服务器,用于Linux和Windows之间共享文件. samba端口号 samba (启动时会预设多个端口) 数据传输的TCP端口 139.445 进行NetBIO ...

  5. rust Option枚举

    枚举 1 fn main() { 2 let a_binding; 3 { 4 let x = 2; 5 a_binding = x * x; 6 } 7 println!("a bindi ...

  6. 日常Java 2021/11/3

    java网络编程 网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来.java.net包中J2SE的APl包含有类和接口,它们提供低层次的通信细节.你可以直接使用这些类和接口, ...

  7. 零基础学习java------day3-运算符 以及eclipse的使用

    今日内容: 1. 算数运算符 2. 赋值运算符 3. 关系运算符 4. 逻辑运算符 5. 位运算符 6.三目运算符 一 运算符 运算:对常量和变量进行操作的过程称为运算 运算符:对常量和变量进行操作的 ...

  8. Vue相关,vue父子组件生命周期执行顺序。

    一.实例代码 父组件: <template> <div id="parent"> <child></child> </div& ...

  9. linux下的C++多线程

    原文链接:http://blog.csdn.net/lee1054908698/article/details/54633056 本随笔作为多线程笔记使用,内容完全照搬原博 多线程是多任务处理的一种特 ...

  10. PhoneGap本地将html打包成安卓App

    PhoneGap的在线打包有大小限制,超过30M的包无法在线打包.当然,可以把包里面的图片.声音文件去掉,然后打包.下载以后,解包,重新打包并签名.蛮麻烦的. 本地打包的简单方法如下: 下载安装Jav ...