Загрузка данных
import os
import cv2
import numpy as np
def calculate_dhash(image, hash_size=8):
"""Вычисляет разностный хэш (dHash) для вырезки."""
# Приводим к оттенкам серого и урезаем до (hash_size + 1, hash_size)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) if len(image.shape) == 3 else image
resized = cv2.resize(gray, (hash_size + 1, hash_size))
# Сравниваем соседние пиксели по горизонтали
diff = resized[:, 1:] > resized[:, :-1]
return diff.flatten()
def hamming_distance(hash1, hash2):
"""Считает число несовпадающих бит между двумя хэшами."""
return np.count_nonzero(hash1 != hash2)
def get_top_crop(cell_img):
"""
Вырезает верхушку фигуры, минимизируя фон клетки.
Захватываем верхние 65% высоты и центральные 70% ширины.
"""
h, w = cell_img.shape[:2]
return cell_img[int(h * 0.05):int(h * 0.70), int(w * 0.15):int(w * 0.85)]
def load_templates(templates_folder="extracted_pieces"):
symbol_map = {
"white_K": "K", "white_Q": "Q", "white_R": "R", "white_B": "B", "white_N": "N", "white_P": "P",
"black_k": "k", "black_q": "q", "black_r": "r", "black_b": "b", "black_n": "n", "black_p": "p",
}
templates = {}
if not os.path.exists(templates_folder):
print(f"[!] Ошибка: Папка '{templates_folder}' не найдена!")
return templates
for filename in os.listdir(templates_folder):
if filename.endswith(".png"):
name_without_ext = os.path.splitext(filename)[0]
symbol = symbol_map.get(name_without_ext)
if not symbol:
continue
file_path = os.path.join(templates_folder, filename)
tpl_img = cv2.imread(file_path)
if tpl_img is not None:
top_part = get_top_crop(tpl_img)
templates[symbol] = calculate_dhash(top_part)
return templates
def generate_fen(board_matrix):
fen_rows = []
for row in board_matrix:
empty_count = 0
row_str = ""
for cell in row:
if cell == ".":
empty_count += 1
else:
if empty_count > 0:
row_str += str(empty_count)
empty_count = 0
row_str += cell
if empty_count > 0:
row_str += str(empty_count)
fen_rows.append(row_str)
return "/".join(fen_rows) + " w - - 0 1"
def scan_board(
board_path="board.png",
templates_folder="extracted_pieces",
max_hash_diff=18 # Порог допустимой разницы dHash (12 - 22)
):
templates = load_templates(templates_folder)
if not templates:
print("[!] Ошибка: Нет шаблонов для сравнения.")
return
board_img = cv2.imread(board_path)
if board_img is None:
print(f"[!] Ошибка: Файл '{board_path}' не найден.")
return
img_h, img_w, _ = board_img.shape
cell_w = img_w / 8.0
cell_h = img_h / 8.0
board_matrix = []
print("Сканирование формы верхушек через dHash...\n")
for row in range(8):
row_symbols = []
for col in range(8):
x1 = int(round(col * cell_w))
y1 = int(round(row * cell_h))
x2 = int(round((col + 1) * cell_w))
y2 = int(round((row + 1) * cell_h))
cell_crop = board_img[y1:y2, x1:x2]
cell_top = get_top_crop(cell_crop)
cell_hash = calculate_dhash(cell_top)
best_symbol = "."
min_dist = float("inf")
for symbol, tpl_hash in templates.items():
dist = hamming_distance(cell_hash, tpl_hash)
if dist < min_dist:
min_dist = dist
best_symbol = symbol
# Если наименьшая разница не превышает порог — фиксируем фигуру
if min_dist <= max_hash_diff:
row_symbols.append(best_symbol)
else:
row_symbols.append(".")
board_matrix.append(row_symbols)
# Отрисовка в консоли
divider = " +" + "---+" * 8
print(divider)
for i, row in enumerate(board_matrix):
rank_label = 8 - i
row_content = " | ".join(row)
print(f"{rank_label} | {row_content} |")
print(divider)
print(" a b c d e f g h\n")
# Генерация FEN
fen_string = generate_fen(board_matrix)
print(f"FEN: {fen_string}\n")
if __name__ == "__main__":
try:
scan_board()
except Exception as e:
print(f"\n[!] Ошибка: {e}")
input("\nНажмите Enter, чтобы закрыть программу...")