【问题标题】:OpenCV - How to use floodFill with RGB image?OpenCV - 如何使用 FloodFill 和 RGB 图像?
【发布时间】:2020-05-28 13:28:19
【问题描述】:

我正在尝试在如下图像上使用floodFill 来提取天空:

但即使我设置了loDiff=Scalar(0,0,0)upDiff=Scalar(255,255,255),结果也只是显示种子点并且不会变大(绿点):

代码:

Mat flood;
Point seed = Point(180, 80);
flood = imread("D:/Project/data/1.jpeg");
cv::floodFill(flood, seed, Scalar(0, 0, 255), NULL, Scalar(0, 0, 0), Scalar(255, 255, 255));
circle(flood, seed, 2, Scalar(0, 255, 0), CV_FILLED, CV_AA);

这是结果(红点是种子):

如何设置功能以获得更大的区域(如整个天空)?

【问题讨论】:

  • @DanMašek 根据dcoumentation,我认为Scalar(0,0,255) 是结果值。如果您能看到红点,我在问题中添加了结果。
  • 是的,你是对的。我的错。
  • 查看文档中的公式。有src(x',y') - loDiff 来获得下限。您将loDiff 设置为0,因此它只考虑比源更亮的颜色。将Scalar(0, 0, 0) 更改为所有 255,看看会发生什么。
  • @DanMašek 谢谢!我误解了 loDiff 的定义。当我设置loDiff=Scalar(5,5,5) 时,它会分隔天空。

标签: python c++ opencv image-processing flood-fill


【解决方案1】:

您需要正确设置loDiffupDiff 参数。

floodFill documentation

loDiff - 当前观察到的像素与其属于该组件的相邻像素之一或添加到该组件的种子像素之间的最大较低亮度/色差。
upDiff – 当前观察到的像素与其属于该组件的相邻像素之一或添加到该组件的种子像素之间的最大亮度/色差。

这是一个 Python 代码示例:

import cv2
flood = cv2.imread("1.jpeg");

seed = (180, 80)

cv2.floodFill(flood, None, seedPoint=seed, newVal=(0, 0, 255), loDiff=(5, 5, 5, 5), upDiff=(5, 5, 5, 5))
cv2.circle(flood, seed, 2, (0, 255, 0), cv2.FILLED, cv2.LINE_AA);

cv2.imshow('flood', flood)
cv2.waitKey(0)
cv2.destroyAllWindows()

结果:

【讨论】:

    【解决方案2】:

    如果您希望填充的轮廓尽可能接近图像中的对比元素,您可以做的另一件事是执行 Kmeans 颜色量化以将图像分割成指定数量的簇。由于天空和山/树有明显的色差,我们可以将图像分割成三种颜色,这样可以更好地分离物体。

    例如clusters=3:

    输入图像->Kmeans颜色分割

    填土结果为绿色

    请注意,分割后,只有三种颜色定义了图像。这样,填埋场将更好地沿着山脉/树木轮廓

    代码

    import cv2
    import numpy as np
    
    # Kmeans color segmentation
    def kmeans_color_quantization(image, clusters=8, rounds=1):
        h, w = image.shape[:2]
        samples = np.zeros([h*w,3], dtype=np.float32)
        count = 0
    
        for x in range(h):
            for y in range(w):
                samples[count] = image[x][y]
                count += 1
    
        compactness, labels, centers = cv2.kmeans(samples,
                clusters, 
                None,
                (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10000, 0.0001), 
                rounds, 
                cv2.KMEANS_RANDOM_CENTERS)
    
        centers = np.uint8(centers)
        res = centers[labels.flatten()]
        return res.reshape((image.shape))
    
    # Load image and perform kmeans
    image = cv2.imread('1.jpg')
    kmeans = kmeans_color_quantization(image, clusters=3)
    result = kmeans.copy()
    
    # Floodfill
    seed_point = (150, 50)
    cv2.floodFill(result, None, seedPoint=seed_point, newVal=(36, 255, 12), loDiff=(0, 0, 0, 0), upDiff=(0, 0, 0, 0))
    
    cv2.imshow('image', image)
    cv2.imshow('kmeans', kmeans)
    cv2.imshow('result', result)
    cv2.waitKey()     
    

    【讨论】:

    • @nathancy 谢谢你的代码!这很棒。我试图添加 Canny edge 作为遮罩以使 FloodFill 更好地工作,但我将在 K-means 之后完成所有这些。
    • @nathancy 我可以使用洪水填充算法来检测孔是关闭还是打开?它会健壮吗?
    • @user1241241 你可以,但我建议使用轮廓过滤,看看凸包。有一个内置的方法来检查凸性isContourConvex
    • 即使在关闭的情况下,从顶视图看,该孔看起来也几乎相似。还有其他方法吗? :O
    • 我很困惑你是在谈论这篇文章还是它与你目前遇到的问题有关。如果它涉及您自己的项目,我建议提出一个问题
    猜你喜欢
    • 1970-01-01
    • 2015-05-30
    • 2015-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-21
    • 2020-04-06
    • 1970-01-01
    相关资源
    最近更新 更多