Загрузка данных


import cv2
import numpy as np
import onnxruntime as ort

MODEL_FILE = "chess_pieces.onnx"
IMAGE_FILE = "board.png"
CLASSES = ['.', 'P', 'N', 'B', 'R', 'Q', 'K', 'p', 'n', 'b', 'r', 'q', 'k']

def crop_board(image_path):
    img = cv2.imread(image_path)
    if img is None:
        raise FileNotFoundError(f"Не удалось найти файл картинки: {image_path}")

    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(gray, (5, 5), 0)
    edges = cv2.Canny(blur, 50, 150)

    contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    board_cnt = None
    max_area = 0

    for cnt in contours:
        area = cv2.contourArea(cnt)
        if area > 10000:
            peri = cv2.arcLength(cnt, True)
            approx = cv2.approxPolyDP(cnt, 0.02 * peri, True)
            if len(approx) == 4 and area > max_area:
                board_cnt = approx
                max_area = area

    if board_cnt is not None:
        pts = board_cnt.reshape(4, 2)
        # Сортировка углов
        rect = np.zeros((4, 2), dtype="float32")
        s = pts.sum(axis=1)
        rect[0] = pts[np.argmin(s)]
        rect[2] = pts[np.argmax(s)]
        diff = np.diff(pts, axis=1)
        rect[1] = pts[np.argmin(diff)]
        rect[3] = pts[np.argmax(diff)]

        dst = np.array([[0, 0], [399, 0], [399, 399], [0, 399]], dtype="float32")
        M = cv2.getPerspectiveTransform(rect, dst)
        return cv2.warpPerspective(img, M, (400, 400))
    else:
        return cv2.resize(img, (400, 400))

def scan_chess():
    # 1. Загружаем модель
    session = ort.InferenceSession(MODEL_FILE)
    input_shape = session.get_inputs()[0].shape
    input_name = session.get_inputs()[0].name
    
    # Автоматически определяем размер (32x32, 64x64 и т.д.)
    target_h, target_w = input_shape[2], input_shape[3]
    print(f"✓ Модель успешно загружена! Размер входа: {target_w}x{target_h}")

    # 2. Вырезаем доску
    board = crop_board(IMAGE_FILE)

    # 3. Готовим 64 клетки
    cells = []
    cell_size = 50
    for row in range(8):
        for col in range(8):
            y1, y2 = row * cell_size, (row + 1) * cell_size
            x1, x2 = col * cell_size, (col + 1) * cell_size
            cell = board[y1:y2, x1:x2]
            
            resized = cv2.resize(cell, (target_w, target_h))
            rgb = cv2.cvtColor(resized, cv2.COLOR_BGR2RGB)
            norm = rgb.astype(np.float32) / 255.0
            chw = np.transpose(norm, (2, 0, 1))
            cells.append(chw)

    batch = np.array(cells, dtype=np.float32)

    # 4. Распознавание
    outputs = session.run(None, {input_name: batch})[0]
    predictions = np.argmax(outputs, axis=1)

    # 5. Сборка FEN
    fen_rows = []
    for r in range(8):
        row_pieces = [CLASSES[idx] for idx in predictions[r*8:(r+1)*8]]
        empty_count = 0
        row_str = ""
        for piece in row_pieces:
            if piece == '.':
                empty_count += 1
            else:
                if empty_count > 0:
                    row_str += str(empty_count)
                    empty_count = 0
                row_str += piece
        if empty_count > 0:
            row_str += str(empty_count)
        fen_rows.append(row_str)

    final_fen = "/".join(fen_rows) + " w - - 0 1"
    print("\n--- УСПЕХ! ---")
    print("Распознанный FEN:", final_fen)

if __name__ == "__main__":
    try:
        scan_chess()
    except Exception as e:
        print("Ошибка:", e)