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


import cv2
import numpy as np

def extract_dominant_piece_color(cell_bgr):
    """Извлекает медианный цвет центральной зоны клетки."""
    h, w, _ = cell_bgr.shape
    center = cell_bgr[int(h * 0.25):int(h * 0.75), int(w * 0.25):int(w * 0.75)]
    median_color = np.median(center, axis=(0, 1))
    return median_color.tolist()


def scan_frame(cell_board, color_database, templates_edges, ALL_PIECES):
    """
    Принимает BGR-изображение доски (numpy array), базу цветов и шаблоны Canny.
    Возвращает:
      - board_matrix (матрица 8x8 с символами фигур)
      - fen (FEN-строку позиции)
    """
    # Приводим к фиксированному размеру для точной нарезки
    board = cv2.resize(cell_board, (400, 400))
    board_matrix = []
    
    for row in range(8):
        row_pieces = []
        for col in range(8):
            cell = board[row * 50:(row + 1) * 50, col * 50:(col + 1) * 50]
            gray_cell = cv2.cvtColor(cell, cv2.COLOR_BGR2GRAY)
            
            # Контуры Canny только в центре клетки (7:43), без границ
            cell_edge = cv2.Canny(gray_cell[7:43, 7:43], 50, 150)

            # 1. Отсекаем пустые клетки (мало граней)
            if np.count_nonzero(cell_edge) < 25:
                row_pieces.append('.')
                continue

            # 2. Сравниваем форму + вычитаем штраф за цвет
            cell_color = np.array(extract_dominant_piece_color(cell))
            best_match, max_score = '.', -999.0

            for piece_symbol in ALL_PIECES:
                if piece_symbol not in templates_edges:
                    continue
                
                # Совпадение формы (Canny)
                res = cv2.matchTemplate(cell_edge, templates_edges[piece_symbol], cv2.TM_CCOEFF_NORMED)
                _, shape_score, _, _ = cv2.minMaxLoc(res)
                
                # Штраф за расхождение по цвету
                color_dist = np.linalg.norm(cell_color - np.array(color_database[piece_symbol]))
                score = shape_score - (color_dist / 100.0)
                
                if score > max_score:
                    max_score, best_match = score, piece_symbol
                    
            row_pieces.append(best_match)
        board_matrix.append(row_pieces)

    # 3. Формирование FEN-строки
    fen_rows = []
    for r in board_matrix:
        empty, row_str = 0, ""
        for p in r:
            if p == '.': 
                empty += 1
            else:
                if empty > 0: 
                    row_str += str(empty)
                    empty = 0
                row_str += p
        if empty > 0: 
            row_str += str(empty)
        fen_rows.append(row_str)
        
    fen_string = "/".join(fen_rows) + " w - - 0 1"
    
    return board_matrix, fen_string