web-dev-qa-db-fra.com

Comment extraire une section spécifique d'une image à l'aide d'OpenCV en Python?

J'essaie d'extraire une partie d'une image en effectuant une détection Canny Edge. J'ai créé avec succès un masque de cet objet. Mais lorsque j'effectue une opération bitwise_and avec l'image d'origine pour extraire la section de premier plan, l'erreur suivante apparaît.

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

Mon code est comme suit -

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

REMARQUE: - Le code fonctionne correctement si j'essaie d'exécuter le bitwise_and avec une version en niveaux de gris de l'image. Cependant, RVB, HSV ou tout autre espace colorimétrique donne l'erreur ci-dessus.

S'il vous plaît aider.


EDIT 1 - L'image en question est la suivante -

 3.jpeg

EDIT 2-

Voici le résultat après l'utilisation de la méthode Numpy. Comme vous pouvez le constater, l’image extraite a la même taille que l’orange mais elle ne contient pas l’orange mais le masque lui-même.

 result

EDIT 3- @ DanMašek et @lightalchemist, je pouvais enfin extraire n’importe quelle image au premier plan.

 result1

 result2

Je vous remercie

5
Boudhayan Dev

J'ai utilisé le code fourni ci-dessus, mais seulement modifié la ligne où la cv2.bitwise_and() est utilisée:

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

Voici ce que j'ai et ce à quoi vous vous attendiez (je suppose):

 enter image description here

EDIT

Je comprends, vous voulez masquer votre image avec une image de contour ayant la plus grande surface. Dans l'extrait supplémentaire suivant, j'ai binarisé l'image contenant le contour de la plus grande surface à utiliser comme masque.

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)

C'est ce que j'ai eu:

 enter image description here

Comparé à l'image ci-dessus, vous ne voyez pas ces trous à l'intérieur de l'objet d'intérêt.

1
Jeru Luke

L'erreur vous indique que vous essayez d'effectuer l'opération bitwise_and sur des matrices où les entrées ne sont pas des entiers. Je crois que les matrices doivent également avoir le même nombre de canaux. C'est pourquoi cela fonctionne avec votre image en niveaux de gris mais pas avec l'image HSV.

Au lieu d'utiliser bitwise_and, il est plus facile et plus flexible d'utiliser simplement la vectorisation numpy matrix pour effectuer le masquage de la manière suivante:

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

Notez que si votre masque est une matrice monocanal au lieu d’une matrice 3 canaux, vous devez modifier le code pour qu’il soit

new_image[mask < 255, :] = 0

1
lightalchemist