python opencv image-processing mask

python - OpenCV-Aplicar máscara a una imagen en color



image-processing mask (4)

¿Cómo puedo aplicar una máscara a una imagen en color en el último enlace de python (cv2)? En el enlace previo de python, la forma más sencilla era usar cv.Copy por ejemplo,

cv.Copy(dst, src, mask)

Pero esta función no está disponible en el enlace cv2. ¿Hay alguna solución sin utilizar el código de boilerplate?


Aquí, podría usar la función cv2.bitwise_and si ya tiene la imagen de máscara.

Para consultar el siguiente código:

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

La salida será la siguiente para una imagen de lena y para una máscara rectangular.


Bueno, aquí hay una solución si desea que el fondo no sea un color negro sólido. Solo necesitamos invertir la máscara y aplicarla en una imagen de fondo del mismo tamaño y luego combinar el fondo y el primer plano. Un profesional de esta solución es que el fondo podría ser cualquier cosa (incluso otra imagen).

Este ejemplo se modifica de Hough Circle Transform . La primera imagen es el logotipo de OpenCV, la segunda, la máscara original, la tercera, el fondo y el primer plano combinados.

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

Nota: es mejor usar los métodos opencv porque están optimizados.


La respuesta dada por Abid Rahman K no es completamente correcta. También lo probé y lo encontré muy útil pero me quedé atascado.

Así es como copio la imagen con una máscara dada.

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]

Esto es un poco lento pero da resultados correctos.

EDITAR:

Camino pitónico.

idx = (mask!=0) dst[idx] = src[idx]


Los otros métodos descritos asumen una máscara binaria. Si desea usar una imagen en escala de grises de un solo canal de valor real como una máscara (por ejemplo, desde un canal alfa), puede expandirla a tres canales y luego utilizarla para la interpolación:

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

Tenga en cuenta que la mask debe estar en el rango 0..1 para que la operación tenga éxito. También se supone que 1.0 codifica mantener solo el primer plano, mientras que 0.0 significa mantener solo el fondo.

Si la máscara puede tener la forma (h, w, 1) , esto ayuda:

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

Aquí np.atleast_3d(mask) hace que la máscara (h, w, 1) si es (h, w) y np.squeeze(...) modifica el resultado de (h, w, 3, 1) a (h, w, 3) .