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


import cv2
import numpy as np

# Инициализация HOG-дескриптора
hog = cv2.HOGDescriptor(
    _winSize=(36, 36),
    _blockSize=(18, 18),
    _blockStride=(9, 9),
    _cellSize=(9, 9),
    _nbins=9
)

def remove_green_highlights(cell_bgr):
    """
    Находит любые зеленые оттенки (точки и подсвеченные клетки) 
    и заменяет их на средний цвет фона данной клетки.
    """
    hsv = cv2.cvtColor(cell_bgr, cv2.COLOR_BGR2HSV)
    
    # Диапазон зеленого цвета в HSV (Hue: 35-85)
    lower_green = np.array([35, 30, 30])
    upper_green = np.array([85, 255, 255])
    
    # Создаем маску зеленых пикселей
    green_mask = cv2.inRange(hsv, lower_green, upper_green)
    
    # Если зеленый цвет найден — заменяем его фоновым цветом углов клетки
    if np.any(green_mask):
        clean_cell = cell_bgr.copy()
        h, w = clean_cell.shape[:2]
        
        # Берём чистый цвет фона по углам клетки
        corners = np.array([
            clean_cell[3, 3], clean_cell[3, w-4],
            clean_cell[h-4, 3], clean_cell[h-4, w-4]
        ])
        bg_color = np.mean(corners, axis=0).astype(np.uint8)
        
        clean_cell[green_mask > 0] = bg_color
        return clean_cell
        
    return cell_bgr


def extract_dominant_piece_color(cell_bgr):
    """Извлекает средний цвет фигуры из центра клетки."""
    h, w = cell_bgr.shape[:2]
    center = cell_bgr[int(h * 0.25):int(h * 0.75), int(w * 0.25):int(w * 0.75)]
    return np.mean(center, axis=(0, 1)).astype(float).tolist()


def get_hog_features(crop_bgr):
    """Вычисляет вектор HOG-фич для центральной области фигуры."""
    gray = cv2.cvtColor(crop_bgr, cv2.COLOR_BGR2GRAY)
    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(4, 4))
    gray_norm = clahe.apply(gray)
    
    descriptor = hog.compute(gray_norm)
    if descriptor is None:
        return np.zeros((324,), dtype=np.float32)
    return descriptor.flatten()


def scan_frame(cropped_board, color_database, templates_hog, ALL_PIECES, variance_threshold=12.0):
    """
    Сканирует обрезаную доску 400x400 и распознает фигуры.
    """
    board_matrix = []
    
    for row in range(8):
        row_pieces = []
        for col in range(8):
            # Клетка 50x50 пикселей
            cell = cropped_board[row * 50:(row + 1) * 50, col * 50:(col + 1) * 50]
            
            # 1. Убираем зеленый цвет (подсветка/точки ходов) из расчета
            cell = remove_green_highlights(cell)
            
            gray_cell = cv2.cvtColor(cell, cv2.COLOR_BGR2GRAY)
            center_crop = cell[7:43, 7:43]
            center_gray = gray_cell[7:43, 7:43]

            # 2. Проверка на пустую клетку
            if np.std(center_gray) < variance_threshold:
                row_pieces.append('.')
                continue

            # 3. Распознавание фигуры через HOG и цвет
            cell_hog = get_hog_features(center_crop)

            cell_color_vec = np.array(extract_dominant_piece_color(cell))
            brightness = np.mean(cell_color_vec)
            
            is_white_piece = brightness > 110
            candidate_pieces = [p for p in ALL_PIECES if p.isupper() == is_white_piece]

            best_match, min_distance = '.', float('inf')

            for piece_symbol in candidate_pieces:
                if piece_symbol not in templates_hog or piece_symbol not in color_database:
                    continue
                
                tpl_hog = templates_hog[piece_symbol]
                hog_dist = np.linalg.norm(cell_hog - tpl_hog)

                tpl_color = np.array(color_database[piece_symbol])
                color_dist = np.linalg.norm(cell_color_vec - tpl_color)

                total_dist = hog_dist + (color_dist / 100.0)

                if total_dist < min_distance:
                    min_distance = total_dist
                    best_match = piece_symbol
                    
            row_pieces.append(best_match)
        board_matrix.append(row_pieces)

    # 4. Генерация 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)
        
    return board_matrix, "/".join(fen_rows) + " w - - 0 1"