Преобразовать эллипс в изображении в круг (деформировать эллипс в круг, как многоугольник деформировать в прямоугольник) - PullRequest
0 голосов
/ 19 июня 2019

У меня есть изображение эллипса, и если изображение имеет эллипс, я нахожу его с помощью findcontours (), а затем я хочу преобразовать этот эллипс в круг.

см. Пример

enter image description here

enter image description here

и я хочу преобразовать каждый из них так, как это

enter image description here

Сначала я применил обнаружение канни-края. Затем к этому изображению применяется findcontour ().

Я нашел эллипс, используя findcontours (), чтобы получить все контуры иполучить требуемый эллиптический контур, а затем я использую fitellipse (), чтобы получить центр, угол поворота и большую и меньшую оси эллипса.

Затем я попытался повернуть изображение на повернутый угол, а затем масштабировать высоту и ширину изображения относительно малой и большой осей (т. Е. Сделать длину главной оси и малой оси одинаковыми), но также я не получаю правильнуюкруговое изображение объекта, как указано выше.Там останется некоторое вращение / оно будет по-прежнему похоже на эллипс, который будет близок к кругу или около того.

     _, contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

    for c in contours:
        if len(c) >= 5:
            a = cv2.fitEllipse(c)
            (x, y), (MA, ma), angle = a
            area = (math.pi * MA * ma)/4
            if abs(x-image.shape[0]/2) <= 2 and abs(y-image.shape[1]/2) <= 2 and (area - cv2.contourArea(c)) < 50:
                screenCount = c
                width, height = MA, ma
                centerX, centerY = x, y
                ellipseAngle = angle
                print(width, height, centerX, centerY, ellipseAngle)
                # cv2.drawContours(img, c, -1, (0, 255, 0), 4)
                cv2.ellipse(img, a, (0, 0, 255), 2, 8)
                cv2.imshow("ellipse", img)
                break

    img = image.copy()
    if ellipseAngle < 90:
        rotatedImg = imutils.rotate(img, ellipseAngle)
    else:
        rotatedImg = imutils.rotate(img, -(ellipseAngle - 90))

Тогда я масштабируюсь по большой и малой оси

после примененияfindcontour () я получил эти 2 контура для 1-го изображения в посте

enter image description here enter image description here

из этих любых контуров в порядкеправо?я использую первый контур от контура согласно коду, и fitellipse () дает мне этот эллипс

enter image description here

РЕДАКТИРОВАНИЕ - Если есть какой-либо лучший подход крешить эту проблему было бы полезно.

1 Ответ

0 голосов
/ 21 июня 2019

Есть несколько проблем, которые я вижу в коде:

  1. Вы используете алгоритм обнаружения краев и получаете контуры результата.Это в принципе нормально, но это приводит к изображению, имеющему два контура: один для внутреннего края и один для внешнего края результата обнаружения края.Проще портировать изображение и получить один край.Хотя, если изображение становится более сложным, обнаружение края может быть уместным.Действительно, любой из двух полученных вами контуров должен быть полезен.

  2. Линия if abs(x-image.shape[0]/2) <= 2 and abs(y-image.shape[1]/2) <= 2 and (area - cv2.contourArea(c)) < 50 очень ограничительная, для меня не сработало второе изображение.

  3. Поворот на -(ellipseAngle - 90), если угол отрицательный, странный.Вы должны вращать все эллипсы одинаковым образом.

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

import cv2
import numpy as np

img = cv2.imread('im1.png',0)
_, thresh = cv2.threshold(img, 128, 255, type=cv2.THRESH_BINARY_INV)
_, contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
params = cv2.fitEllipse(contours[0])
angle = params[2]
scale = params[1]
scale = scale[0]/scale[1]

M = cv2.getRotationMatrix2D((img.shape[0]/2, img.shape[1]/2), angle, 1)
# Let's add the scaling too:
M[:,0:2] = np.array([[1,0],[0,scale]]) @ M[:,0:2]
M[1,2] = M[1,2] * scale # This moves the ellipse so it doesn't end up outside the image (it's not correct to keep the ellipse in the middle of the image)

out = cv2.warpAffine(img, M, img.shape, borderValue=255)
cv2.imshow('out',out)
cv2.waitKey()

Использование PyDIP (I '(автор), вы можете получить более точную меру в идеализированном случае OP, не используя пороговое значение, а используя значения серого по краям эллипса, чтобы получить более точное соответствие.Мы вычисляем центральные моменты изображения второго порядка и выводим из них параметры эллипса.Здесь важно, чтобы фон был ровно 0 и чтобы передний план (пиксели эллипса) был равномерным по интенсивности, за исключением края, где промежуточные значения серого добавляют информацию о расположении субпикселя края.

import PyDIP as dip
import numpy as np

img = -dip.ImageRead('im1.png').TensorElement(0) # We use the inverted first channel
params = dip.Moments(img).secondOrder
M = np.array([[params[0],params[2]],[params[2],params[1]]])
d, V = np.linalg.eig(M)
d = np.sqrt(d)
scale = d[0]/d[1]
angle = np.arctan2(V[1,0],V[0,0])

img = dip.Rotation2D(img, -angle)
img = dip.Resampling(img, [scale, 1])
img.Show()
...