【问题标题】:Overlapping contours重叠轮廓
【发布时间】:2020-03-07 18:33:41
【问题描述】:

我正在尝试在图像上绘制多个轮廓,到目前为止,我已经设法通过应用不同的阈值来绘制轮廓。唯一的问题是大多数轮廓区域是重叠的,我被困在这里如何处理它。我理想情况下想要的是,只要有重叠,它就应该将轮廓分成单独的区域。例如,在Conceptual image 中有 4 个区域(轮廓)橙色、绿色、蓝色和黑色。每当有重叠时,它应该分成紫色区域。这似乎很棘手,我什至不确定这是否可能。如果没有,我希望所有重叠合并。任何人都可以帮助解决这个问题吗? Sample image

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
im = cv.imread('images/sample.jpg')
imgray = cv.cvtColor(im, cv.COLOR_BGR2GRAY)
ret1, thresh1 = cv.threshold(imgray, 30, 80, 0)
ret2, thresh2 = cv.threshold(imgray, 80, 110, 0)
ret3, thresh3 = cv.threshold(imgray, 110, 150, 0)
ret4, thresh4 = cv.threshold(imgray, 150, 200, 0)
ret5, thresh5 = cv.threshold(imgray, 200, 255, 0)
_,contours1, hierarchy1 = cv.findContours(thresh1, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
_,contours2, hierarchy2 = cv2.findContours(thresh2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
_,contours3, hierarchy3 = cv2.findContours(thresh3,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
_,contours4, hierarchy4 = cv2.findContours(thresh4,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
_,contours5, hierarchy5 = cv2.findContours(thresh5,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)



cv2.drawContours(im, contours1, -1, (0, 0, 255), 1)
cv2.drawContours(im, contours2, -1, (0, 255, 0), 1)
cv2.drawContours(im, contours3, -1, (0, 0, 255), 1)
cv2.drawContours(im, contours4, -1, (10, 200, 200), 1)
cv2.drawContours(im, contours5, -1, (255, 255, 0), 1)

cv2.imshow("im",im)
cv2.waitKey(0)

【问题讨论】:

  • 这是您的实际输入图像,还是只是一些可视化?如果是后者,请发布实际的输入图像。一种昂贵的方法是在单独的蒙版上绘制填充的轮廓,并为每两个轮廓计算交点并找到它的轮廓。正如我所说,这会很昂贵,但我认为会给出准确的结果。
  • @HansHirse 这只是一个概念图像,用于理解问题。我已附上示例图片。
  • @HansHirse 如果我们说 10 个重叠的轮廓,那么找到这些区域需要大量的计算时间。还有其他方法吗?
  • 不一定。我想,这种方法会占用大量内存,但计算量不会那么大,因为单个操作非常基础。

标签: python numpy opencv image-processing contour


【解决方案1】:

如前所述,从轮廓生成蒙版,然后计算成对交点以及原始蒙版中的“独占”部分,肯定会为您提供所需的区域,但这种方法往往会很昂贵也是。从您的示例图像和代码中,我无法弄清楚您真正想要做什么,所以我坚持使用一些非常基本的示例来说明这种方法。

import cv2
import numpy as np
from matplotlib import pyplot as plt

# Generate some dummy images, whose (main) contours overlap
img1 = cv2.circle(np.zeros((400, 400, 3), np.uint8), (150, 150), 100, (0, 255, 0), cv2.FILLED)
img2 = cv2.rectangle(np.zeros((400, 400, 3), np.uint8), (175, 175), (325, 325), (0, 0, 255), cv2.FILLED)

# Find contours (OpenCV 4.x)
contours1, _ = cv2.findContours(cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
contours2, _ = cv2.findContours(cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

# Find contours (OpenCV 3.x)
#_, contours1, _ = cv2.findContours(cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
#_, contours2, _ = cv2.findContours(cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

# Generate masks of (main) contours; Attention: Hard-coded selection of first contour here!
mask1 = cv2.drawContours(np.zeros((400, 400), np.uint8), [contours1[0]], -1, 255, cv2.FILLED)
mask2 = cv2.drawContours(np.zeros((400, 400), np.uint8), [contours2[0]], -1, 255, cv2.FILLED)

# Find intersection of both masks
mask_combined = cv2.bitwise_and(mask1, mask2)

# Generate "exclusive" masks, i.e. masks without the intersection parts
mask1_excl = cv2.bitwise_xor(mask1, mask_combined)
mask2_excl = cv2.bitwise_xor(mask2, mask_combined)

# Visualization
plt.figure()
plt.subplot(3, 3, 1), plt.imshow(img1), plt.ylabel('img1')
plt.subplot(3, 3, 2), plt.imshow(img2), plt.ylabel('img2')
plt.subplot(3, 3, 3), plt.imshow(img1 + img2), plt.ylabel('img1 + img2')
plt.subplot(3, 3, 4), plt.imshow(mask1, cmap='gray'), plt.ylabel('mask1')
plt.subplot(3, 3, 5), plt.imshow(mask2, cmap='gray'), plt.ylabel('mask2')
plt.subplot(3, 3, 6), plt.imshow(mask_combined, cmap='gray'), plt.ylabel('mask_combined')
plt.subplot(3, 3, 7), plt.imshow(mask1_excl, cmap='gray'), plt.ylabel('mask1_excl')
plt.subplot(3, 3, 8), plt.imshow(mask2_excl, cmap='gray'), plt.ylabel('mask2_excl')
plt.subplot(3, 3, 9), plt.imshow(mask_combined, cmap='gray'), plt.ylabel('mask_combined')
plt.show()

可视化:

现在,必须对每个轮廓元组执行此操作 - 不仅是对,因为您可以有三个或更多轮廓的交集。跟踪所有这些生成的掩码等很可能是内存密集型的,但计算量不会那么大。最后,所有方法都需要以某种方式将生成的区域存储为某种掩码。

希望有帮助!

【讨论】:

  • 它看起来很神奇,但我想要实现的是它应该在最后一张图中生成 3 个区域。一个圆形(没有相交区域),一个正方形(相交区域)和一个相交区域。每个都应该有一个边界来区分它们是单独的区域
  • 并且“每个轮廓元组-不仅是对”是指每个可能的组合,例如轮廓 1 与轮廓 2、3、4、5,然后轮廓 2 与 3、4、5 等等?
  • @Happy 更多:c1 仅与 c2 组合,仅与 c3 组合,等等。然后,c1c2c3 组合,c1c3c4 组合,等等。这意味着,对于 k = 2, ..., n,您需要所有 k 组合而不重复。
  • 那么对于每个组合,我们是否需要对相同的程序进行硬编码?
  • @Happy (a) 您将所有轮廓存储在一个列表中。 (b) 你计算所有可能的k-组合对于k = 2, ..., n,并将它们存储在另一个列表中。 (例如:对于n = 3,您将得到[[1, 2], [1, 3], [2, 3], [1, 2, 3]) (c) 您迭代组合列表,并选择与包含的索引对应的所有轮廓,并如上所述生成交点和排他掩码。所有这些都可以使用循环和其他东西来完成,你不需要硬编码任何东西。但是,事实上,这仍然是很多工作,但进一步,个人帮助超出了 Stack Overflow 的范围。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-15
  • 1970-01-01
  • 2022-07-12
  • 1970-01-01
相关资源
最近更新 更多