简介
在计算机视觉领域, 工程师们经常会用到某些特定的“”功能”。因为这些功能的存在, 大家只需编写寥寥几行代码, 就能够检测出轮廓或者对应的对象。不过, 需要注意的是, 通过这种方法检测出来的轮廓, 往往呈现出一种分散的状态。
举例来说, 一张内容丰富且包含较多细节的图片, 可能会生成成百上千个轮廓, 但千万不要以为这意味着图片里真的存在那么多独立的对象。有些情况下, 同一个对象会对应多个独立的轮廓线, 所以我们想做的, 就是把这些零散的轮廓给凑到一块儿去。这么一处理呢,就能使得一个单独的轮廓, 刚好就代表着那一个对象了。
实现思路
当我的项目中碰到了这个麻烦的时候, 我花了不少功夫去试着用别的参数或者换其他的函数来看能不能找出轮廓线出来, 可惜试了一遍又一个, 没有一个是管用的。后来, 我又做了不少调查研究工作, 最终在那一个叫的那个论坛上, 还真就让我看到了一篇帖子, 里面说到了什么叫做凝聚聚类这么一回事。
不过, 这篇帖子上面并没有把源代码给贴出来供人参考。我也确实还发现了好像有个地方是支持那个聚合聚类的算法的, 但是我最后决定还是别去用它了, 原因有两个方面需要考虑进去嘛:
就我个人的感觉而言, 这个功能实际上显得有些过于复杂了。我根本不清楚该如何去输入那些正确的参数, 同时我也一直在怀疑, 关于轮廓检测所得出的数据类型, 到底是不是能够直接适配到这样一个函数里面去使用的状态之中。
在具体的版本要求方面, 我必须得要去使用版本号是2.7的那个系统, 还需要用到版本号是3.3.1的某种环境支持, 另外也得把Numpy的库升级到1.11.3这个特定的版本才行。
可是目前这种状况下, 它跟我们现有的版本(也就是0.20+)之间完全是对不兼容的, 因为后面提到的那个更高版本的软件环境, 恰恰才是真正能够支持聚类算法运作的那一个版本选项。
源代码
为了向大家分享我自己编写的这个函数, 我将它进行了开源操作。同时, 我会把相关内容作为要点发布在下面部分。这个特定的版本是用来适配某个环境的。
如果你需要在“.7”这个环境当中使用它的话, 那么你只需要进行一个简单的替换动作就可以搞定了。具体来说, 就是要把代码里的“range”这个词给更换掉, 把它替换成空白的内容, 或者说替换为对应的占位符。
#!/usr/bin/env python3
import os
import cv2
import numpy
def calculate_contour_distance(contour1, contour2):
x1, y1, w1, h1 = cv2.boundingRect(contour1)
c_x1 = x1 + w1/2
c_y1 = y1 + h1/2
x2, y2, w2, h2 = cv2.boundingRect(contour2)
c_x2 = x2 + w2/2
c_y2 = y2 + h2/2
return max(abs(c_x1 - c_x2) - (w1 + w2)/2, abs(c_y1 - c_y2) - (h1 + h2)/2)
def merge_contours(contour1, contour2):
return numpy.concatenate((contour1, contour2), axis=0)
def agglomerative_cluster(contours, threshold_distance=40.0):
current_contours = contours
while len(current_contours) > 1:
min_distance = None
min_coordinate = None
for x in range(len(current_contours)-1):
for y in range(x+1, len(current_contours)):
distance = calculate_contour_distance(current_contours[x], current_contours[y])
if min_distance is None:
min_distance = distance
min_coordinate = (x, y)
elif distance < min_distance:
min_distance = distance
min_coordinate = (x, y)
if min_distance < threshold_distance:
index1, index2 = min_coordinate
current_contours[index1] = merge_contours(current_contours[index1], current_contours[index2])
del current_contours[index2]
else:
break
return current_contours
注意:
结果
如果想要查看集群处理之后的效果, 那么请看下面提供的这两幅图像。第一张图片展示的是在最开始的时候, 一共检测出了12个轮廓。而在进行了聚类操作之后, 这些轮廓的数量就减少了, 具体只剩下4个轮廓了, 这一点可以从第二张图像中看出来。
在这两幅图对应的场景中, 其中有两个很小的物体, 它们是因为受到噪声干扰才出现的。这两个小物体并没有与其他的物体合并到一起, 造成这种现象的原因是它们之间的距离太远了, 相比之下, 这个距离是超过了预设的阈值距离的。