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


import cv2
import numpy as np


def crop_chess_board(
    input_path="board.png", output_path="cropped_board.png"
):
    # 1. Загрузка изображения
    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

    # 2. Подготовка изображения
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    blurred = cv2.GaussianBlur(gray, (5, 5), 0)
    edges = cv2.Canny(blurred, 50, 150)

    # 3. Поиск всех контуров
    contours, _ = cv2.findContours(
        edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
    )

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

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

    board_contour = None

    # 4. Поиск именно шахматной доски
    for c in contours:
        area = cv2.contourArea(c)

        # Отсеиваем слишком мелкие элементы (< 5% экрана)
        # и слишком большие (например, всё окно браузера > 90% экрана)
        if area < (total_area * 0.05) or area > (total_area * 0.90):
            continue

        peri = cv2.arcLength(c, True)
        approx = cv2.approxPolyDP(c, 0.02 * peri, True)

        # Ищем четырёхугольник
        if len(approx) == 4:
            x, y, w, h = cv2.boundingRect(approx)
            aspect_ratio = float(w) / h

            # Шахматная доска — это квадрат!
            # Допускаем погрешность в 10% (соотношение сторон от 0.9 до 1.1)
            if 0.9 <= aspect_ratio <= 1.1:
                board_contour = approx
                break

    # 5. Если идеальный квадрат не найден, берем fallback-вариант с фильтром по квадрату
    if board_contour is None:
        print("Предупреждение: Чёткий квадратный контур не найден.")
        print("Пробуем найти ближайшую подходящую область...")

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

            # Фильтруем просто по соотношению сторон boundingRect
            if (
                0.85 <= aspect_ratio <= 1.15
                and area > (total_area * 0.05)
            ):
                x, y, w, h = cv2.boundingRect(c)
                cropped_img = img[y : y + h, x : x + w]
                cv2.imwrite(output_path, cropped_img)
                print(f"Доска (резервный метод) сохранена в '{output_path}'.")
                return

        print("Не удалось выделить шахматную доску на изображении.")
        return

    # 6. Вырезаем найденную область и сохраняем
    x, y, w, h = cv2.boundingRect(board_contour)
    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()