Spaces:
Sleeping
Sleeping
| 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[1] if imutils.is_cv3() else contours[0] | |
| 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 | |