├── 12.png ├── 13.png ├── 14.png ├── LICENSE ├── Predicted_captcha - Copy.jpg ├── Predicted_captcha.jpg ├── README.md ├── captcha_detector.py ├── examples ├── axios_example.js ├── python_request.py └── server.py ├── labelmap.pbtxt └── solver.py /12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Summaw/Text-Captcha-Solver/21001473195f44b11d72c00f53e46183a94a0cc5/12.png -------------------------------------------------------------------------------- /13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Summaw/Text-Captcha-Solver/21001473195f44b11d72c00f53e46183a94a0cc5/13.png -------------------------------------------------------------------------------- /14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Summaw/Text-Captcha-Solver/21001473195f44b11d72c00f53e46183a94a0cc5/14.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Summaw 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Predicted_captcha - Copy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Summaw/Text-Captcha-Solver/21001473195f44b11d72c00f53e46183a94a0cc5/Predicted_captcha - Copy.jpg -------------------------------------------------------------------------------- /Predicted_captcha.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Summaw/Text-Captcha-Solver/21001473195f44b11d72c00f53e46183a94a0cc5/Predicted_captcha.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Text-Captcha-Solver 2 | - **Image to text** 3 | - **If you run into any problems, please open a issue and I will try to reply with a solution for you. Enjoy please drop a star!** 4 | 5 | # Updates/Additions 11/7/23: 6 | - Updated server.py example to use requests to downlaod image rather then selenium. 7 | 8 | # Read The Following Fixs: 9 | - ISSUE: https://github.com/Summaw/Text-Captcha-Solver/issues/3 10 | - ISSUE: https://github.com/Summaw/Text-Captcha-Solver/issues/6 11 | 12 | # Program For Photos: 13 | - https://github.com/heartexlabs/labelImg 14 | 15 | ![image](https://user-images.githubusercontent.com/98126132/208988308-28f4522a-115b-4798-8900-c66ac20d6b44.png) 16 | 17 | # Server/Request Examples Included 18 | - Response Photo: 19 | 20 | ![image](https://user-images.githubusercontent.com/98126132/209490026-6ec110ab-2831-4b1b-b449-b1a809193b25.png) 21 | 22 | # Example usages 23 | - In the server.py example I left for you, It takes the image url you send it and downloads the image and saves it as "Captcha.png" 24 | 25 | # Model Downlpad 26 | - This Model was trained for wish.com, You will need to train your own model for the site you want to use this on. 27 | - Download the frozen_inference_graph.pb here (File was too big to upload to github :( ): 28 | - [Model Download](https://pixeldrain.com/u/DxfFyXPR) 29 | -------------------------------------------------------------------------------- /captcha_detector.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import os 4 | import sys 5 | 6 | # run on CPU, to run on GPU comment this line or write '0' 7 | os.environ['CUDA_VISIBLE_DEVICES'] = '-1' 8 | # import tensorflow as tf 9 | import tensorflow.compat.v1 as tf 10 | from distutils.version import StrictVersion 11 | from collections import defaultdict 12 | 13 | # title of our window 14 | title = "CAPTCHA" 15 | 16 | # Env setup 17 | from object_detection.utils import ops as utils_ops 18 | from object_detection.utils import label_map_util 19 | from object_detection.utils import visualization_utils as vis_util 20 | 21 | # Model preparation 22 | PATH_TO_FROZEN_GRAPH = 'frozen_inference_graph.pb' 23 | # List of the strings that is used to add correct label for each box. 24 | PATH_TO_LABELS = 'labelmap.pbtxt' 25 | NUM_CLASSES = 37 26 | 27 | # Load a (frozen) Tensorflow model into memory. 28 | label_map = label_map_util.load_labelmap(PATH_TO_LABELS) 29 | categories = label_map_util.convert_label_map_to_categories(label_map, max_num_classes=NUM_CLASSES, 30 | use_display_name=True) 31 | category_index = label_map_util.create_category_index(categories) 32 | 33 | detection_graph = tf.Graph() 34 | with detection_graph.as_default(): 35 | od_graph_def = tf.GraphDef() 36 | with tf.io.gfile.GFile(PATH_TO_FROZEN_GRAPH, 'rb') as fid: 37 | serialized_graph = fid.read() 38 | od_graph_def.ParseFromString(serialized_graph) 39 | tf.import_graph_def(od_graph_def, name='') 40 | 41 | 42 | # Detection 43 | def Captcha_detection(image, average_distance_error=3): 44 | with detection_graph.as_default(): 45 | with tf.Session(graph=detection_graph) as sess: 46 | # Open image 47 | image_np = cv2.imread(image) 48 | # Resize image if needed 49 | image_np = cv2.resize(image_np, (0, 0), fx=3, fy=3) 50 | # To get real color we do this: 51 | image_np = cv2.cvtColor(image_np, cv2.COLOR_BGR2RGB) 52 | # Expand dimensions since the model expects images to have shape: [1, None, None, 3] 53 | image_np_expanded = np.expand_dims(image_np, axis=0) 54 | # Actual detection. 55 | image_tensor = detection_graph.get_tensor_by_name('image_tensor:0') 56 | boxes = detection_graph.get_tensor_by_name('detection_boxes:0') 57 | scores = detection_graph.get_tensor_by_name('detection_scores:0') 58 | classes = detection_graph.get_tensor_by_name('detection_classes:0') 59 | num_detections = detection_graph.get_tensor_by_name('num_detections:0') 60 | # Visualization of the results of a detection. 61 | (boxes, scores, classes, num_detections) = sess.run( 62 | [boxes, scores, classes, num_detections], 63 | feed_dict={image_tensor: image_np_expanded}) 64 | vis_util.visualize_boxes_and_labels_on_image_array( 65 | image_np, 66 | np.squeeze(boxes), 67 | np.squeeze(classes).astype(np.int32), 68 | np.squeeze(scores), 69 | category_index, 70 | use_normalized_coordinates=True, 71 | line_thickness=2) 72 | # Show image with detection 73 | # cv2.imshow(title, cv2.cvtColor(image_np, cv2.COLOR_BGR2RGB)) 74 | # Save image with detection 75 | cv2.imwrite("Predicted_captcha.jpg", cv2.cvtColor(image_np, cv2.COLOR_BGR2RGB)) 76 | 77 | # Bellow we do filtering stuff 78 | captcha_array = [] 79 | # loop our all detection boxes 80 | for i, b in enumerate(boxes[0]): 81 | for Symbol in range(37): 82 | if classes[0][i] == Symbol: # check if detected class equal to our symbols 83 | if scores[0][i] >= 0.65: # do something only if detected score more han 0.65 84 | # x-left # x-right 85 | mid_x = (boxes[0][i][1] + boxes[0][i][3]) / 2 # find x coordinates center of letter 86 | # to captcha_array array save detected Symbol, middle X coordinates and detection percentage 87 | captcha_array.append([category_index[Symbol].get('name'), mid_x, scores[0][i]]) 88 | 89 | # rearange array acording to X coordinates datected 90 | for number in range(20): 91 | for captcha_number in range(len(captcha_array) - 1): 92 | if captcha_array[captcha_number][1] > captcha_array[captcha_number + 1][1]: 93 | temporary_captcha = captcha_array[captcha_number] 94 | captcha_array[captcha_number] = captcha_array[captcha_number + 1] 95 | captcha_array[captcha_number + 1] = temporary_captcha 96 | 97 | # Find average distance between detected symbols 98 | average = 0 99 | captcha_len = len(captcha_array) - 1 100 | while captcha_len > 0: 101 | average += captcha_array[captcha_len][1] - captcha_array[captcha_len - 1][1] 102 | captcha_len -= 1 103 | # Increase average distance error 104 | average = average / (len(captcha_array) + average_distance_error) 105 | 106 | captcha_array_filtered = list(captcha_array) 107 | captcha_len = len(captcha_array) - 1 108 | while captcha_len > 0: 109 | # if average distance is larger than error distance 110 | if captcha_array[captcha_len][1] - captcha_array[captcha_len - 1][1] < average: 111 | # check which symbol has higher detection percentage 112 | if captcha_array[captcha_len][2] > captcha_array[captcha_len - 1][2]: 113 | del captcha_array_filtered[captcha_len - 1] 114 | else: 115 | del captcha_array_filtered[captcha_len] 116 | captcha_len -= 1 117 | 118 | # Get final string from filtered CAPTCHA array 119 | captcha_string = "" 120 | for captcha_letter in range(len(captcha_array_filtered)): 121 | captcha_string += captcha_array_filtered[captcha_letter][0] 122 | print('Solved Captcha:'+ captcha_string) 123 | return captcha_string 124 | -------------------------------------------------------------------------------- /examples/axios_example.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | 3 | 4 | async function main(captcha_url) { 5 | var config = { 6 | method: 'get', 7 | url: `http://127.0.0.1:5000/?url=${captcha_url}`, 8 | headers: { } 9 | }; 10 | 11 | axios(config) 12 | .then(function (response) { 13 | console.log(JSON.stringify(response.data)) 14 | if ( response.status == 200) { 15 | console.log(`Solved Captcha: ` + response.data.response) 16 | } else { 17 | console.log(`[+] Error: ${response.status}`) 18 | } 19 | }) 20 | .catch(function (error) { 21 | console.log(error); 22 | }); 23 | } 24 | 25 | main("captchaimage_url"); 26 | -------------------------------------------------------------------------------- /examples/python_request.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import asyncio 3 | 4 | 5 | async def start(captcha_url): 6 | url = f'http://127.0.0.1:5000/?url={captcha_url}' 7 | 8 | payload={} 9 | headers = {} 10 | 11 | response = requests.request("GET", url, headers=headers, data=payload) 12 | 13 | print(response.text) 14 | 15 | if __name__ in "__main__": 16 | captcha_url = 'your captcha image url' 17 | asyncio.run(start(captcha_url)) 18 | -------------------------------------------------------------------------------- /examples/server.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify, make_response, request 2 | from captcha_detector import Captcha_detection 3 | from time import sleep 4 | import time 5 | import urllib 6 | import httpx 7 | 8 | app = Flask(__name__) 9 | 10 | @app.route('/') 11 | def hello_world(): 12 | new_url = request.args.get('url') 13 | print(request.args.get('url')) 14 | 15 | session = httpx.Client(headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36'},timeout=30) 16 | url = new_url 17 | output_file = 'captcha.png' 18 | response = session.get(url) 19 | 20 | if response.status_code == 200: 21 | with open(output_file, 'wb') as file: 22 | file.write(response.content) 23 | 24 | print(f"Photo downloaded and saved as '{output_file}'") 25 | else: 26 | print(f"Failed to download the photo. Status code: {response.status_code}") 27 | 28 | response = { 29 | "Solved": True, 30 | "response": Captcha_detection('captcha.png') 31 | } 32 | return make_response(jsonify(response), 200) 33 | 34 | if __name__ == '__main__': 35 | app.run() 36 | -------------------------------------------------------------------------------- /labelmap.pbtxt: -------------------------------------------------------------------------------- 1 | item { 2 | id: 1 3 | name: 'A' 4 | } 5 | item { 6 | id: 2 7 | name: 'B' 8 | } 9 | item { 10 | id: 3 11 | name: 'C' 12 | } 13 | item { 14 | id: 4 15 | name: 'D' 16 | } 17 | item { 18 | id: 5 19 | name: 'E' 20 | } 21 | item { 22 | id: 6 23 | name: 'F' 24 | } 25 | item { 26 | id: 7 27 | name: 'G' 28 | } 29 | item { 30 | id: 8 31 | name: 'H' 32 | } 33 | item { 34 | id: 9 35 | name: 'I' 36 | } 37 | item { 38 | id: 10 39 | name: 'J' 40 | } 41 | item { 42 | id: 11 43 | name: 'K' 44 | } 45 | item { 46 | id: 12 47 | name: 'L' 48 | } 49 | item { 50 | id: 13 51 | name: 'M' 52 | } 53 | item { 54 | id: 14 55 | name: 'N' 56 | } 57 | item { 58 | id: 15 59 | name: 'O' 60 | } 61 | item { 62 | id: 16 63 | name: 'P' 64 | } 65 | item { 66 | id: 17 67 | name: 'Q' 68 | } 69 | item { 70 | id: 18 71 | name: 'R' 72 | } 73 | item { 74 | id: 19 75 | name: 'S' 76 | } 77 | item { 78 | id: 20 79 | name: 'T' 80 | } 81 | item { 82 | id: 21 83 | name: 'U' 84 | } 85 | item { 86 | id: 22 87 | name: 'V' 88 | } 89 | item { 90 | id: 23 91 | name: 'W' 92 | } 93 | item { 94 | id: 24 95 | name: 'X' 96 | } 97 | item { 98 | id: 25 99 | name: 'Y' 100 | } 101 | item { 102 | id: 26 103 | name: 'Z' 104 | } 105 | item { 106 | id: 27 107 | name: '0' 108 | } 109 | item { 110 | id: 28 111 | name: '1' 112 | } 113 | item { 114 | id: 29 115 | name: '2' 116 | } 117 | item { 118 | id: 30 119 | name: '3' 120 | } 121 | item { 122 | id: 31 123 | name: '4' 124 | } 125 | item { 126 | id: 32 127 | name: '5' 128 | } 129 | item { 130 | id: 33 131 | name: '6' 132 | } 133 | item { 134 | id: 34 135 | name: '7' 136 | } 137 | item { 138 | id: 35 139 | name: '8' 140 | } 141 | item { 142 | id: 36 143 | name: '9' 144 | } -------------------------------------------------------------------------------- /solver.py: -------------------------------------------------------------------------------- 1 | from captcha_detector import Captcha_detection 2 | 3 | print(Captcha_detection('12.png')) --------------------------------------------------------------------------------