Загрузка данных
import os
import cv2
import numpy as np
def check_cell_has_piece(cell_gray, threshold=20.0):
"""Проверяет наличие фигуры в клетке путем анализа контрастности (разброса
цветов) вдоль центрального креста клетки.
"""
h, w = cell_gray.shape
if h < 8 or w < 8:
return False
mid_y, mid_x = h // 2, w // 2
# Отступ от краев клетки (15%), чтобы случайно не захватить внешнюю сетку
margin_x = int(w * 0.15)
margin_y = int(h * 0.15)
# Берем срез пикселей по вертикали и горизонтали (крест)
row_pixels = cell_gray[mid_y, margin_x : w - margin_x]
col_pixels = cell_gray[margin_y : h - margin_y, mid_x]
# Объединяем пиксели креста в один массив
cross_pixels = np.concatenate([row_pixels, col_pixels])
# Вычисляем стандартное отклонение (показатель контрастности)
std_dev = float(np.std(cross_pixels))
# Если контрастность превышает порог — внутри есть фигура
return std_dev > threshold
def save_human_readable_board(board_matrix, output_txt="human.txt"):
"""Записывает текстовую доску 8x8 с символами [X] и [ ] в файл."""
with open(output_txt, "w", encoding="utf-8") as f:
for row in board_matrix:
line = "".join(["[X]" if cell else "[ ]" for cell in row])
f.write(line + "\n")
print(f"[OK] Визуальная схема доски сохранена в: {output_txt}")
def save_board_cells(board_size, txt_path="Boardcells.txt"):
"""Записывает координаты 64 клеток относительно обрезанного скриншота."""
cell_size = board_size / 8.0
with open(txt_path, "w", encoding="utf-8") as f:
cell_idx = 1
for row in range(8):
for col in range(8):
x = int(round(col * cell_size))
y = int(round(row * cell_size))
z = int(round((col + 1) * cell_size))
w = int(round((row + 1) * cell_size))
f.write(f"cells_{cell_idx}: {x}, {y}, {z}, {w}\n")
cell_idx += 1
print(f"[OK] Координаты клеток сохранены в: {txt_path}")
def verify_chessboard_grid(gray_crop):
"""Проверяет наличие сетки 8x8 внутри найденного квадрата."""
h, w = gray_crop.shape
if h < 64:
return False, 0
edges = cv2.Canny(gray_crop, 40, 120)
col_sums = np.sum(edges, axis=0)
row_sums = np.sum(edges, axis=1)
cell_size = w / 8.0
score_x = 0
score_y = 0
for i in range(1, 8):
idx = int(round(i * cell_size))
x_min, x_max = max(0, idx - 2), min(w, idx + 3)
y_min, y_max = max(0, idx - 2), min(h, idx + 3)
score_x += np.max(col_sums[x_min:x_max]) if x_max > x_min else 0
score_y += np.max(row_sums[y_min:y_max]) if y_max > y_min else 0
total_score = score_x + score_y
return True, total_score
def find_chessboard_strictly_1to1(
input_path="board1.png",
output_path="aboard1.png",
cells_path="Boardcells.txt",
human_path="human.txt",
):
img = cv2.imread(input_path)
if img is None:
print(f"[Ошибка] Не удалось загрузить {input_path}")
return False
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 30, 150)
contours, _ = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
best_board = None
max_score = -1
for cnt in contours:
x, y, w, h = cv2.boundingRect(cnt)
if w < 80 or h < 80:
continue
aspect_ratio = float(w) / h
if not (0.98 <= aspect_ratio <= 1.02):
continue
size = min(w, h)
crop = gray[y : y + size, x : x + size]
is_grid, score = verify_chessboard_grid(crop)
if is_grid and score > max_score:
max_score = score
best_board = (x, y, size)
if best_board is None:
print(f"[Ошибка] Квадратная доска 1*1 не найдена в {input_path}")
return False
bx, by, size = best_board
cropped_board = img[by : by + size, bx : bx + size]
cropped_gray = gray[by : by + size, bx : bx + size]
# 1. Сохраняем обрезку
cv2.imwrite(output_path, cropped_board)
print(f"[OK] {input_path} -> {output_path} | Размер: {size}x{size} px")
# 2. Сохраняем координаты всех клеток
save_board_cells(size, cells_path)
# 3. Анализируем каждую клетку на наличие фигур
cell_size = size / 8.0
board_matrix = []
for row in range(8):
row_status = []
for col in range(8):
x1 = int(round(col * cell_size))
y1 = int(round(row * cell_size))
x2 = int(round((col + 1) * cell_size))
y2 = int(round((row + 1) * cell_size))
cell_crop = cropped_gray[y1:y2, x1:x2]
has_piece = check_cell_has_piece(cell_crop, threshold=30.0)
row_status.append(has_piece)
board_matrix.append(row_status)
# 4. Сохраняем схему доски для человека
save_human_readable_board(board_matrix, human_path)
return True
if __name__ == "__main__":
input_file = "board1.png"
output_file = "aboard1.png"
if os.path.exists(input_file):
find_chessboard_strictly_1to1(input_file, output_file)
else:
print(f"Файл {input_file} не найден.")