【问题标题】:How to get an expanded or contracted contour in OpenCV?如何在 OpenCV 中获得扩展或收缩的轮廓?
【发布时间】:2019-08-17 20:22:43
【问题描述】:

是否可以获得轮廓的扩展或收缩版本?

例如在下图中,我在二值图像上使用了 cv::findContour() 和 cv::drawContour 来获取轮廓:

我想绘制另一个与原始轮廓有自定义像素距离的轮廓,如下所示:

除了腐蚀,我​​认为这可能不是一个好主意,因为使用腐蚀似乎很难控制像素距离,我不知道如何解决这个问题。我可以知道正确的方向吗?

【问题讨论】:

  • 您可以使用 cv::dilate() 和 cv::erode() 然后再次检测轮廓。
  • 初始轮廓有多大?生成的轮廓在多大程度上反映了原始轮廓的形状?这两个问题将决定解决方案的复杂程度。我同意,cv::dilatecv::erode 将在一定程度上(或细节)完成这项工作。超精细的解决方案将包含诸如找到质心,将原始轮廓的x, y 坐标投影到正确的方向,并为得到的轮廓确定新的x, y 坐标,因此需要进行大量的插值和外插,我假设。

标签: c++ opencv contour opencv-contour opencv-drawcontour


【解决方案1】:

使用带有小内核和多次迭代的 cv::erode 可能足以满足您的需求,即使它并不准确。

C++ 代码:

cv::Mat img = ...;
int iterations = 10;
cv::erode(img, img,
   cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3,3)),
   cv::Point(-1,-1),
   iterations);

演示:

# img is the image containing the original black contour
for form in [cv.MORPH_RECT, cv.MORPH_CROSS]:
    eroded = cv.erode(img, cv.getStructuringElement(form, (3,3)), iterations=10)
    contours, hierarchy = cv.findContours(~eroded, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
    vis = cv.cvtColor(img, cv.COLOR_GRAY2BGR)
    cv.drawContours(vis, contours, 0, (0,0,255))
    cv.drawContours(vis, contours, 1, (255,0,0))
    show_image(vis)

使用 cv.MORPH_RECT 和 3x3 内核进行 10 次迭代:

使用 cv.MORPH_CROSS 和 3x3 内核进行 10 次迭代:

您可以通过调整迭代次数来改变偏移量。

更准确的方法是使用 cv::distanceTransform 查找距离轮廓大约 10px 的所有像素:

dist = cv.distanceTransform(img, cv.DIST_L2, cv.DIST_MASK_PRECISE)
ring = cv.inRange(dist, 9.5, 10.5) # take all pixels at distance between 9.5px and 10.5px
show_image(ring)
contours, hierarchy = cv.findContours(ring, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)

vis = cv.cvtColor(img, cv.COLOR_GRAY2BGR)
cv.drawContours(vis, contours, 0, (0,0,255))
cv.drawContours(vis, contours, 2, (255,0,0))
show_image(vis)

您将在原始轮廓的每一侧得到两个轮廓。使用带有 RETR_EXTERNAL 的 findContours 仅恢复外轮廓。要恢复内部轮廓,请使用 RETR_LIST

【讨论】:

    【解决方案2】:

    我认为解决方案可以更简单,无需膨胀和新轮廓。

    1. 对于每个轮廓搜索质心:cv::moments(contours[i]) -> cv::Point2f mc(mu.m10 / mu.m00), mu.m01 / mu.m00));

    2. 对于轮廓的每个点:对质心进行移位 -> 乘以系数 K -> 向后移位:pt_new = (k * (pt - mc) + mc);

    但是系数 k 对于每个点必须是单独的。稍后我会计算一下...

    【讨论】:

      猜你喜欢
      • 2012-10-26
      • 1970-01-01
      • 2013-08-23
      • 2022-01-10
      • 2019-09-20
      • 2021-09-07
      • 1970-01-01
      • 2016-09-25
      • 2013-04-06
      相关资源
      最近更新 更多