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


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} не найден.")