OpenCV Python: аппроксимация замкнутого контура для формы речи пузыря

У меня есть форма, похожая на речевой пузырь. И я хочу только обнаружить эллипс этой формы, как на изображении с зеленым кружком.

Я пытался с закрытой морфологией, но некоторые части пузырьков также удаляются. Я использовал Ядро с матрицей 20, 20. Форма становится более прямоугольной. Может быть, мне нужно изменить матрицу ядра, например, так:

0 1 0
1 1 1
0 1 0

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

for i in range (max_index):
    hull = cv2.convexHull(contours[i])
    cv2.drawContours(image, [hull], 0, (0, 255, 0), 2)

Я получил контуры с параметрами cv2.RETR_EXTERNAL а также cv2.CHAIN_APPROX_NONE

1 ответ

Решение

Это лучшее, что я смог получить: Баллон эллипс

Это не самый умный способ сделать это. То, что я делаю здесь, на самом деле просто, несмотря на подробный код.

Во-первых, я получаю серое изображение и добавляю много размытия и так же, как вы пытались, применить порог и найти контуры. Затем я беру самый большой контур и нахожу эллипс, который соответствует этому контуру с fitEllipse, Это все в getEllipse функция.

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

Функция grayEllipse фильтрует изображение по эллипсу. Итак, я использую эллипс с первой попытки, чтобы обработать исходное изображение и выделить точки внутри первого эллипса. Я использую это изображение в качестве ввода во втором раунде.

Повторяя процесс, последний эллипс, который я получаю во второй раз, гораздо менее искажен.

Вот код:

import cv2
import numpy as np


def getEllipse(imgray):


    ret, thresh = cv2.threshold(imgray, 20, 255, cv2.THRESH_BINARY|cv2.THRESH_OTSU)
    _, contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

    maxArea = 0
    best = None
    for contour in contours:
        area = cv2.contourArea(contour)
        if area > maxArea :
            maxArea = area
            best = contour

    ellipse = cv2.fitEllipse(best)
    el = np.zeros(imgray.shape)
    cv2.ellipse(el, ellipse,(255,255,255),-1)

    return el

def grayEllipse(el, img):
    el = np.dstack((el,el,el))
    el = el*img
    el = el/(255)
    el = el.astype('uint8')
    imgray = cv2.cvtColor(el, cv2.COLOR_BGR2LAB)[...,0]
    return imgray


image = cv2.imread("./baloon.png", cv2.IMREAD_COLOR)
img = image.copy()
imgray = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)[...,0]
imgray = cv2.GaussianBlur(imgray, (79,79), 0)
el = getEllipse(imgray)
imgray = grayEllipse(el, img.copy())
imgray = cv2.GaussianBlur(imgray, (11,11), 0)
el = getEllipse(imgray)
imgray = grayEllipse(el, img.copy())

ret, thresh = cv2.threshold(imgray, 20, 255, cv2.THRESH_BINARY|cv2.THRESH_OTSU)
_, contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

maxArea = 0
best = None
for contour in contours:
    area = cv2.contourArea(contour)
    if area > maxArea :
        maxArea = area
        best = contour

ellipse = cv2.fitEllipse(best)
cv2.ellipse(image, ellipse, (0,255,0),3)

while True:
  cv2.imshow("result", image)
  k = cv2.waitKey(30) & 0xff
  if k == 27:
      break
Другие вопросы по тегам