Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenCV - How to use floodFill with RGB image?

I am trying to use floodFill on an image like below to extract the sky:

enter image description here

But even when I set the loDiff=Scalar(0,0,0) and upDiff=Scalar(255,255,255) the result is just showing the seed point and does not grow larger (the green dot):

enter image description here

code:

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);

This is the result (red dot is the seed):

enter image description here

How can I set the function to get a larger area (like the whole sky)?

like image 734
Hadi GhahremanNezhad Avatar asked Feb 12 '20 22:02

Hadi GhahremanNezhad


People also ask

How do I use flood fill in OpenCV?

Flood Fill using OpenCV. To use the flood fill, first a seed point is selected, then all neighbouring pixels of a similar colour are converted to a uniform colour. In this example the seed point is at 200, 200 (shown by a blue circle). The neighbouring pixels are then flood filled with a red colour.

How to use imfill in OpenCV?

There is no imfill function in OpenCV, but we can surely write one! The idea is rather simple. We know the pixel (0,0) is connected to the background. So we can extract the background, by simply doing a floodfill operation from pixel (0, 0). Pixels that are not affected by the floodfill operation are necessarily inside the boundary.

How do I display an image in OpenCV?

In OpenCV, you display an image using the imshow () function. Here’s the syntax: This function also takes two arguments: The first argument is the window name that will be displayed on the window. The second argument is the image that you want to display.

How to fill holes in a binary image using OpenCV?

MATLAB has a function called imfill that allows you to fill holes, and you can use it in the following way. % MATLAB code for filling holes in a binary image. im = imfill (im,'holes'); There is no imfill function in OpenCV, but we can surely write one! The idea is rather simple. We know the pixel (0,0) is connected to the background.


2 Answers

You need to set loDiff and upDiff arguments correctly.

See floodFill documentation:

loDiff – Maximal lower brightness/color difference between the currently observed pixel and one of its neighbors belonging to the component, or a seed pixel being added to the component.
upDiff – Maximal upper brightness/color difference between the currently observed pixel and one of its neighbors belonging to the component, or a seed pixel being added to the component.

Here is a Python code sample:

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()

Result:
floor

like image 127
Rotem Avatar answered Sep 29 '22 14:09

Rotem


Another thing you could do if you want the floodfill to contour as close as possible to contrasting elements in your image is to perform Kmeans color quantization to segment the image into a specified number of clusters. Since the sky and the mountains/trees have a visible color difference, we could segment the image into only three colors which will separate the objects better.

For instance with clusters=3:

Input image -> Kmeans color segmentation

Floodfill result in green

Notice how after segmenting, only three colors define the image. In this way, the floodfill will contour along the mountains/trees better

Code

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()     
like image 35
nathancy Avatar answered Sep 29 '22 14:09

nathancy