(
img: cv2.typing.MatLike,
)
| 16 | |
| 17 | |
| 18 | def get_captcha_fields( |
| 19 | img: cv2.typing.MatLike, |
| 20 | ) -> Tuple[List[bytes], List[Tuple[int, int]]]: |
| 21 | captcha_fields_with_sizes: List[Tuple[bytes, int, int, int]] = [] |
| 22 | captcha_fields: List[Tuple[bytes, int, int]] = [] |
| 23 | |
| 24 | # Turn image to grayscale and Apply a white threshold to it |
| 25 | gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) |
| 26 | ret, thresh = cv2.threshold(gray, 254, 255, cv2.CHAIN_APPROX_NONE) |
| 27 | # Find Countours of the white threshold |
| 28 | try: |
| 29 | image, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) # type: ignore |
| 30 | except ValueError: |
| 31 | contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) # type: ignore |
| 32 | |
| 33 | for contour in contours: |
| 34 | # Checking Image area to only get large captcha areas (no image details) |
| 35 | area = cv2.contourArea(contour) |
| 36 | if area > 1000: |
| 37 | # IDK what this does i copy pasted it :) |
| 38 | approx = cv2.approxPolyDP(contour, 0.01 * cv2.arcLength(contour, True), True) |
| 39 | |
| 40 | # Calculating x, y, width, height, aspectRatio |
| 41 | x, y, w, h = cv2.boundingRect(approx) |
| 42 | aspectRatio = float(w) / h |
| 43 | |
| 44 | if 0.95 <= aspectRatio <= 1.05: |
| 45 | # Cropping Image area to Captcha Field |
| 46 | crop_img = img[y:y+h, x:x+w] # fmt: skip |
| 47 | # Cv2 to Image Bytes |
| 48 | image_bytes = cv2.imencode(".jpg", crop_img)[1].tobytes() |
| 49 | image_size: int = w * h |
| 50 | # Getting Center of Captcha Field |
| 51 | center_x, center_y = x + (w // 2), y + (h // 2) |
| 52 | captcha_fields_with_sizes.append((image_bytes, center_x, center_y, image_size)) |
| 53 | |
| 54 | if len(captcha_fields_with_sizes) >= 9: |
| 55 | # Dont use captcha fields that are too big |
| 56 | size_median = median([sizes[3] for sizes in captcha_fields_with_sizes]) |
| 57 | for i, (image_bytes, center_x, center_y, image_size) in enumerate(captcha_fields_with_sizes): |
| 58 | if int(image_size) == int(size_median): |
| 59 | captcha_fields.append((image_bytes, center_x, center_y)) |
| 60 | else: |
| 61 | for image_bytes, center_x, center_y, image_size in captcha_fields_with_sizes: |
| 62 | captcha_fields.append((image_bytes, center_x, center_y)) |
| 63 | |
| 64 | sorted_captcha_fields: List[Tuple[bytes, int, int]] = sorted(captcha_fields, key=lambda element: [element[2], element[1]]) |
| 65 | # return sorted_captcha_fields |
| 66 | return ( |
| 67 | [field[0] for field in sorted_captcha_fields], |
| 68 | [(field[1], field[2]) for field in sorted_captcha_fields], |
| 69 | ) |
| 70 | |
| 71 | |
| 72 | def split_image_into_tiles(img: cv2.typing.MatLike, tile_count: int) -> List[bytes]: |
no outgoing calls
no test coverage detected