Spaces:
Sleeping
Sleeping
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 | |
def index(): | |
with lock: | |
return render_template('index.html', captchas=list(solved_captchas)) | |
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) | |