web-dev-qa-db-ja.com

copyTo in Python OpenCVバインディング?

OpenCVにはcopyTo関数があり、マット領域をあるマットから別のマットにコピーできます。

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

Pythonバインディングでこれに相当するものは何ですか?バイナリマスクを使用して、画像の領域を別の画像にコピーしたいと思います。

13
mikevanis

cv::Mat::copyTo は、出力行列が初期化されているかどうかに応じて、2つのことのいずれかを行います。出力行列が初期化されていない場合、copyToをマスクとともに使用すると、入力と同じタイプの新しい出力行列が作成され、すべてのチャネルですべての値が0に設定されます。それが起こると、マスクによって定義された画像データがコピーされ、残りのマトリックスは0に設定されます。出力マトリックスisの場合初期化され、すでにコンテンツで構成されている場合、copyToはマスクで定義されたピクセルをソースからコピーし、マスクの一部ではないピクセルを宛先でそのまま残します。そのため、ソースイメージのマスクで定義されたピクセルの置換が出力にコピーされます。

OpenCVはnumpyを使用してライブラリとインターフェイスするため、どちらの方法も非常に簡単です。この投稿で見られる他の答えと区別するために、最初の方法は、単純にマスクを要素ごとに画像で乗算することで実現できます。入力がimgと呼ばれ、バイナリマスクがmaskと呼ばれると仮定します。ここで、マスクは2Dであると仮定して、次のようにします。

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

ただし、上記のコードでは、imgmaskの両方が同じチャンネル数を共有していると想定しています。既に想定しているように、ソースとしてカラーイメージを使用し、2Dをマスクとして使用している場合、注意が必要です。したがって、チャネルの合計数は3ではなく2であるため、2つのディメンション間の互換性がなくなるため、上記の構文ではエラーが発生します。カラー画像を使用している場合は、これに対応する必要があります。これを行うには、シングルトンの3次元をマスクに追加して、ブロードキャストを利用できるようにします。

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

2番目のアプローチでは、other_imageという別のイメージがあり、マスクで定義されたこのイメージの内容をターゲットイメージimgにコピーすることを想定します。この場合、最初に行うことは、 numpy.where を使用してゼロ以外のマスク内のすべての位置を決定し、次にこれらを使用して画像にインデックスを付けるかスライスするだけでなく、コピー元。また、最初のアプローチと同様に、2つの画像間のチャネル数にも注意する必要があります。

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

両方のアプローチの実行例を次に示します。ほとんどの画像処理アルゴリズムで見られる標準的なテスト画像であるカメラマン画像を使用します。

enter image description here

また、グレースケールとして視覚化されていますが、強度はすべてのチャンネルにコピーされますが、画像の色を人工的に作成しました。また、単に左上の100 x 100サブ領域であるマスクを定義するため、このサブ領域のみをコピーする出力イメージを作成します。

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

最初の方法を使用し、結果を表示すると、次の結果が得られます。

enter image description here

左上の100 x 100サブ領域に残りのピクセルが0に設定された画像データが含まれる出力画像を作成したことがわかります。これは、Trueに設定されたマスク位置の影響を受けます。 2番目のアプローチでは、すべてのチャネルの[0, 255]から広がる入力イメージと同じサイズのランダムなイメージになるように、他のイメージを作成します。

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

2番目のアプローチでコードを実行すると、次の画像が得られます。

enter image description here

ご覧のとおり、Trueに設定されているマスクの場所に応じて、画像の左上隅が更新されています。

14
rayryeng

これがまさにあなたが望むものであるかどうかに注意してください、しかしPythonでマスクを使ってコピーするために、私はcv2.bitwise_

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