wake-up-neo.net

OpenCV - Maske auf ein Farbbild anwenden

Wie kann ich in der neuesten Python-Bindung (cv2) eine Maske auf ein Farbbild anwenden? In früheren Python-Bindungen bestand der einfachste Weg darin, cv.Copy zu verwenden, z.

cv.Copy(dst, src, mask)

Diese Funktion ist jedoch in der CV2-Bindung nicht verfügbar. Gibt es eine Problemumgehung ohne Boilerplate-Code?

21
pzo

Hier können Sie die Funktion cv2.bitwise_and verwenden, wenn Sie bereits über das Maskenbild verfügen.

Überprüfen Sie den folgenden Code:

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

Die Ausgabe für ein Lena-Bild und für eine rechteckige Maske lautet wie folgt.

enter image description here

39
Abid Rahman K

Nun, hier ist eine Lösung, wenn Sie möchten, dass der Hintergrund nicht schwarz ist. Wir müssen nur die Maske umkehren und in einem Hintergrundbild von gleicher Größe anwenden und dann Hintergrund und Vordergrund kombinieren. Ein Vorteil dieser Lösung ist, dass der Hintergrund alles sein kann (sogar ein anderes Bild).

Dieses Beispiel wurde von Hough Circle Transform geändert. Das erste Bild ist das OpenCV-Logo, zweitens die Originalmaske, drittens der Hintergrund + Vordergrund kombiniert.

 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)

Hinweis: Es ist besser, die opencv-Methoden zu verwenden, da sie optimiert sind.

10
lmiguelmh

Die anderen beschriebenen Methoden setzen eine binäre Maske voraus. Wenn Sie ein echtes einkanaliges Graustufenbild als Maske (z. B. aus einem Alphakanal) verwenden möchten, können Sie es auf drei Kanäle erweitern und dann zur Interpolation verwenden:

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

Beachten Sie, dass mask im Bereich 0..1 liegen muss, damit die Operation erfolgreich ausgeführt werden kann. Es wird auch angenommen, dass 1.0 nur den Vordergrund codiert, während 0.0 nur den Hintergrund bedeutet.

Wenn die Maske die Form (h, w, 1) hat, hilft dies:

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

Hier macht np.atleast_3d(mask) die Maske (h, w, 1), wenn es (h, w) ist und np.squeeze(...) das Ergebnis von (h, w, 3, 1) in (h, w, 3) umformt.

3
sunside
import cv2 as cv

im_color = cv.imread("lena.png", cv.IMREAD_COLOR)
im_gray = cv.cvtColor(im_color, cv.COLOR_BGR2GRAY)

Zu diesem Zeitpunkt haben Sie eine Farbe und ein graues Bild. Wir haben es hier mit 8-bit, uint8 Bildern zu tun. Das heißt, die Bilder können Pixelwerte im Bereich von [0, 255] haben und die Werte müssen Ganzzahlen sein.

 left-color,right-gray

Lassen Sie uns eine binäre Schwellenwertoperation durchführen. Es wird ein maskiertes Bild erstellt. Die schwarzen Regionen haben den Wert 0 und die weißen Regionen 255

_, mask = cv.threshold(im_gray, thresh=180, maxval=255, type=cv.THRESH_BINARY)
im_thresh_gray = cv.bitwise_and(im_gray, mask)

Die binäre Maske ist links unten zu sehen. Das Bild rechts davon ist das Ergebnis der Anwendung von bitwise_and zwischen dem grauen Bild und der Maske. Was passiert ist, ist, dass die räumlichen Orte, an denen die Maske einen Pixelwert von Null (Schwarz) hatte, im Ergebnisbild zum Pixelwert Null wurden. An den Stellen, an denen die Maske den Pixelwert 255 (weiß) hatte, behielt das resultierende Bild seinen ursprünglichen Grauwert bei.

 left-mask,right-bitwise_and_with_mask

Um diese Maske auf unser ursprüngliches Farbbild anzuwenden, müssen Sie die Maske in ein 3-Kanal-Bild konvertieren, da das ursprüngliche Farbbild ein 3-Kanal-Bild ist.

mask3 = cv.cvtColor(mask, cv.COLOR_GRAY2BGR)  # 3 channel mask

Dann können wir diese Maske mit derselben bitwise_and-Funktion auf unser ursprüngliches Farbbild anwenden.

im_thresh_color = cv.bitwise_and(im_color, mask3)

mask3 aus dem Code ist das Bild unten links und im_thresh_color befindet sich rechts davon.

 left-mask-3channel,right-bitwise_and_with_3channel-mask

Sie können die Ergebnisse plotten und sich selbst überzeugen.

cv.imshow("original image", im_color)
cv.imshow("binary mask", mask)
cv.imshow("3 channel mask", mask3)
cv.imshow("im_thresh_gray", im_thresh_gray)
cv.imshow("im_thresh_color", im_thresh_color)
cv.waitKey(0)

Das Originalbild ist lenacolor.png, den ich hier gefunden habe.

0
Sounak

Die Antwort von Abid Rahman K ist nicht ganz korrekt. Ich habe es auch ausprobiert und fand es sehr hilfreich, blieb aber hängen.

So kopiere ich ein Bild mit einer bestimmten Maske.

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]

Dies ist etwas langsam, liefert aber korrekte Ergebnisse.

BEARBEITEN:

Pythonischer Weg.

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