我工作的计算机视觉问题,其中一个步骤的问题是寻找到的对象接近彼此的位置。例如,在下面我找到标记为灰色的区域有趣在图像中。
输入:
输出:
我目前的做法是通过侵蚀第一反转图像,其次是形态梯度跟随,然后删除一些不感兴趣的轮廓。脚本如下:
img = cv2.imread('mask.jpg', 0)
img = (255 - img)
kernel = np.ones((11,11), np.uint8)
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
kernel = np.ones((5,5), np.uint8)
img_erosion = cv2.erode(gradient, kernel, iterations=3)
img_erosion[img_erosion > 200] = 255
img_erosion[img_erosion <= 200] = 0
def get_contours(mask):
contours, hierarchy = cv2.findContours(mask,cv2.RETR_TREE,cv2.cv2.CHAIN_APPROX_NONE)
return contours
cnts = get_contours(img_erosion)
img_new = np.zeros_like(img_erosion)
img_h, img_w = img_erosion.shape
for i in cnts:
if cv2.contourArea(i) > 30:
print(cv2.boundingRect(i), cv2.contourArea(i))
x, y, h, w = cv2.boundingRect(i)
if h/w > 5 or w/h > 5 or cv2.contourArea(i) > 100: ## Should be elongated
if (x - 10 > 0) and (y - 10 > 0): ## Check if near top or left edge
if (img_w - x > 10) and (img_h - y > 10): ## Check if near bottom or right edge
cv2.drawContours(img_new, [i], -1, (255,255,255), 2)
kernel = np.ones((3,3), np.uint8)
img_new = cv2.dilate(img_new, kernel, iterations=2)
plt.figure(figsize=(6,6))
plt.imshow(img_new)
结果是:
但是,使用这种方法,我需要调整很多参数,而且它在很多情况下失败时的方向是不同的或边缘稍微远,或“L”形的边缘等
我是新来的图像处理,还有没有其他的方法,可以帮助我有效地解决这个任务?
编辑:一些附加更多图片
(多为长方形的多边形,但很多的尺寸和相对位置的变化)
对可能做到这一点的最好办法是通过Stroke Width Transform。这是不是在OpenCV的,但它是在几个其他图书馆,你可以找到一些实现浮在互联网。笔划宽度变换找到了针对图像中的每个像素最接近的边缘之间的最小宽度。请参阅从纸如下图所示:
阈值此图像,然后告诉你那里有一些小的距离分开边缘。例如,所有的值<40的像素,也就是说,是由小于40个像素分离边缘的两个之间。
所以,这可能正是清楚,这是非常接近你想要的答案。会有一些额外的噪音在这里,像你这样想也碰到一些方形脊上你的形状...的边缘,你不得不过滤掉或平滑(之间的值轮廓逼近将是一个简单的方法来清理它们作为预处理步骤,例如)。
然而,当我有一个原型SWT编程,这不是一个很好的实现了,我还没有真正测试过它(居然忘了几个月.......也许一年),所以我”不打算把它现在不在。但是,我有另一个想法就是有点简单,没有必要阅读的研究论文。
你在你的输入图像的多个斑点。试想一下,如果你在自己的图像分别有各一个,并通过你不过多的距离你愿意它们之间把长大每个斑。如果你从小每个斑的说10个像素,它们重叠,那么他们会在彼此的20个像素。然而,这并没有给我们的完全重叠区域,只需两个扩展斑点重叠的地方部分。测量此不同的,但是类似的方式是,如果斑点增长了10个像素,并重叠,进而重叠原斑点他们被膨胀之前,则这两个斑点是在彼此的10个像素。我们将使用第二个定义,以寻找附近的斑点。
def find_connection_paths(binimg, distance):
h, w = binimg.shape[:2]
overlap = np.zeros((h, w), dtype=np.int32)
overlap_mask = np.zeros((h, w), dtype=np.uint8)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (distance, distance))
# grows the blobs by `distance` and sums to get overlaps
nlabels, labeled = cv2.connectedComponents(binimg, connectivity=8)
for label in range(1, nlabels):
mask = 255 * np.uint8(labeled == label)
overlap += cv2.dilate(mask, kernel, iterations=1) // 255
overlap = np.uint8(overlap > 1)
# for each overlap, does the overlap touch the original blob?
noverlaps, overlap_components = cv2.connectedComponents(overlap, connectivity=8)
for label in range(1, noverlaps):
mask = 255 * np.uint8(overlap_components == label)
if np.any(cv2.bitwise_and(binimg, mask)):
overlap_mask = cv2.bitwise_or(overlap_mask, mask)
return overlap_mask
现在的产量是不完美的---当我扩大了斑点,我扩大了他们向外用圆(扩张内核),所以连接区域不完全超清晰。然而,这是为了确保它会在任何方向的事情工作的最佳途径。你可能会筛选了这一点/剪辑下来。一个简单的方法来做到这一点会得到各连接件(图中蓝色),并反复侵蚀下来的象素,直到它不重叠原斑点。其实OK,让我们补充一点:
def find_connection_paths(binimg, distance):
h, w = binimg.shape[:2]
overlap = np.zeros((h, w), dtype=np.int32)
overlap_mask = np.zeros((h, w), dtype=np.uint8)
overlap_min_mask = np.zeros((h, w), dtype=np.uint8)
kernel_dilate = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (distance, distance))
# grows the blobs by `distance` and sums to get overlaps
nlabels, labeled = cv2.connectedComponents(binimg)
for label in range(1, nlabels):
mask = 255 * np.uint8(labeled == label)
overlap += cv2.dilate(mask, kernel_dilate, iterations=1) // 255
overlap = np.uint8(overlap > 1)
# for each overlap, does the overlap touch the original blob?
noverlaps, overlap_components = cv2.connectedComponents(overlap)
for label in range(1, noverlaps):
mask = 255 * np.uint8(overlap_components == label)
if np.any(cv2.bitwise_and(binimg, mask)):
overlap_mask = cv2.bitwise_or(overlap_mask, mask)
# for each overlap, shrink until it doesn't touch the original blob
kernel_erode = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
noverlaps, overlap_components = cv2.connectedComponents(overlap_mask)
for label in range(1, noverlaps):
mask = 255 * np.uint8(overlap_components == label)
while np.any(cv2.bitwise_and(binimg, mask)):
mask = cv2.erode(mask, kernel_erode, iterations=1)
overlap_min_mask = cv2.bitwise_or(overlap_min_mask, mask)
return overlap_min_mask
当然,如果你还是想他们大一点或小,你可以做任何你与他们喜欢,但这个看起来相当接近您所要求的输出,所以我会离开它。另外,如果你想知道,我不知道在哪里右上方的斑点去了。我可以在以后的另一次传递,在这最后一块。需要注意的是最后两个步骤可以合并;检查是否有重叠,如果是,酷---收缩下来,并把它存储在面具。