Inundación OpenCV con máscara
flood-fill (3)
Según la respuesta de Aurelius, la máscara debe ser puesta a cero.
Comprobando el comentario en la fuente, declaró que
Dado que se trata de un parámetro de entrada y salida, debe asumir la responsabilidad de inicializarlo. El relleno de inundaciones no puede atravesar píxeles distintos de cero en la máscara de entrada.
La máscara afectará el resultado, por lo que debe ponerse a cero antes de usar:
cv::Mat mask;
mask = cv::Mat::zeros(img.rows + 2, img.cols + 2, CV_8UC1);
La documentation para la función de relleno de OpenCV indica:
La función utiliza y actualiza la máscara, por lo que usted es responsable de inicializar el contenido de la máscara. El relleno por inundación no puede atravesar píxeles distintos de cero en la máscara. Por ejemplo, una salida del detector de bordes se puede utilizar como una máscara para detener el llenado en los bordes. Es posible usar la misma máscara en varias llamadas a la función para asegurarse de que el área rellena no se superponga.
¿Cómo actualiza la función la máscara? ¿Establece todos los píxeles dentro del relleno a algún valor distinto de cero?
Y una versión en pitón.
im = cv2.imread("seagull.jpg")
h,w,chn = im.shape
seed = (w/2,h/2)
mask = np.zeros((h+2,w+2),np.uint8)
floodflags = 4
floodflags |= cv2.FLOODFILL_MASK_ONLY
floodflags |= (255 << 8)
num,im,mask,rect = cv2.floodFill(im, mask, seed, (255,0,0), (10,)*3, (10,)*3, floodflags)
cv2.imwrite("seagull_flood.png", mask)
(Imagen de la gaviota de Wikimedia: https://commons.wikimedia.org/wiki/Commons:Quality_images#/media/File:Gull_portrait_ca_usa.jpg )
Resultado:
Todos los píxeles de valor cero en el mismo componente conectado que el punto de inicio de la máscara se reemplazan por el valor que especifique. Este valor debe agregarse al parámetro de flags
, desplazado a la izquierda en 8 bits:
uchar fillValue = 128;
cv::floodFill(img, mask, seed, cv::Scalar(255) ,0, cv::Scalar(), cv::Scalar(), 4 | cv::FLOODFILL_MASK_ONLY | (fillValue << 8));
Un ejemplo simple, pero quizás esclarecedor sigue. Creando una imagen así:
//Create simple input image
cv::Point seed(4,4);
cv::Mat img = cv::Mat::zeros(100,100,CV_8UC1);
cv::circle(img, seed, 20, cv::Scalar(128),3);
Resultados en esta imagen:
Luego, creando una máscara y llenándola por inundación:
//Create a mask from edges in the original image
cv::Mat mask;
cv::Canny(img, mask, 100, 200);
cv::copyMakeBorder(mask, mask, 1, 1, 1, 1, cv::BORDER_REPLICATE);
//Fill mask with value 128
uchar fillValue = 128;
cv::floodFill(img, mask, seed, cv::Scalar(255) ,0, cv::Scalar(), cv::Scalar(), 4 | cv::FLOODFILL_MASK_ONLY | (fillValue << 8));
Da este resultado:
Los píxeles blancos en la máscara son el resultado de la detección de bordes, mientras que los píxeles grises son el resultado del relleno de inundación.
ACTUALIZACIÓN: En respuesta al comentario, el valor 4
marca 4
especifica el vecindario de píxeles con el que se compara la diferencia de valor de color. De la documentación:
Los bits inferiores contienen un valor de conectividad, 4 (predeterminado) u 8, utilizado dentro de la función. La conectividad determina qué vecinos de un píxel se consideran.
Cuando no se pasa el indicador cv::FLOODFILL_MASK_ONLY
, tanto la imagen como la máscara se actualizan, pero el relleno de inundación se detendrá en cualquier valor de máscara distinto de cero.