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


import cv2
import numpy as np
import os

class ChessAnalyzer:
    def __init__(self, templates_dir='templates', win_size=(64, 64)):
        self.templates_dir = templates_dir
        self.win_size = win_size
        
        # Настройка HOG-детектора (оптимизирован для размера 64x64)
        self.hog = cv2.HOGDescriptor(
            _winSize=self.win_size,
            _blockSize=(16, 16),
            _blockStride=(8, 8),
            _cellSize=(8, 8),
            _nbins=9
        )
        
        self.templates = {}
        self.load_templates()

    def _compute_phash(self, image):
        """Вычисление pHash (перцептивного хэша) через DCT"""
        resized = cv2.resize(image, (32, 32))
        gray = cv2.cvtColor(resized, cv2.COLOR_BGR2GRAY) if len(image.shape) == 3 else resized
        dct = cv2.dct(np.float32(gray))
        dct_low = dct[:8, :8]
        avg = (np.sum(dct_low) - dct_low[0, 0]) / 63.0
        return dct_low > avg

    def _phash_distance(self, hash1, hash2):
        """Расстояние Хэмминга между pHash"""
        return np.count_nonzero(hash1 != hash2)

    def load_templates(self):
        """Загрузка всех PNG из папки templates"""
        if not os.path.exists(self.templates_dir):
            print(f"[ERROR] Папка {self.templates_dir} не найдена!")
            return

        for filename in os.listdir(self.templates_dir):
            if filename.lower().endswith('.png'):
                # Имя файла без расширения (напр. "black_pawn", "white_knight")
                piece_name = os.path.splitext(filename)[0]
                path = os.path.join(self.templates_dir, filename)
                
                # Читаем с альфа-каналом (BGRA)
                img = cv2.imread(path, cv2.IMREAD_UNCHANGED)
                if img is None:
                    continue

                img_resized = cv2.resize(img, self.win_size)

                # Если есть альфа-канал, делаем наложение на нейтральный фон для HOG
                if img_resized.shape[2] == 4:
                    alpha = img_resized[:, :, 3] / 255.0
                    rgb = img_resized[:, :, :3]
                    gray_piece = cv2.cvtColor(rgb, cv2.COLOR_BGR2GRAY)
                    bg = np.ones_like(gray_piece, dtype=np.uint8) * 128
                    composite_gray = (gray_piece * alpha + bg * (1 - alpha)).astype(np.uint8)
                else:
                    composite_gray = cv2.cvtColor(img_resized, cv2.COLOR_BGR2GRAY)

                # Вычисляем признаки
                hog_feat = self.hog.compute(composite_gray)
                phash_feat = self._compute_phash(composite_gray)

                self.templates[piece_name] = {
                    'raw': img_resized,
                    'gray': composite_gray,
                    'hog': hog_feat,
                    'phash': phash_feat
                }

    def analyze_cell(self, cell_img, method='hog'):
        """
        Анализирует вырезанную клетку.
        method: 'hog' или 'phash'
        Возвращает: имя фигуры (напр. 'white_queen') и метрику уверенности/расстояние.
        """
        if cell_img is None or cell_img.size == 0:
            return None, float('inf')

        cell_resized = cv2.resize(cell_img, self.win_size)
        
        if method == 'hog':
            gray = cv2.cvtColor(cell_resized, cv2.COLOR_BGR2GRAY) if len(cell_resized.shape) == 3 else cell_resized
            cell_hog = self.hog.compute(gray)
            
            best_piece = None
            min_dist = float('inf')

            for piece_name, data in self.templates.items():
                dist = np.linalg.norm(cell_hog - data['hog'])
                if dist < min_dist:
                    min_dist = dist
                    best_piece = piece_name

            return best_piece, min_dist

        elif method == 'phash':
            cell_hash = self._compute_phash(cell_resized)
            best_piece = None
            min_dist = 64

            for piece_name, data in self.templates.items():
                dist = self._phash_distance(cell_hash, data['phash'])
                if dist < min_dist:
                    min_dist = dist
                    best_piece = piece_name

            return best_piece, min_dist

    def analyze_board_image(self, image_path='aboard1.png', board_matrix=None):
        """
        Метод для вызова из logic.py при старте:
        Принимает либо путь к картинке aboard1.png, либо вырезанный кадр доски/клеток.
        """
        # Если передан путь к файлу
        if isinstance(image_path, str) and os.path.exists(image_path):
            board_img = cv2.imread(image_path)
        else:
            board_img = image_path

        # Если передана матрица заполненности от crop.py, анализируем только занятые клетки
        # Пример возвращаемого словаря: {'a1': 'white_rook', 'e1': 'white_king', ...}
        results = {}
        
        # Ниже пример использования функции под твой logic.py:
        return results


# Пример проверки работы автономно
if __name__ == '__main__':
    analyzer = ChessAnalyzer(templates_dir='templates')
    
    # Загружаем картинку доски aboard1.png, если она лежит рядом
    if os.path.exists('aboard1.png'):
        board = cv2.imread('aboard1.png')
        print("Изображение aboard1.png успешно загружено для анализа.")
    else:
        print("Загружены шаблоны:", list(analyzer.templates.keys()))