OpenCV - Как использовать floodFill с изображением RGB? - PullRequest
3 голосов
/ 13 февраля 2020

Я пытаюсь использовать floodFill на изображении, как показано ниже, чтобы извлечь небо:

enter image description here

Но даже когда я установил loDiff=Scalar(0,0,0) и upDiff=Scalar(255,255,255) результат просто показывает начальную точку и не увеличивается (зеленая точка):

enter image description here

код:

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

Это результат (красная точка - семя):

enter image description here

Как настроить функцию, чтобы получить большую площадь (как и все небо)?

Ответы [ 2 ]

2 голосов
/ 13 февраля 2020

Еще одна вещь, которую вы могли бы сделать, если вы хотите, чтобы заливка контура была как можно ближе к контрастным элементам вашего изображения, - это выполнить квантование цветов Kmeans для сегментирования изображения на определенное количество кластеров. Поскольку небо и горы / деревья имеют видимую разницу в цвете, мы могли бы разделить изображение только на три цвета, которые лучше разделят объекты.

Например, с clusters=3:

Входное изображение -> Цветовая сегментация Kmeans

image image

Результат заливки зеленым цветом

image

Обратите внимание, что после сегментирования только три цвета определяют изображение. Таким образом, пойма будет лучше очерчиваться вдоль гор / деревьев

Код

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()     
2 голосов
/ 13 февраля 2020

Вам необходимо правильно установить loDiff и upDiff аргументы.

См. Документацию floodFill :

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

Результат:
floor

...