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 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):
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):
cell = cropped_board[row * 50:(row + 1) * 50, col * 50:(col + 1) * 50]
gray_cell = cv2.cvtColor(cell, cv2.COLOR_BGR2GRAY)
center_crop = cell[7:43, 7:43]
center_gray = gray_cell[7:43, 7:43]
if np.std(center_gray) < variance_threshold:
row_pieces.append('.')
continue
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)
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"