OpenCV: установить эллипс с большинством точек на контуре (вместо наименьших квадратов) - PullRequest
1 голос
/ 29 апреля 2019

У меня есть бинаризованное изображение, на котором я уже использовал морфологические операции открытия / закрытия (это настолько чисто, насколько я могу его себе представить, поверьте мне), которое выглядит так: enter image description here

Как видите, существует очевидный эллипс с некоторым искажением сверху. ПРИМЕЧАНИЕ. У меня нет предварительной информации о размере круга, и он должен выполняться очень быстро (HoughCircles слишком медленный, я обнаружил). Я пытаюсь выяснить, какподогнать к нему эллипс так, чтобы он максимально увеличил количество точек на подогнанном эллипсе, которые соответствуют ребрам формы.То есть я хочу получить такой результат: enter image description here

Однако я не могу найти способ сделать это в OpenCV.Используя общие инструменты fitEllipse (синяя линия) и minAreaRect (зеленая линия), я получаю следующие результаты: enter image description here

которые, очевидно, не представляют действительный эллипс Iпытаюсь обнаружить.Любые мысли о том, как я мог бы сделать это?Рад видеть примеры на Python или C ++.

Ответы [ 2 ]

1 голос
/ 30 апреля 2019

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

, на котором я уже использовал морфологические операции открытия / закрытия (это настолько чисто, насколько я могу это понять,поверьте мне в этом)

И, прочитав ваш комментарий,

Для точности мне нужно, чтобы он соответствовал с точностью около 2 пикселей

Я был почти уверен, что может быть хорошее приближение с использованием морфологических операций.

Пожалуйста, взгляните на следующий код:

import cv2

# Load image (as BGR for later drawing the circle)
image = cv2.imread('images/hvFJF.jpg', cv2.IMREAD_COLOR)

# Convert to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# Get rid of possible JPG artifacts (when do people learn to use PNG?...)
_, gray = cv2.threshold(gray, 128, 255, cv2.THRESH_BINARY)

# Downsize image (by factor 4) to speed up morphological operations
gray = cv2.resize(gray, dsize=(0, 0), fx=0.25, fy=0.25)

# Morphological Closing: Get rid of the hole
gray = cv2.morphologyEx(gray, cv2.MORPH_CLOSE, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)))

# Morphological opening: Get rid of the stuff at the top of the circle
gray = cv2.morphologyEx(gray, cv2.MORPH_OPEN, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (121, 121)))

# Resize image to original size
gray = cv2.resize(gray, dsize=(image.shape[1], image.shape[0]))

# Find contours (only most external)
cnts, _ = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

# Draw found contour(s) in input image
image = cv2.drawContours(image, cnts, -1, (0, 0, 255), 2)

cv2.imwrite('images/intermediate.png', gray)
cv2.imwrite('images/result.png', image)

Промежуточное изображение выглядит так:

Intermediate

И, конечный результат выглядит так:

Result

СЯ думаю, что ваш имидж довольно велик, если его уменьшить, то это не повредит.Ускорены следующие морфологические операции, которые могут представлять интерес для вашей обстановки.

Согласно вашему заявлению:

ПРИМЕЧАНИЕ: У меня нет предварительной информации о размере круга [...]

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

Надеюсь, это поможет!

1 голос
/ 29 апреля 2019

Hough-Circle идеально подходит для этого.Если вы знаете диаметр, вы можете получить лучшее решение.Если вы знаете только диапазон, который может подойти лучше всего:

РЕДАКТИРОВАТЬ: причина, по которой это работает лучше, чем встроенный эллипс: Если вы ищете круг, вы должны использовать круг в качестве модели. статья вики объясняет эту прекрасную идею.

Кстати, вы могли бы сделать это и с открытием, и с закрытием.(Учитывая то, насколько велик ваш круг)

import skimage
import matplotlib.pyplot as plt
import numpy as np
from skimage import data, color
from skimage.feature import canny
from skimage.draw import circle_perimeter
from skimage.util import img_as_ubyte
from skimage.transform import hough_circle, hough_circle_peaks


image = skimage.io.imread("hvFJF.jpg")

# Load picture and detect edges

edges = canny(image, sigma=3, low_threshold=10, high_threshold=50)


# Detect two radii
hough_radii = np.arange(250, 300, 10)
hough_res = hough_circle(edges, hough_radii)

# Select the most prominent 5 circles
accums, cx, cy, radii = hough_circle_peaks(hough_res, hough_radii,
                                           total_num_peaks=3)

# Draw them
fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(10, 4))
image = color.gray2rgb(image)
for center_y, center_x, radius in zip(cy, cx, radii):
    circy, circx = circle_perimeter(center_y, center_x, radius)
    image[circy, circx] = (220, 20, 20)

ax.imshow(image, cmap=plt.cm.gray)
plt.show()

enter image description here

...