Обнаружение кругов на фотографии с использованием HoughCircles

Здравствуйте! Делал прогу для распознавания количество круглых труб на фото, использовал cv2.HoughCircles, настраивал все параметры что бы отрегулировать распознание кругов:

circles = cv2.HoughCircles(
        image,
        cv2.HOUGH_GRADIENT,
        dp=1.2,
        minDist=20,  # Минимальное расстояние между центрами кругов
        param1=388,  # Порог для градиентного детектора
        param2=65,  # Порог для акцепта круга
        minRadius=5,  # Минимальный радиус круга
        maxRadius=95  # Максимальный радиус круга
    )

введите сюда описание изображения

Использовал эти же параметры для распознания труб на другой фотке, но там это работает совсем по другому, вот результат:

введите сюда описание изображения

Помогите разобраться пожалуйста??

Исходный код:

import cv2
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split


def load_data(annotation_file):
    data = pd.read_csv(annotation_file)
    image_paths = data['img_path'].tolist()
    pipe_counts = data['pipe_count'].tolist()
    return image_paths, pipe_counts


def preprocess_image(image_path):
    """
    Предобработка изображения: преобразование в градации серого и размытие.
    """
    image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
    blurred = cv2.GaussianBlur(image, (7, 7), 1)  # Попробуйте разные размеры
    return blurred


def detect_circles(image):
    """
    Обнаружение кругов на изображении с использованием Hough Circle Transform.
    """
    circles = cv2.HoughCircles(
        image,
        cv2.HOUGH_GRADIENT,
        dp=1.2,
        minDist=20,  # Минимальное расстояние между центрами кругов
        param1=388,  # Порог для градиентного детектора
        param2=65,  # Порог для акцепта круга
        minRadius=5,  # Минимальный радиус круга
        maxRadius=95  # Максимальный радиус круга
    )

    if circles is not None:
        circles = np.round(circles[0, :]).astype("int")

        # Фильтрация кругов по радиусу
        filtered_circles = [circle for circle in circles if 10 < circle[2] < 100]

        # Опциональная дополнительная фильтрация для обеспечения полноты круга
        valid_circles = []
        for (x, y, r) in filtered_circles:
            if is_complete_circle(image, x, y, r):
                valid_circles.append((x, y, r))

        return np.array(valid_circles)

    return []


def is_complete_circle(image, x, y, r):
    """
    Проверка, является ли обнаруженный круг полноценным, а не частичным.
    """
    # Определение области изображения, содержащей круг
    mask = np.zeros_like(image, dtype=np.uint8)
    cv2.circle(mask, (x, y), r, 255, -1)

    # Получение пикселей круга
    circle_pixels = cv2.bitwise_and(image, mask)

    # Проверка, что круг заполнен (более 50% пикселей круга должны быть белыми)
    circle_area = np.sum(mask > 0)
    filled_area = np.sum(circle_pixels > 0)

    return filled_area / circle_area > 0.5


def split_data(image_paths, pipe_counts, test_size=0.2):
    return train_test_split(image_paths, pipe_counts, test_size=test_size, random_state=42)


def extract_features(image_paths):
    images = [preprocess_image(image_path) for image_path in image_paths]
    features = [len(detect_circles(image)) for image in images]
    return np.array(features).reshape(-1, 1)


def draw_circles(image_path, circles):
    """
    Рисование обнаруженных кругов на изображении.
    """
    image = cv2.imread(image_path)
    for (x, y, r) in circles:
        cv2.circle(image, (x, y), r, (0, 255, 0), 2)  # Рисуем круги
        cv2.rectangle(image, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1)  # Рисуем центр
    cv2.imshow('Detected Circles', image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

Ответы (1 шт):

Автор решения: MBo

Круги, наблюдаемые под углом - эллипсы, причём их эксцентриситет меняется по мере изменения угла зрения на торец трубы

Чтобы обнаружить эллипсы, попробуйте SimpleBlobDetector или выделить контуры и подогнать их эллипсами, фильтруя по нужным параметрам

→ Ссылка