目標檢測算法中規則矩形和不規則四邊形IOU的Python實現
交并比(Intersection-over-Union,IoU),目標檢測中使用的一個概念,我們在進行目標檢測算法測試時,重要的指標,是產生的預測框(candidate bound)與標記框(ground truth bound)的交疊率,即它們的交集與并集的比值。最理想情況是完全重疊,即比值為1。
通常,我們所說的目標檢測檢測的框是規則的矩形框,計算IOU也非常簡單,一般兩種方法:
- 兩個矩形的寬之和減去組合后的矩形的寬就是重疊矩形的寬,同比重疊矩形的高。
- 右下角的最小值減去左上角的最大值就是重疊矩形的寬,同比高。
上述規則四邊形(矩形)IOU計算方式一的 Python實現
- def calculate_regular_iou(rec1, rec2):
- """
- computing IoU
- :param rec1: (y0, x0, y1, x1), which reflects
- (top, left, bottom, right)
- :param rec2: (y0, x0, y1, x1)
- :return: scala value of IoU
- """
- S_rec1 = (rec1[2] - rec1[0]) * (rec1[3] - rec1[1])
- S_rec2 = (rec2[2] - rec2[0]) * (rec2[3] - rec2[1])
- sum_area = S_rec1 + S_rec2
-
- left_line = max(rec1[1], rec2[1])
- right_line = min(rec1[3], rec2[3])
- top_line = max(rec1[0], rec2[0])
- bottom_line = min(rec1[2], rec2[2])
-
- if left_line >= right_line or top_line >= bottom_line:
- return 0
- else:
- intersect = (right_line - left_line) * (bottom_line - top_line)
- return (intersect / (sum_area - intersect)) * 1.0
- if __name__ == '__main__':
- # (top, left, bottom, right)
- rect1 = [551, 26, 657, 45]
- rect2 = [552, 27, 672, 46]
- iou = calculate_regular_iou(rect1, rect2)
上述規則四邊形(矩形)IOU計算方式二的 Python 實現
- def compute_regular_iou_other(rec1, rec2):
- """
- computing IoU
- :param rec1: (y0, x0, y1, x1), which reflects
- (top, left, bottom, right)
- :param rec2: (y0, x0, y1, x1)
- :return: scala value of IoU
- """
- areas1 = (rec1[3] - rec1[1]) * (rec1[2] - rec1[0])
- areas2 = (rec2[3] - rec2[1]) * (rec2[2] - rec2[0])
-
- left = max(rec1[1],rec2[1])
-
- right = min(rec1[3],rec2[3])
-
- top = max(rec1[0], rec2[0])
-
- bottom = min(rec1[2], rec2[2])
-
- w = max(0, right - left)
- h = max(0, bottom - top)
-
- return w*h / (areas2 + areas1 - w*h)
-
- if __name__ == '__main__':
- # (top, left, bottom, right)
- rect1 = [551, 26, 657, 45]
- rect2 = [552, 27, 672, 46]
- iou = compute_regular_iou_other(rect1, rect2)
但是,對于不規則四邊形就不能通過上述這兩種方式來計算,這里可以使用Python的 Shapely 庫實現,Python 實現如下:
- import numpy as np
- import shapely
- from shapely.errors import TopologicalError
- from shapely.geometry import Polygon,MultiPoint
-
- def to_polygon(quadrilateral):
- """
-
- :param quadrilateral: 四邊形四個點坐標的一維數組表示,[x,y,x,y....]
- :return: 四邊形二維數組, Polygon四邊形對象
- """
- # 四邊形二維數組表示
- quadrilateral_array = np.array(quadrilateral).reshape(4, 2)
- # Polygon四邊形對象,會自動計算四個點,最后四個點順序為:左上 左下 右下 右上 左上
- quadrilateral_polygon = Polygon(quadrilateral_array).convex_hull
-
- return quadrilateral_array, quadrilateral_polygon
-
- def calculate_iou(actual_quadrilateral, predict_quadrilateral):
- """
-
- :param actual_quadrilateral: 預測四邊形四個點坐標的一維數組表示,[x,y,x,y....]
- :param predict_quadrilateral: 期望四邊形四個點坐標的一維數組表示,[x,y,x,y....]
- :return:
- """
- # 預測四邊形二維數組, 預測四邊形 Polygon 對象
- actual_quadrilateral_array, actual_quadrilateral_polygon = to_polygon(actual_quadrilateral)
- # 期望四邊形二維數組, 期望四邊形 Polygon 對象
- predict_quadrilateral_array, predict_quadrilateral_polygon = to_polygon(predict_quadrilateral)
-
- # 合并兩個box坐標,變為8*2 便于后面計算并集面積
- union_poly = np.concatenate((actual_quadrilateral_array, predict_quadrilateral_array))
- # 兩兩四邊形是否存在交集
- inter_status = actual_quadrilateral_polygon.intersects(predict_quadrilateral_polygon)
- # 如果兩四邊形相交,則進iou計算
- if inter_status:
- try:
- # 交集面積
- inter_area = actual_quadrilateral_polygon.intersection(predict_quadrilateral_polygon).area
- # 并集面積 計算方式一
- #union_area = poly1.area + poly2.area - inter_area
- # 并集面積 計算方式二
- union_area = MultiPoint(union_poly).convex_hull.area
- # 若并集面積等于0,則iou = 0
- if union_area == 0:
- iou = 0
- else:
- # 第一種計算的是: 交集部分/包含兩個四邊形最小多邊形的面積
- iou = float(inter_area) / union_area
- # 第二種: 交集 / 并集(常見矩形框IOU計算方式)
- # iou=float(inter_area) /(poly1.area+poly2.area-inter_area)
- except shapely.errors.TopologicalError :
- print('shapely.errors.TopologicalError occured, iou set to 0')
- iou = 0
- else:
- iou = 0
-
- return iou
-
- if __name__ == '__main__':
- actual_quadrilateral = [908, 215, 934, 312, 752, 355, 728, 252]
- predict_quadrilateral = [923, 308, 758, 342, 741, 262, 907, 228]
- iou = calculate_iou(actual_quadrilateral, predict_quadrilateral)
- print(iou)
避坑指南
運行代碼拋出 WinError 126 錯誤
在使用Python中的使用 import shapely 時不會報錯,但是在使用 from shapely.geometry import Polygon,MultiPoint 會報錯,報錯的詳細信息如下圖:

報錯的主要原因就出現在 geos_c.dll 這里,看了網上很多文章大部分說是由于 geos_c.dll 文件缺失導致報錯。嘗試在網上找了幾個 geos_c.dll 文件放到 C:\Windows\System32 下仍然沒有解決問題。

最終解決方案:通過 pip uninstall Shapely 卸載原來安裝的 Shapely 然后 在 https://www.lfd.uci.edu/~gohlke/pythonlibs/#shapely,如上圖,這里下載對應版本的whl文件安裝,安裝這個whl 就可以解決該問題。
whl文件下載404錯誤
在 https://www.lfd.uci.edu/~gohlke/pythonlibs/#shapely 下載制定版本的whl時,出現404錯誤。如下。

此時改用 chrome 瀏覽器重新嘗試下載,即可解決。