wake-up-neo.net

Entspricht copyTo in Python OpenCV-Bindungen

OpenCV verfügt über die Funktion copyTo, mit der Sie einen maskierten Bereich von einer Matte auf eine andere kopieren können. 

http://docs.opencv.org/3.1.0/d3/d63/classcv_1_1Mat.html#a4331fa88593a9a9c14c0998574695ebb

Was ist das Äquivalent in den Python-Bindungen? Ich möchte einen Bereich eines Bildes mit einer binären Maske in ein anderes Bild kopieren. 

10
mikevanis

cv::Mat::copyTo führt eine der beiden folgenden Aktionen aus, je nachdem, ob die Ausgabematrix initialisiert wurde. Wenn Ihre Ausgabematrix nicht initialisiert ist, wird mit copyTo mit einer Maske eine neue Ausgabematrix erstellt, die dem gleichen Typ wie die Eingabe entspricht, und alle Werte werden über alle Kanäle auf 0 gesetzt. Wenn dies der Fall ist, werden die durch die Maske definierten Bilddaten kopiert, wobei der Rest der Matrix auf 0 gesetzt wird. Wenn Ihre Ausgabematrix ist initialisiert ist und bereits aus Inhalt besteht, kopiert copyTo die Pixel Diese werden in der Maske von der Quelle definiert und lassen die Pixel, die nicht Teil der Maske waren, im Ziel intakt. Daher wird ein Ersatz von Pixeln, die durch die Maske aus dem Quellbild definiert werden, in die Ausgabe übernommen.

Da OpenCV jetzt numpy als Schnittstelle zur Bibliothek verwendet, können beide Methoden sehr einfach ausgeführt werden. Um sich von der anderen Antwort in diesem Beitrag zu unterscheiden, kann das erste Verfahren durch einfaches Multiplizieren der Maske mit dem Bild in elementarer Weise erreicht werden. Wenn Sie davon ausgehen, dass Ihre Eingabe img und Ihre binäre Maske mask heißt, wobei ich davon ausgehe, dass die Maske 2D ist, gehen Sie einfach wie folgt vor:

import numpy as np
import cv2

mask = ... # define mask here
img = cv2.imread(...) # Define input image here

# Create new image
new_image = img * (mask.astype(img.dtype))

Der obige Code setzt jedoch voraus, dass sowohl img als auch mask dieselbe Anzahl von Kanälen verwenden. Es wird schwierig, wenn Sie ein Farbbild als Quelle und die Maske 2D verwenden, wie ich bereits angenommen habe. Daher ist die Gesamtzahl der Kanäle 2 und nicht 3, und daher gibt die obige Syntax einen Fehler aus, da die Dimensionen zwischen den beiden nicht mehr kompatibel sind. Sie müssen dies berücksichtigen, wenn Sie Farbbilder verwenden. Sie können dies tun, indem Sie der Maske eine dritte Dimension hinzufügen, so dass Broadcasting genutzt werden kann.

import numpy as np
import cv2

mask = ... # define mask here
img = cv2.imread(...) # Define input image here

# Create new image
# Case #1 - Other image is grayscale and source image is colour
if len(img.shape) == 3 and len(mask.shape) != 3:
    new_image = img * (mask[:,:,None].astype(img.dtype))
# Case #2 - Both images are colour or grayscale
Elif (len(img.shape) == 3 and len(mask.shape) == 3) or \
   (len(img.shape) == 1 and len(mask.shape) == 1):
    new_image = img * (mask.astype(img.dtype))
# Otherwise, we can't do this
else:
    raise Exception("Incompatible input and mask dimensions")

Für den zweiten Ansatz nehmen wir an, dass wir ein anderes Bild namens other_image haben, in dem Sie den Inhalt dieses Bildes, das durch Ihre Maske definiert wurde, zurück in das Zielbild img kopieren möchten. In diesem Fall müssen Sie zunächst alle Positionen in der Maske bestimmen, die nicht Null sind, und zwar mit numpy.where . Dann können Sie diese zum Indexieren oder Slice in Ihr Bild sowie zum gewünschten Speicherort verwenden. Wie beim ersten Ansatz müssen wir auch die Anzahl der Kanäle zwischen den beiden Bildern berücksichtigen:

import numpy as np
import cv2

mask = ... # define mask here
img = cv2.imread(...) # Define input image here
other_image = cv2.imread(...) # Define other image here

locs = np.where(mask != 0) # Get the non-zero mask locations

# Case #1 - Other image is grayscale and source image is colour
if len(img.shape) == 3 and len(other_image.shape) != 3:
    img[locs[0], locs[1]] = other_image[locs[0], locs[1], None]
# Case #2 - Both images are colour or grayscale
Elif (len(img.shape) == 3 and len(other_image.shape) == 3) or \
   (len(img.shape) == 1 and len(other_image.shape) == 1):
    img[locs[0], locs[1]] = other_image[locs[0], locs[1]]
# Otherwise, we can't do this
else:
    raise Exception("Incompatible input and output dimensions")

Hier ist ein Beispiel für beide Ansätze. Ich werde das Kameramannbild verwenden, das in den meisten Bildverarbeitungsalgorithmen ein Standardtestbild ist. 

 enter image description here

Ich habe das Bild auch künstlich gemacht, obwohl es als Graustufen dargestellt wird, aber die Intensitäten werden auf alle Kanäle kopiert. Ich werde auch eine Maske definieren, die einfach der obere linke 100 x 100-Unterbereich ist. Daher erstellen wir ein Ausgabebild, das nur diesen Unterbereich kopiert:

import numpy as np
import cv2

# Define image
img = cv2.imread("cameraman.png")

# Define mask
mask = np.zeros(img.shape, dtype=np.bool)
mask[:100, :100] = True

Wenn Sie die erste Methode verwenden und die Ergebnisse anzeigen, erhalten Sie:

 enter image description here

Wir können sehen, dass wir ein Ausgabebild erstellt haben, in dem der obere linke 100 x 100-Unterbereich unsere Bilddaten enthält, wobei der Rest der Pixel gleich 0 ist. Dies unterliegt den Maskenpositionen, die auf True gesetzt sind. Für den zweiten Ansatz erstellen wir ein anderes Bild, das zufällig die gleiche Größe wie das Eingabebild hat, das sich für alle Kanäle von [0, 255] erstreckt.

# Define other image
other_image = (255*np.random.Rand(*img.shape)).astype(np.uint8)

Sobald wir den Code mit dem zweiten Ansatz durchlaufen haben, erhalte ich jetzt dieses Bild:

 enter image description here

Wie Sie sehen können, wurde die obere linke Ecke des Bildes entsprechend den Maskenpositionen aktualisiert, die auf True gesetzt sind.

12
rayryeng

Beachten Sie, ob dies genau das ist, was Sie möchten, aber zum Kopieren mit Masken in Python würde ich mit cv2.bitwise_ gehen.

new_image = cv2.bitwise_and(old_image,binary_mask)
3
Soltius