web-dev-qa-db-fra.com

OpenCV floodfill avec masque

La documentation de la fonction de remplissage de OpenCV se lit comme suit:

La fonction utilise et met à jour le masque, vous prenez donc la responsabilité de initialiser le contenu du masque. L'inondation ne peut pas dépasser non nulle pixels dans le masque. Par exemple, une sortie de détecteur de bord peut être utilisée en tant que masque pour arrêter de remplir les bords. Il est possible d'utiliser le même masquez plusieurs appels à la fonction pour vous assurer que la zone est remplie ne se chevauchent pas.

Comment la fonction met-elle à jour le masque? Définit-il tous les pixels du remplissage à une valeur non nulle?

18
1''

Tous les pixels de valeur zéro dans le même composant connecté que le point de départ du masque sont remplacés par la valeur que vous spécifiez. Cette valeur doit être ajoutée au paramètre flags, décalée à gauche de 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));

Voici un exemple simple, mais peut-être éclairant. Créer une image comme celle-ci:

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

Résultats dans cette image:

Original image

Ensuite, créer un masque et le remplir par inondation:

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

Donne ce résultat:

Flood-filled mask

Les pixels blancs du masque résultent de la détection des contours, tandis que les pixels gris résultent du remplissage.

UPDATE: .__ En réponse au commentaire, la valeur de drapeau 4 spécifie le voisinage de pixels avec lequel comparer la différence de valeur de couleur. De la documentation:

Les bits inférieurs contiennent une valeur de connectivité, 4 (par défaut) ou 8, utilisée dans la fonction. La connectivité détermine quels voisins d'un pixel sont pris en compte.

Lorsque l'indicateur cv::FLOODFILL_MASK_ONLY n'est pas passé, les deux l'image et le masque sont mis à jour, mais le remplissage par inondation s'arrête à toutes les valeurs de masque non nulles.

25
Aurelius

Et une version python

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)

(Image de mouette de Wikimedia: https://commons.wikimedia.org/wiki/Commons:Quality_images#/media/File:Gull_portrait_ca_usa.jpg )

Résultat: result

5
Roy Shilkrot

Selon la réponse d'Aurelius, le masque doit être mis à zéro. 

Vérification commentaire dans la source, il a déclaré que 

Comme il s’agit à la fois d’un paramètre d’entrée et d’un paramètre de sortie, vous devez assumer la responsabilité de l'initialiser. Le remplissage par inondation ne peut pas traverser des pixels non nuls dans le masque de saisie.

Le masque aura un impact sur le résultat, il faut donc le mettre à zéro avant utilisation:

cv::Mat mask;
mask = cv::Mat::zeros(img.rows + 2, img.cols + 2, CV_8UC1);
0
MK Yung