J'ai trouvé le code suivant sur ce site Web :
[INFO] processing image 1/9955 Traceback (most recent call last): File "extract_single_letters_from_captchas.py", line 47, in <module> (x, y, w, h) = cv2.boundingRect(contour) cv2.error: OpenCV(4.0.0) /Users/travis/build/skvark/opencv-python/opencv/modules/imgproc/src/shapedescr.cpp:741: error: (-215:Assertion failed) npoints >= 0 && (depth == CV_32F || depth == CV_32S) in function 'pointSetBoundingRect'
Lorsque j'essaye d'exécuter le code, j'obtiens l'erreur suivante:
import os import os.path import cv2 import glob import imutils CAPTCHA_IMAGE_FOLDER = "generated_captcha_images" OUTPUT_FOLDER = "extracted_letter_images" # Get a list of all the captcha images we need to process captcha_image_files = glob.glob(os.path.join(CAPTCHA_IMAGE_FOLDER, "*")) counts = {} # loop over the image paths for (i, captcha_image_file) in enumerate(captcha_image_files): print("[INFO] processing image {}/{}".format(i + 1, len(captcha_image_files))) # Since the filename contains the captcha text (i.e. "2A2X.png" has the text "2A2X"), # grab the base filename as the text filename = os.path.basename(captcha_image_file) captcha_correct_text = os.path.splitext(filename)[0] # Load the image and convert it to grayscale image = cv2.imread(captcha_image_file) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # Add some extra padding around the image gray = cv2.copyMakeBorder(gray, 8, 8, 8, 8, cv2.BORDER_REPLICATE) # threshold the image (convert it to pure black and white) thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1] # find the contours (continuous blobs of pixels) the image contours = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # Hack for compatibility with different OpenCV versions contours = contours[0] if imutils.is_cv2() else contours[1] letter_image_regions = [] # Now we can loop through each of the four contours and extract the letter # inside of each one for contour in contours: # Get the rectangle that contains the contour (x, y, w, h) = cv2.boundingRect(contour) # Compare the width and height of the contour to detect letters that # are conjoined into one chunk if w / h > 1.25: # This contour is too wide to be a single letter! # Split it in half into two letter regions! half_width = int(w / 2) letter_image_regions.append((x, y, half_width, h)) letter_image_regions.append((x + half_width, y, half_width, h)) else: # This is a normal letter by itself letter_image_regions.append((x, y, w, h)) # If we found more or less than 4 letters in the captcha, our letter extraction # didn't work correcly. Skip the image instead of saving bad training data! if len(letter_image_regions) != 4: continue # Sort the detected letter images based on the x coordinate to make sure # we are processing them from left-to-right so we match the right image # with the right letter letter_image_regions = sorted(letter_image_regions, key=lambda x: x[0]) # Save out each letter as a single image for letter_bounding_box, letter_text in zip(letter_image_regions, captcha_correct_text): # Grab the coordinates of the letter in the image x, y, w, h = letter_bounding_box # Extract the letter from the original image with a 2-pixel margin around the edge letter_image = gray[y - 2:y + h + 2, x - 2:x + w + 2] # Get the folder to save the image in save_path = os.path.join(OUTPUT_FOLDER, letter_text) # if the output directory does not exist, create it if not os.path.exists(save_path): os.makedirs(save_path) # write the letter image to a file count = counts.get(letter_text, 1) p = os.path.join(save_path, "{}.png".format(str(count).zfill(6))) cv2.imwrite(p, letter_image) # increment the count for the current key counts[letter_text] = count + 1
type (contour [0])
=
len (contour)
= 4
6 Réponses :
Cela ne fait pas la bonne chose:
contours = contours[1] if imutils.is_cv3() else contours[0]
imutils.is_cv2 ()
renvoie False
même s'il doit renvoyer Vrai
. Si cela ne vous dérange pas de supprimer cette dépendance, changez en:
contours = contours[0]
J'ai trouvé la raison. Le didacticiel que vous suivez a probablement été publié avant la sortie d'OpenCV 4. OpenCV 3 a changé cv2.findContours (...)
pour renvoyer image, contours, hiérarchie
, tandis que OpenCV 2 cv2.findContours (...)
et OpenCV 4's cv2.findContours (...)
a> renvoie contours, hiérarchie
. Par conséquent, avant OpenCV 4, il était correct de dire que si vous utilisez OpenCV 2, il devrait s'agir de contours [0]
sinon de contours [1]
. Si vous souhaitez toujours avoir cette "compatibilité", vous pouvez passer à:
contours = contours[0] if imutils.is_cv2() else contours[1]
@Fozoro est heureux de vous aider, mais maintenant je suis curieux de savoir pourquoi ils ont changé cette sortie sur OpenCV 3 :) Je vous ferai savoir si je trouve quelque chose à ce sujet
@Fozoro Je n'ai pas pu le comprendre :( Le changement s'est produit il y a 5 mois (voici le
Vous pouvez également passer à imutils.is_cv2 (or_better = True)
. Vous obtiendrez alors True
si vous utilisez opencv4
@ NikO'Lai mais cela ne résoudrait pas le problème que seul OpenCV 3 a un format de retour différent
【OpenCV 3 a changé cv2.findContours (...) pour renvoyer l'image, les contours, la hiérarchie】 Ce contenu est très utile pour moi. J'ajoute une nouvelle variable à l'avant et je corrige toute l'erreur ..
Bien que cela puisse être un indice précieux pour résoudre le problème, une bonne réponse démontre également la solution. Veuillez MODIFIER pour fournir un exemple de code illustrant ce que vous voulez dire. Vous pouvez également envisager d'écrire ceci comme un commentaire à la place
Ceci est dû à la version 4.0.0 d'opencv-python. Si vous souhaitez résoudre ce problème sans changer votre code, rétrograder opencv-python à la version 3.4.9.31
Désinstaller opencv-python
pip désinstaller opencv-python
Installez opencv-python == 3.4.9.31
pip install opencv-python == 3.4.9.31
Si vous rencontrez un problème avec la fonction 'pointSetBoundingRect', vous devez installer 'opencv-python-headless'
pip install opencv-python-headless==3.4.9.31
Dans OpenCV4, cv2.findContours n'a que 2 valeurs de retour. Contours étant la PREMIÈRE valeur
contours, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
Notez que j'ai ajouté un trait de soulignement pour supprimer l'autre valeur de retour de hiérarchie
J'ai écrit le même code de la manière suivante:
_, contours, _ = cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
et mon code a fonctionné. Je pense qu'avant, il retournait 2 variables maintenant que nous devons décompresser en trois variables. Si cela ne fonctionne pas, essayez ce qui suit:
_, contours, hierarchy = cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
cela devrait fonctionner.
Pour plus d'informations, vous pouvez visiter la page de documentation OpenCV: https://docs.opencv.org/3.1.0/d4/d73/tutorial_py_contours_begin.html
J'espère que cela vous aidera.
(x, y, w, h) = cv2.boundingRect(contour.astype(np.int))
Bien que les réponses de code uniquement puissent répondre à la question, vous pouvez améliorer considérablement la qualité de votre réponse en fournissant un contexte pour votre code, une raison pour laquelle ce code fonctionne et des références à la documentation pour une lecture plus approfondie. De Comment répondre : "La concision est acceptable, mais des explications plus complètes sont meilleures."
Veuillez ajouter
len (contour)
ettype (contour [0])
.Merci beaucoup pour la réponse rapide, je viens de mettre à jour ma question.
Commentez cette ligne
contours = contours [0] if imutils.is_cv2 () else contours [1]
@BahramdunAdil Merci pour la réponse rapide, maintenant cela me donne l'erreur suivante:
Traceback (dernier appel en dernier): Fichier "extract_single_letters_from_captchas.py", ligne 49, dans (x, y, w, h) = cv2.boundingRect (contour) TypeError: cv :: UMat attendu pour l'argument 'array'
@Fozoro J'ai mis à jour ma réponse avec quelques informations sur les raisons pour lesquelles cela s'est produit au cas où vous seriez curieux :)