Как получить единственный прямоугольник минимальной площади на изображении с несколькими контурами с помощью cv2.minAreaRect(cnt)?

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

Как получить единственный прямоугольник минимальной площади на изображении с несколькими контурами с помощью cv2.minAreaRect(cnt)?

И получите этот результат с помощью cv2.minAreaRect(cnt):

Как получить единственный прямоугольник минимальной площади на изображении с несколькими контурами с помощью cv2.minAreaRect(cnt)?

Кажется, что это изображение разделено на несколько частей. Может быть, это потому, что на краю этого изображения есть точка останова. можете ли вы сказать мне, как использовать только один прямоугольник, чтобы покрыть этот круг моего изображения? Большое спасибо!

Это мой код:

def draw_min_rect_circle(img, cnts):  # conts = contours
    img = np.copy(img)

    for cnt in cnts:
        x, y, w, h = cv2.boundingRect(cnt)
        cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)  # blue

        min_rect = cv2.minAreaRect(cnt)  # min_area_rectangle
        min_rect = np.int0(cv2.boxPoints(min_rect))
        cv2.drawContours(img, [min_rect], 0, (0, 255, 0), 2)  # green

        (x, y), radius = cv2.minEnclosingCircle(cnt)
        center, radius = (int(x), int(y)), int(radius)  # center and radius of minimum enclosing circle
        img = cv2.circle(img, center, radius, (0, 0, 255), 2)  # red
return img

Конечно, можно было бы найти решение на предоставленном двоичном изображении, но я думаю, было бы лучше, если бы вы предоставили исходное входное изображение, так как может быть лучшее общее решение для вашей проблемы.

HansHirse 09.04.2019 10:05
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
1
6 341
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Что вам нужно сделать, так это то, что вам нужно каким-то образом получить только 1 контур из изображения путем слияния контуров, что немного сложно сделать, поэтому, если вам нужен только охватывающий прямоугольник вокруг всех контуров, вы можете сделать что-то как таковое

def draw_min_rect_circle(img, cnts):  # conts = contours
    img = np.copy(img)
    x1,y1 = np.inf
    x2,y2 = 0
    for cnt in cnts:
        x, y, w, h = cv2.boundingRect(cnt)
        if x > x1:
           x1=x
        if y > y1:
           y1=y
        if x2 < x+w
           x2 = x+w
        if y2 < y+h
           y2 = y+h
     w = x2 - x1
     h = y2 - y1
     r = math.sqrt((w*w) + (h*h)) / 2

     cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
     cv2.circle(img, (x1+w/2,y1+h/2), r, (0, 0, 255), 2)
Ответ принят как подходящий

Вы, вероятно, искали контуры с помощью cv2.findContours() и повторяли их, чтобы нарисовать прямоугольник на изображении. Проблема в том, что на вашем изображении круг состоит не из одной соединенной линии, а из множества ломаных линий.

Контуры — это кривые, соединяющие все непрерывные точки (вдоль границы), имеющие одинаковый цвет или интенсивность (документация OpenCV).

Поэтому, чтобы получить лучший результат, вы должны сначала подготовить изображение, прежде чем искать контуры. Вы можете использовать различные инструменты для предварительной обработки изображения (вы можете поискать в документации OpenCV). В этом случае я бы попробовал выполнить процедуру под названием «закрытие» с небольшим ядром. Закрытие — это расширение с последующей эрозией пикселей. Это может помочь соединить ваши маленькие контуры в один большой контур (круг). Затем вы можете выбрать самый большой и нарисовать ограничивающий прямоугольник.

Пример:

Входное изображение:

import cv2
import numpy as np

img = cv2.imread('test.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
kernel = np.ones((3,3), dtype=np.uint8)
closing = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
_, contours, hierarchy = cv2.findContours(closing, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(img, (x,y), (x+w, y+h), (255,255,0), 1)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Результат:

Изображение после выполнения операции закрытия:

Надеюсь, поможет. Ваше здоровье!

Это отличное решение. Метод удаления шума путем замыкания и повторения контуров для нахождения максимума прост, но очень эффективен.

nathancy 09.04.2019 22:05

Простые решения, если они работают, по моему опыту, являются лучшими решениями. Рад, что это помогло.

kavko 10.04.2019 05:57

@kavko Спасибо за помощь! Ваше решение работает. Это действительно отличное решение!

lixun 15.04.2019 03:25

Можно объединить все контуры в один контур, так как они представляют собой просто массивы координат точек, описывающих контур. Вы можете использовать np.concatenate(contours), и кажется, что функция cv2.minAreaRect не заботится о том, чтобы точки в новом массиве не были непрерывными. В моем случае это сработало лучше, чем использование функции закрытия, так как у меня более сложные объекты. Если хотите, можете попробовать, это просто. Вот как должна выглядеть ваша функция:

def draw_min_rect_circle(img, cnts):  # conts = contours
    img = np.copy(img)

    join_cnts = np.concatenate(cnts)

    x, y, w, h = cv2.boundingRect(join_cnts)
    cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)  # blue

    min_rect = cv2.minAreaRect(join_cnts)  # min_area_rectangle
    min_rect = np.int0(cv2.boxPoints(min_rect))
    cv2.drawContours(img, [min_rect], 0, (0, 255, 0), 2)  # green

    (x, y), radius = cv2.minEnclosingCircle(join_cnts)
    center, radius = (int(x), int(y)), int(radius)  # center and radius of minimum enclosing circle
    img = cv2.circle(img, center, radius, (0, 0, 255), 2)  # red
    
return img

Другие вопросы по теме