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?
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.
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é.
# 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.
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)
.
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]