计算公式:
已知: b o x 1 = ( w 1 , h 1 ) \mathbf{box_1} = (w_1, h_1) box1=(w1,h1), b o x 2 = ( w 2 , h 2 ) \mathbf{box_2} = (w_2, h_2) box2=(w2,h2)
b o x 1 \mathbf{box_1} box1 和 b o x 2 \mathbf{box_2} box2 的交并比:
J ( b 1 , b 2 ) = min ( w 1 , w 2 ) ⋅ min ( h 1 , h 2 ) w 1 h 1 + w 2 h 2 − min ( w 1 , w 2 ) ⋅ min ( h 1 , h 2 ) J(\mathbf{b_1}, \mathbf{b_2}) = \frac{\text{min}(w_1, w_2)\cdot\text{min}(h_1, h_2)}{w_1h_1 + w_2h_2 - \text{min}(w_1, w_2)\cdot\text{min}(h_1, h_2)} J(b1,b2)=w1h1+w2h2−min(w1,w2)⋅min(h1,h2)min(w1,w2)⋅min(h1,h2)
YOLOv2中不使用欧式距离,使用如下公式来计算两个框的距离
d J ( b 1 , b 2 ) = 1 − J ( b 1 , b 2 ) d_J(\mathbf{b_1}, \mathbf{b_2}) = 1 - J(\mathbf{b_1}, \mathbf{b_2}) dJ(b1,b2)=1−J(b1,b2)
python实现
import numpy as np
# 计算质心和其他boxes的距离
def iou(box, clusters):
x = np.minimum(clusters[:, 0], box[0])
y = np.minimum(clusters[:, 1], box[1])
intersection = x * y
box_area = box[0] * box[1]
cluster_area = clusters[:, 0] * clusters[:, 1]
iou_ = intersection / (box_area + cluster_area - intersection)
return iou_
def kmeans(boxes, k, dist=np.median):
rows = boxes.shape[0]
# rows行k列,每行对应一个boxes,每列是boxes与各个质心的距离
distances = np.empty((rows, k))
#
last_clusters = np.zeros((rows,))
np.random.seed()
# 在boxes中随机选取k个作为质心clusters
clusters = boxes[np.random.choice(rows, k, replace=False)]
while True:
for row in range(rows):
distances[row] = 1 - iou(boxes[row], clusters)
# 找到与boxes距离最近的clusters的索引
nearest_clusters = np.argmin(distances, axis=1)
# 当两次聚类结果相同时结束
if (last_clusters == nearest_clusters).all():
break
# 分别取w和h的平均值更新clusters
for cluster in range(k):
clusters[cluster] = dist(boxes[nearest_clusters == cluster], axis=0)
last_clusters = nearest_clusters
return clusters
参考:
https://lars76.github.io/object-detection/k-means-anchor-boxes/#