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


import cv2
import numpy as np


def crop_chess_board(
    input_path="board.png", output_path="cropped_board.png"
):
    img = cv2.imread(input_path)
    if img is None:
        print(f"Ошибка: Не удалось открыть файл '{input_path}'.")
        return

    img_h, img_w = img.shape[:2]
    total_area = img_h * img_w

    # 1. Перевод в оттенки серого
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # 2. Адаптивный порог (отлично выделяет границы шахматных клеток)
    thresh = cv2.adaptiveThreshold(
        gray,
        255,
        cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
        cv2.THRESH_BINARY_INV,
        11,
        2,
    )

    # 3. Морфологическое "закрытие" — объединяем стоящие рядом клетки и фигуры
    # в один плотный сплошной блок
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
    closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)

    # 4. Поиск контуров
    contours, _ = cv2.findContours(
        closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
    )

    if not contours:
        print("Контуры не найдены.")
        return

    # Сортируем контуры по площади
    contours = sorted(contours, key=cv2.contourArea, reverse=True)

    best_box = None

    for c in contours:
        x, y, w, h = cv2.boundingRect(c)
        area = w * h

        # Отбрасываем мелочь (< 3% экрана) и сам браузер/экран (> 95% экрана)
        if area < (total_area * 0.03) or area > (total_area * 0.95):
            continue

        aspect_ratio = float(w) / h

        # Доска должна быть близкой к квадрату (0.85 ... 1.15)
        if 0.85 <= aspect_ratio <= 1.15:
            best_box = (x, y, w, h)
            break

    # 5. Если по закрытию не нашли, пробуем fallback по Canny без жестких условий
    if best_box is None:
        edges = cv2.Canny(gray, 50, 150)
        contours, _ = cv2.findContours(
            edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE
        )
        contours = sorted(contours, key=cv2.contourArea, reverse=True)

        for c in contours:
            x, y, w, h = cv2.boundingRect(c)
            area = w * h
            if (
                area > (total_area * 0.05)
                and area < (total_area * 0.90)
                and (0.85 <= float(w) / h <= 1.15)
            ):
                best_box = (x, y, w, h)
                break

    if best_box is None:
        print("Не удалось найти доску.")
        return

    x, y, w, h = best_box
    cropped_img = img[y : y + h, x : x + w]
    cv2.imwrite(output_path, cropped_img)
    print(f"Успешно! Доска сохранена в '{output_path}'.")


if __name__ == "__main__":
    crop_chess_board()