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 -
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.
EDIT 3- @ DanMašek et @lightalchemist, je pouvais enfin extraire n’importe quelle image au premier plan.
Je vous remercie
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):
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:
Comparé à l'image ci-dessus, vous ne voyez pas ces trous à l'intérieur de l'objet d'intérêt.
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