web-dev-qa-db-ja.com

PythonでOpenCVを使用して画像の特定のセクションを抽出するにはどうすればよいですか?

キャニーエッジ検出を実行して、画像の一部を抽出しようとしています。そのオブジェクトのマスクを作成しました。しかし、元の画像でbitwise_and操作を実行して前景セクションを抽出すると、次のエラーが発生します。

OpenCV Error: Assertion failed ((mtype == CV_8U || mtype == CV_8S) && _mask.sameSize(*psrc1)) in cv::binary_op, file C:\projects\opencv-python\opencv\modules\core\src\arithm.cpp, line 241
    Traceback (most recent call last):
      File "C:\Users\Boudhayan Dev\Desktop\extraction.py", line 37, in <module>
        new_image = cv2.bitwise_and(img_rgb,img_rgb,mask=mask)
    cv2.error: C:\projects\opencv-python\opencv\modules\core\src\arithm.cpp:241: error: (-215) (mtype == CV_8U || mtype == CV_8S) && _mask.sameSize(*psrc1) in function cv::binary_op

私のコードは次のとおりです-

import cv2
import numpy as np

img_rgb = cv2.imread("3.jpg")
cv2.namedWindow("Original Image",cv2.WINDOW_NORMAL)

img = cv2.cvtColor(img_rgb,cv2.COLOR_RGB2HSV)
img = cv2.bilateralFilter(img,9,105,105)
r,g,b=cv2.split(img)
equalize1= cv2.equalizeHist(r)
equalize2= cv2.equalizeHist(g)
equalize3= cv2.equalizeHist(b)
equalize=cv2.merge((r,g,b))

equalize = cv2.cvtColor(equalize,cv2.COLOR_RGB2GRAY)

ret,thresh_image = cv2.threshold(equalize,0,255,cv2.THRESH_OTSU+cv2.THRESH_BINARY)
equalize= cv2.equalizeHist(thresh_image)


canny_image = cv2.Canny(equalize,250,255)
canny_image = cv2.convertScaleAbs(canny_image)
kernel = np.ones((3,3), np.uint8)
dilated_image = cv2.dilate(canny_image,kernel,iterations=1)


new,contours, hierarchy = cv2.findContours(dilated_image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours= sorted(contours, key = cv2.contourArea, reverse = True)[:10]
c=contours[0]
print(cv2.contourArea(c))
final = cv2.drawContours(img, [c], -1, (255,0, 0), 3)



mask = np.zeros(img_rgb.shape,np.uint8)
new_image = cv2.drawContours(mask,[c],0,255,-1,)
new_image = cv2.bitwise_and(img_rgb,img_rgb,mask=mask)


cv2.namedWindow("new",cv2.WINDOW_NORMAL)
cv2.imshow("new",new_image)

cv2.imshow("Original Image",img)
cv2.waitKey() 

注:-画像のグレースケールバージョンでbitwise_andを実行しようとすると、コードは正常に機能します。ただし、RGB、HSV、またはその他の色空間では、上記のエラーが発生します。

助けてください。


編集1-問題の画像はこれです-

3.jpeg

編集2-

以下は、Numpyメソッドを使用した後の結果です。ご覧のとおり、抽出された画像はオレンジと同じサイズですが、マスク自体ではなくオレンジが含まれていません。

result

編集3-@DanMašekと@lightalchemist、最終的に任意の前景画像を抽出できました。

result1

result2

ありがとうございました

5
Boudhayan Dev

上記のコードを使用しましたが、cv2.bitwise_and()が使用されている行のみを変更しました。

new_image = cv2.bitwise_and(img_rgb, img_rgb, mask = equalize)

これは私が得たものであり、あなたが期待したものです(私は推測します):

enter image description here

[〜#〜]編集[〜#〜]

わかりました。最大の面積を持つ輪郭の画像で画像をマスクしたいと思います。次の追加のスニペットでは、マスクとして使用される最大領域の輪郭を含む画像を2値化しました。

new_image = cv2.drawContours(mask,[c], -1, (255,255,255), -1)
new_image_gray = cv2.cvtColor(new_image, cv2.COLOR_BGR2GRAY)
ret, thresh1 = cv2.threshold(new_image_gray, 100, 255, cv2.THRESH_BINARY)
final = cv2.bitwise_and(img_rgb, img_rgb, mask = thresh1)

これは私が得たものです:

enter image description here

上の画像と比較すると、対象のオブジェクトの内部にこれらの穴はありません。

1
Jeru Luke

エラーは、エントリが整数ではない行列に対してbitwise_and演算を実行しようとしていることを示しています。行列にも同じ数のチャネルが必要だと思います。これが、グレースケール画像では機能しますが、HSV画像では機能しない理由です。

Bitwise_andを使用する代わりに、numpy行列のベクトル化を使用して次のようにマスキングを実行する方が簡単で柔軟性があります。

mask = np.zeros_like(img_rgb, dtype=np.uint8)

# I believe you want to draw the filled in contour on the mask
# You code actually assigns the resulting mask to new_image
# But that does not affect things as drawContours modifies mask in place
mask = cv2.drawContours(mask, [c] ,0, 255, -1) 

new_image = img_rgb.copy()
new_image[mask < 255] = 0  # Set values not masked to be 0

マスクが3チャネルマトリックスではなく単一チャネルマトリックスである場合は、コードを次のように変更する必要があることに注意してください。

new_image[mask < 255, :] = 0

1
lightalchemist