OpenCV-appliquer le masque à une image en couleur

Comment appliquer un masque à une image en couleur dans la dernière reliure python (cv2)? Dans la fixation python précédente, la manière la plus simple était d'utiliser cv.Copy e.g.

cv.Copy(dst, src, mask)

Mais cette fonction n'est pas disponible dans cv2 de liaison. Est-il une solution sans utiliser de code réutilisable?

21
demandé sur Jeru Luke 2012-05-06 12:32:57

4 réponses

ici, vous pourriez utiliser cv2.bitwise_and fonction si vous avez déjà l'image du masque.

Pour vérifier le code ci-dessous:

img = cv2.imread('lena.jpg')
mask = cv2.imread('mask.png',0)
res = cv2.bitwise_and(img,img,mask = mask)

la sortie sera comme suit pour une image lena, et pour un masque rectangulaire.

enter image description here

34
répondu Abid Rahman K 2012-05-06 10:49:02

Eh bien, voici une solution si vous voulez que le fond soit autre qu'une couleur noire unie. Il suffit d'inverser le masque et de l'appliquer dans une image de fond de la même taille et puis combiner à la fois l'arrière-plan et l'avant-plan. Un pro de cette solution est que l'arrière-plan pourrait être n'importe quoi (même une autre image).

cet exemple est modifié de Hough Cercle Transformer. La première image est le logo OpenCV, la deuxième le masque original, la troisième l'arrière-plan + de premier plan combiné.

apply mask and get a customized background

# http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_houghcircles/py_houghcircles.html
import cv2
import numpy as np

# load the image
img = cv2.imread('E:\FOTOS\opencv\opencv_logo.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# detect circles
gray = cv2.medianBlur(cv2.cvtColor(img, cv2.COLOR_RGB2GRAY), 5)
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=50, minRadius=0, maxRadius=0)
circles = np.uint16(np.around(circles))

# draw mask
mask = np.full((img.shape[0], img.shape[1]), 0, dtype=np.uint8)  # mask is only 
for i in circles[0, :]:
    cv2.circle(mask, (i[0], i[1]), i[2], (255, 255, 255), -1)

# get first masked value (foreground)
fg = cv2.bitwise_or(img, img, mask=mask)

# get second masked value (background) mask must be inverted
mask = cv2.bitwise_not(mask)
background = np.full(img.shape, 255, dtype=np.uint8)
bk = cv2.bitwise_or(background, background, mask=mask)

# combine foreground+background
final = cv2.bitwise_or(fg, bk)

Note: il est préférable d'utiliser les méthodes opencv car elles sont optimisées.

10
répondu lmiguelmh 2016-07-21 00:46:52

Les autres méthodes décrites assumer un masque binaire. Si vous voulez utiliser une image en échelle de gris à un canal comme masque (par exemple à partir d'un canal alpha), vous pouvez l'étendre à trois canaux et ensuite l'utiliser pour l'interpolation:

assert len(mask.shape) == 2 and issubclass(mask.dtype.type, np.floating)
assert len(foreground_rgb.shape) == 3
assert len(background_rgb.shape) == 3

alpha3 = np.stack([mask]*3, axis=2)
blended = alpha3 * foreground_rgb + (1. - alpha3) * background_rgb

Notez que mask doit être dans la gamme 0..1 pour le succès de l'opération. Il est également supposé que 1.0 Code en gardant le premier plan seulement, alors que 0.0 signifie Ne garder que l'arrière-plan.

Si le masque peut ont la forme (h, w, 1), ce qui permet de:

alpha3 = np.squeeze(np.stack([np.atleast_3d(mask)]*3, axis=2))

Ici np.atleast_3d(mask) en fait le masque (h, w, 1) si c'est (h, w) et np.squeeze(...) change le résultat de (h, w, 3, 1)(h, w, 3).

2
répondu sunside 2017-02-24 23:43:59

Voici comment je copie une image avec un masque donné.

x, y = np.where(mask!=0)
pts = zip(x, y)
# Assuming dst and src are of same sizes
for pt in pts:
   dst[pt] = src[pt]

C'est un peu lent, mais donne des résultats corrects.

EDIT:

Pythonic.

idx = (mask!=0)
dst[idx] = src[idx]
0
répondu Froyo 2013-07-31 20:17:36