最新のpythonバインディング(cv2)でカラー画像にマスクを適用するにはどうすればよいですか?前のpythonバインディングで最も簡単な方法は_cv.Copy
_を使用することでした例えば.
cv.Copy(dst, src, mask)
ただし、この関数はcv2バインディングでは使用できません。定型コードを使用せずに回避策はありますか?
ここでは、cv2.bitwise_and
関数は、既にマスクイメージを持っている場合。
以下のコードを確認するには:
img = cv2.imread('lena.jpg')
mask = cv2.imread('mask.png',0)
res = cv2.bitwise_and(img,img,mask = mask)
出力は、lenaイメージおよび矩形マスクの場合、次のようになります。
さて、ここで背景を黒一色以外にしたい場合の解決策があります。マスクを反転し、同じサイズの背景画像に適用するだけですそして、背景と前景の両方を組み合わせます。このソリューションの長所は、背景が何でも(他の画像でも)できることです。
この例は Hough Circle Transform から変更されています。最初の画像はOpenCVロゴ、2番目は元のマスク、3番目は背景と前景を組み合わせたものです。
# 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)
注:opencvメソッドは最適化されているため、使用することをお勧めします。
import cv2 as cv
im_color = cv.imread("lena.png", cv.IMREAD_COLOR)
im_gray = cv.cvtColor(im_color, cv.COLOR_BGR2GRAY)
この時点で、色とグレーの画像ができました。ここでは8-bit
、uint8
画像を扱っています。つまり、画像は[0, 255]
の範囲のピクセル値を持つことができ、値は整数でなければなりません。
バイナリしきい値処理を行いましょう。マスクされた画像を作成します。黒い領域の値は0
で、白い領域の値は255
です
_, mask = cv.threshold(im_gray, thresh=180, maxval=255, type=cv.THRESH_BINARY)
im_thresh_gray = cv.bitwise_and(im_gray, mask)
バイナリマスクは左下にあります。右の画像は、グレーの画像とマスクの間にbitwise_and
操作を適用した結果です。起こったのは、マスクのピクセル値がゼロ(黒)であった空間位置が、結果イメージのピクセル値ゼロになったことです。マスクのピクセル値が255(白)であった場所、結果の画像は元のグレー値を保持していました。
このマスクを元のカラー画像に適用するには、元のカラー画像が3チャンネル画像であるため、マスクを3チャンネル画像に変換する必要があります。
mask3 = cv.cvtColor(mask, cv.COLOR_GRAY2BGR) # 3 channel mask
次に、同じbitwise_and
関数を使用して、このマスクを元のカラー画像に適用できます。
im_thresh_color = cv.bitwise_and(im_color, mask3)
コードのmask3
は左下の画像で、im_thresh_color
はその右にあります。
結果をプロットして、自分で確認できます。
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)
元の画像は、lenacolor.png
でした ここ を見つけました。
説明されている他の方法では、バイナリマスクを想定しています。実数値の単一チャネルグレースケールイメージをマスクとして(たとえば、アルファチャネルから)使用する場合、3つのチャネルに展開し、補間に使用できます。
_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
_
操作を成功させるには、mask
が_0..1
_の範囲にある必要があることに注意してください。また、_1.0
_はフォアグラウンドのみを保持してエンコードし、_0.0
_はバックグラウンドのみを保持することを意味します。
マスクの形状が_(h, w, 1)
_の可能性がある場合、これは役立ちます。
_alpha3 = np.squeeze(np.stack([np.atleast_3d(mask)]*3, axis=2))
_
ここで、np.atleast_3d(mask)
は、マスクが_(h, w, 1)
_である場合、マスクを_(h, w)
_にし、np.squeeze(...)
は、結果を_(h, w, 3, 1)
_から_(h, w, 3)
_に再整形します。
Abid Rahman Kの回答は完全に正しいものではありません。私も試してみましたが、とても役に立ちましたが、行き詰まりました。
これは、指定されたマスクで画像をコピーする方法です。
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]
これは少し遅いですが、正しい結果が得られます。
編集:
Pythonicな方法。
idx = (mask!=0)
dst[idx] = src[idx]