File size: 5,299 Bytes
cefe58f
 
 
 
 
 
 
 
 
2495559
cefe58f
 
 
 
 
 
 
 
 
 
 
 
2495559
5239c02
2495559
5239c02
2495559
 
5985dd0
2495559
 
 
 
 
5239c02
2495559
 
f318822
2495559
 
 
 
 
 
 
5239c02
2495559
 
 
 
5985dd0
 
2495559
f318822
2495559
 
 
f318822
2495559
5239c02
2495559
5239c02
 
cefe58f
 
 
 
 
 
 
 
2495559
 
cefe58f
 
 
 
 
2495559
5239c02
 
 
 
 
2d8ec0b
 
 
5a423af
5239c02
2495559
 
 
 
5a423af
2495559
5a423af
2495559
 
cefe58f
 
 
 
 
 
2495559
cefe58f
 
 
 
 
 
 
 
5239c02
cefe58f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2495559
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import base64
import logging
import re
import requests
import cv2
import numpy as np
import pytesseract
from flask import Flask, render_template, jsonify
from threading import Lock
import math

app = Flask(__name__)
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

solved_captchas = []
lock = Lock()

CAPTCHA_URL = 'https://checkege.rustest.ru/api/captcha'
HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}

def deskew(image):
    """
    Вычисляет угол наклона и поворачивает изображение, но только если угол адекватен.
    """
    gray = cv2.bitwise_not(image)
    coords = np.column_stack(np.where(gray > 0))
    
    if len(coords) < 1:
        logging.warning("Нет контента для выпрямления, пропуск deskew.")
        return image
        
    angle = cv2.minAreaRect(coords)[-1]

    if angle < -45:
        correction_angle = -(90 + angle)
    else:
        correction_angle = -angle
        
    # --- КЛЮЧЕВОЕ ИЗМЕНЕНИЕ: ПРОВЕРКА НА АДЕКВАТНОСТЬ ---
    # Если вычисленный угол слишком большой, это почти наверняка ошибка.
    # Безопаснее пропустить поворот, чем повернуть на 90 градусов.
    if abs(correction_angle) > 45:
        logging.warning(f"Вычислен неадекватный угол {correction_angle:.2f}. Пропуск коррекции наклона.")
        return image

    # Пропускаем, если наклон незначителен
    if abs(correction_angle) < 1:
        logging.info("Угол наклона незначителен, коррекция не требуется.")
        return image

    logging.info(f"Обнаружен адекватный угол наклона: {correction_angle:.2f} градусов. Применяется коррекция.")
    
    (h, w) = image.shape[:2]
    center = (w // 2, h // 2)
    M = cv2.getRotationMatrix2D(center, correction_angle, 1.0)
    
    rotated = cv2.warpAffine(image, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_CONSTANT, borderValue=(255,255,255))
    
    return rotated


def fetch_and_solve_captcha():
    try:
        logging.info("Получение новой капчи...")
        response = requests.get(CAPTCHA_URL, headers=HEADERS)
        response.raise_for_status()
        
        data = response.json()
        base64_image_data = data.get("Image")
        if not base64_image_data:
            return None

        image_bytes = base64.b64decode(base64_image_data)
        nparr = np.frombuffer(image_bytes, np.uint8)
        original_image = cv2.imdecode(nparr, cv2.IMREAD_COLOR)

        scale_factor = 2
        width = int(original_image.shape[1] * scale_factor)
        height = int(original_image.shape[0] * scale_factor)
        upscaled_image = cv2.resize(original_image, (width, height), interpolation=cv2.INTER_CUBIC)

        hsv = cv2.cvtColor(upscaled_image, cv2.COLOR_BGR2HSV)
        lower_blue = np.array([90, 50, 50])
        upper_blue = np.array([130, 255, 255])
        mask = cv2.inRange(hsv, lower_blue, upper_blue)
        
        kernel = np.ones((2, 2), np.uint8)
        cleaned_mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=2)
        
        inverted_mask = cv2.bitwise_not(cleaned_mask)
        deskewed_image = deskew(inverted_mask)
        
        processed_image = deskewed_image
        
        tesseract_config = r'--oem 3 --psm 6 -c tessedit_char_whitelist=0123456789'
        text = pytesseract.image_to_string(processed_image, config=tesseract_config)
        recognized_text = re.sub(r'\s+', '', text).strip() or "Не распознано"
        logging.info(f"Распознано: {recognized_text}")

        _, buffer_orig = cv2.imencode('.png', original_image)
        original_b64 = base64.b64encode(buffer_orig).decode('utf-8')
        
        _, buffer_proc = cv2.imencode('.png', processed_image)
        processed_b64 = base64.b64encode(buffer_proc).decode('utf-8')

        return {
            "text": recognized_text,
            "original_b64": original_b64,
            "processed_b64": processed_b64
        }
    except Exception as e:
        logging.error(f"Произошла ошибка при решении капчи: {e}", exc_info=True)
        return None

@app.route('/')
def index():
    with lock:
        return render_template('index.html', captchas=list(solved_captchas))

@app.route('/solve', methods=['POST'])
def solve_new_captcha():
    new_captcha = fetch_and_solve_captcha()
    if new_captcha:
        with lock:
            solved_captchas.insert(0, new_captcha)
        return jsonify(new_captcha)
    return jsonify({"error": "Не удалось решить капчу"}), 500

if __name__ == '__main__':
    logging.info("Запуск приложения...")
    initial_captcha = fetch_and_solve_captcha()
    if initial_captcha:
        solved_captchas.append(initial_captcha)
    
    app.run(host='0.0.0.0', port=7860, debug=False)