➣ Reading Time: 11 minutes

前言

在機器學習的領域中,我們很常會需要用到 iou 的計算,
iou 全名為 intersection over union,
能替兩張圖形重疊的範圍提供一個參考分數,是一個相對具有參考意義的值。
本篇文章中也提供範例程式碼,
另外也發現網路上查到的作法有很多類似的常見錯誤,一並分享在此文當中。
因為我自己也很常用XD,不時就會回來拿這段 function 去實作。

iou 的概念與公式

iou 基本上 = 兩矩形的交集 / 兩矩形的聯集

所以:

  • 完全重合時:得到最大值 1
  • 完全不重合時:得到最小值 0
  • 部分重合:得到 0~1 範圍的值

以下為圖解

iou

  • 圖片引用自:https://blog.csdn.net/IAMoldpan/article/details/78799857

用 C++ 實作計算 iou 的 function – 網路常見「錯誤」示範

iou – 常見「錯誤」範例程式碼

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;
using namespace std;


int main()
{
  Rect bbox_1(10, 20, 30, 40);
  Rect bbox_2(20, 30, 40, 50);

  Rect bbox_and;
  bbox_and = bbox_1 & bbox_2;

  Rect bbox_or;
  bbox_or = bbox_1 | bbox_2;

  cout<< "bbox_and.area() = " << bbox_and.area() << endl;
  cout<< "bbox_or.area() = " << bbox_or.area() << endl;

  cout<< "iou = " << (bbox_and.area()*1.0 / bbox_or.area()) << endl;

  return 0;
}

編譯與結果

> g++ iou.cpp -o iou.out -std=c++11 `pkg-config --cflags opencv`; ./iou.out

bbox_and.area() = 600
bbox_or.area() = 3000
iou = 0.2

「正確」實驗結果分析

看下圖,我們可以大概知道圖形的分布

iou-1

  • 首先是紅框 (bbox_1),面積為 30*40=1200
  • 再來是綠框 (bbox_2),面積為 40*50=2000
  • 紅綠框交疊部分 ,面積為 (40-20)*(60-30)=600
  • 紅綠框聯集,面積為 1200+2000-600 = 2600 (兩個相加後,扣掉重複部分)

得到結果 600/2600 = 0.23076923076 (就是我們上面最後印出來的結果囉!)

所以上面的程式問題出在哪?

網路上常見做 iou 算法的錯誤是出在計算「兩個矩形的聯集」的部份,
如上面的程式碼,使用了「bbox_1 | bbox_2」,
這就是關鍵問題所在,「Rectangle OR」計算出的結果是「最大範圍的 Rectangle」,
用下圖來說,我們其實算出的是「藍色的部份」

「Rectangle OR」算出的「藍色的部份 Rectangle」,
並非我們要的「聯集」,請見最上面的定義。

這就是網路上常見的「錯誤計算 iou 程式碼」。

用 C++ 實作計算 iou 的 function – 「正確」示範

iou – 「正確」範例程式碼

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;
using namespace std;


int main()
{
  Rect bbox_1(10, 20, 30, 40);
  Rect bbox_2(20, 30, 40, 50);

  Rect bbox_and;
  bbox_and = bbox_1 & bbox_2;

  float bbox_or = bbox_1.area() + bbox_2.area() - bbox_and.area();

  cout<< "bbox_and.area() = " << bbox_and.area() << endl;
  cout<< "bbox_or.area() = " << bbox_or << endl;

  cout<< "iou = " << (bbox_and.area()*1.0 / bbox_or) << endl;

  return 0;
}

可以注意我們只有改寫「聯集」的地方,將他改寫成正確的算法。
這樣計算出來才是正確的。

編譯與結果

> g++ iou.cpp -o iou.out -std=c++11 `pkg-config --cflags opencv`; ./iou.out

bbox_and.area() = 600
bbox_or.area() = 2600
iou = 0.230769

我們得到了正確的 iou 結果。

想看 python 計算 iou 方法,可見我的另外一篇文

Reference

https://www.cnblogs.com/lfri/p/10498876.html
https://my.oschina.net/u/3800567/blog/1795889
https://blog.csdn.net/weixin_34195546/article/details/92412045

⭐C++ 基礎用法 相關文章整理⭐:
1.【C++】C++ compile 程式碼 使用 c++ 11 與使用相關的 package
2.【C++】C/C++ 顯示資料的類別 (type) sample code (內含範例程式碼) print C data type, cout C++ data type, get variable type in c++
3.【C++】C++ 複製 2D array的方法 copy 2d array memcpy sample code (內含範例程式碼)
⭐C++ 字串處理相關文章整理⭐:
1.【C++】字串 char string stringstream 相關用法總整理 (內含範例程式碼) 與利用 sprinf, snprinf assign 值的方法
2.【C++】字串 char string stringstream 「轉換」用法總整理 (內含範例程式碼)
3.【C】printf, fprintf, sprintf, snprintf 相關用法總整理 (內含範例程式碼)
4.【C++】C++ String 用法 連接兩個 String c++ string concat
⭐C++ 系統偵測相關文章整理⭐:
1.【C++】C++ 利用 dirent.h 計算資料夾的檔案數量 count files sample code (內含範例程式碼)
2.【C++】C++ inotify sample code 偵測指定路徑底下的文件變化 (內有範例程式碼)
⭐C++ OpenCV 相關文章整理⭐:
1.【OpenCV】c++ OpenCV – 在 ubuntu 上第一次執行 OpenCV 程式 sample code (內含範例程式碼)
2.【OpenCV】c++ OpenCV - 在圖片上寫上文字 cv::putText sample code (內含範例程式碼)
3.【OpenCV】c++ OpenCV - cv::Rect 矩形用法與相關功能函數 sample code (內含範例程式碼)
4.【OpenCV】c++ OpenCV - OpenCV 中的純量 定義顏色 cv::Scalar(255,255,255) color sample code (內含範例程式碼)
5.【OpenCV】用 C++ 計算 iou 的方法 與網路算法常見錯誤(內附範例程式碼) sample code
⭐【喜歡我的文章嗎? 幫忙按讚除了鼓勵外,我也會將部分所得捐出!
如果喜歡我的文章,請幫我在下方【按五下Like】 (Google, Facebook 免費註冊),會由 「LikeCoin」 贊助作者鼓勵繼續創作,扣除掉網站本身經營的成本 (可惜目前還是虧本的),我會將 【50% 收益全部捐出】 並公開發文,讀者們「只需幫忙按讚,完全不用出錢」哦!

likecoin-steps