同一位置周围多次出现边界框

时间:2019-12-04 23:27:18

标签: python opencv image-processing

我实现了以下代码,以使用裁剪后的小图像作为模板来匹配植物中的节点。

img_rgb = cv2.imread('Exp.2 - Florestópolis, 35DAE, 2017-2018, T4, R2, P4.jpg')
img_rgb = cv2.medianBlur(img_rgb, 7)

img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)

template_image = cv2.imread('TemplateNode.jpg',0)
template_image = cv2.medianBlur(template_image, 5)
width, height = template_image.shape[::-1]

res = cv2.matchTemplate(img_gray, template_image, cv2.TM_CCOEFF_NORMED)

threshold =  0.6

locations = np.where(res >= threshold)

for position_tuple in zip(*locations[::-1]):

        cv2.rectangle(img_rgb, position_tuple, (position_tuple[0] + width, position_tuple[1] + height), (0,255,0), 1)

但是,它在同一位置周围生成了太多的边界框(元组),如下所示:

Output Image from Template Matching

因此,有解决此问题的方法吗?

编辑:

Original Image

1 个答案:

答案 0 :(得分:1)

这是一种可能的方法。代码不太可能是一种有效的代码。我认为从某些软件包进行k均值聚类可能会更好。想法是将太近的位置分组在一起:

def group_locations(locations, min_radius):
    x = locations[:, 0][ : , None]
    dist_x = x - x.T
    y = locations[:, 1][ : , None]
    dist_y = y - y.T
    dist = np.sqrt(dist_x**2 + dist_y**2)
    np.fill_diagonal(dist, min_radius+1)
    too_close = np.nonzero(dist <= min_radius)
    groups = []
    points = np.arange(len(locations))
    i = 0
    j = 0
    while i < len(points):
        groups.append([points[i]])
        for j in range(len(too_close[0])):
            if too_close[0][j] == points[i]:
                groups[i].append(too_close[1][j])
                points = np.delete(points, np.nonzero(points == too_close[1][j]))
        i += 1

    new_locations = []
    for group in groups:
        new_locations.append(np.mean(locations[group], axis=0))

    return np.array(new_locations)

因此,在绘制之前,请先对位置进行分组并分组:

locations = []
size = 600
for _ in range(50):
    locations.append((random.randint(0, size), random.randint(0, size)))

locations = np.array(locations)
min_radius = 50

new_locations = group_locations(locations, min_radius)
#I run it second time as sometimes locations form chains which are longer than radius 
new_locations = group_locations(new_locations, min_radius) 
plt.scatter(locations[:, 0], locations[:, 1], c='blue', label='Original locations')
plt.scatter(new_locations[:, 0], new_locations[:, 1], c='red', marker='x', label='New grouped locations')
plt.legend()
plt.show()

enter image description here


使用提供的图片进行了实际的尝试

img_rgb = cv2.imread('obsvu.jpg')
img_rgb = cv2.medianBlur(img_rgb, 7)

img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)

template_image = cv2.imread('template.jpg',0)
template_image = cv2.medianBlur(template_image, 5)
width, height = template_image.shape[::-1]

res = cv2.matchTemplate(img_gray, template_image, cv2.TM_CCOEFF_NORMED)

threshold =  0.6

locations = np.where(res >= threshold)

new_locations = group_locations(np.array(locations).T, 50).T

for position_tuple in zip(*new_locations.astype(int)[::-1]):
        cv2.rectangle(img_rgb, position_tuple, (position_tuple[0] + width, position_tuple[1] + height), (0,255,0), 5)

原始位置:723个
新位置:6(是的,不是最好的模板选择)

result