Линейная регрессия по эллипсу показывает неожиданное поведение - PullRequest
0 голосов
/ 26 февраля 2019

Я рисую 2D-эллипс на пустом изображении.Теперь я хочу провести линию через эллипс, чтобы получить большую ось.Зная, что существует множество вариантов (PCA, моменты изображения и т. Д.), Я подумал, что линейная регрессия должна сделать эту работу.Однако, это только «работает», если вращение эллипса параллельно оси x.Почему это?Разве любое симметричное облако точек, которое распределено одинаково, не дает среднюю линию?

Это код, который я использовал:

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from skimage.draw import ellipse
from ipywidgets import interact
from sklearn.linear_model import LinearRegression

@interact
def rotateAndFit(rot:(-90,90)=-90):
    im = np.zeros((300,300), dtype=np.float64)
    im[ellipse(im.shape[0]//2, # center x
               im.shape[1]//2-10, # center y
               120,            # radius major axis
               40,             # radius minor axis
               im.shape,       # image shape
               rot/180*np.pi)] = 1  # rotation angle in degree,


    # Get corresponding x and y values
    y, x = np.where(im)

    # Do Linear Regression
    lr = LinearRegression()
    lr.fit(x[None].T,y)

    plt.imshow(im)
    plt.plot([0, 300], [lr.intercept_, lr.coef_[0]*300+lr.intercept_])
    plt.axis([0,300,300,0])
    plt.title('rotation $r = {}°$'.format(rot))

Код обеспечивает следующий вывод:

Rotation of ellipse and corresponding linear fit

Я действительно смущен, есть идеи?Я использовал гребень и регрессию лассо, чтобы отрегулировать веса, но они понижают веса, но кажется, что веса, то есть наклон должен быть круче, я думаю, что линейная регрессия недооценивает наклон.Интересно, что линейная регрессия часто является своего рода «точечной» симметрией, но не симметричной по всей линии ... Я понимаю, что поведение близко к 0 °, наклон не может быть бесконечным.Но это должно по крайней мере работать для низкой степени вращения.

Ответы [ 2 ]

0 голосов
/ 26 февраля 2019

Чтобы добавить к ответу выше, вот схематическое изображение того, что вы делаете, используя OLS с точками эллипса.Поскольку у вас есть две точки в каждом x, вы по существу находите среднее значение y в каждом x.Для не повернутого эллипса (верхний эллипс на рисунке) это работает, как вы ожидали.Но когда вы вращаете эллипс (нижний эллипс) в заданном x, точка на полпути между двумя точками на эллипсе находится далеко от главной оси эллипса.Так что да, вы должны минимизировать ортогональность к оси вращения.

schematic result of an OLS regression for points of an ellipse

0 голосов
/ 26 февраля 2019

Линия восстановления не может совпадать с главной осью, поскольку регрессия минимизируется в направлении y, а не перпендикулярно линии регрессии.В следующем примере используется регрессия ортогонального расстояния вместо линейной регрессии по y, и она дает желаемый результат:

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from skimage.draw import ellipse
from ipywidgets import interact
from sklearn.linear_model import LinearRegression
from scipy.odr import ODR, Model, Data

def lin(beta, x):
    a,b = beta
    return a*x+b

@interact(rot=(-90,90))
def rotateAndFit(rot=-90):
    im = np.zeros((300,300), dtype=np.float64)
    im[ellipse(im.shape[0]//2, # center x
               im.shape[1]//2-10, # center y
               120,            # radius major axis
               40,             # radius minor axis
               im.shape,       # image shape
               rot/180*np.pi)] = 1  # rotation angle in pi (40°),


    y, x = np.where(im)

    d = Data(x,y)
    m = Model(lin)
    o = ODR(d, m, [0,0])
    out = o.run()
    a,b = out.beta

    plt.imshow(im)
    plt.plot([0, 300], [b, a*300+b])
    plt.axis([0,300,300,0])
    plt.title('rotation $r = {}°$'.format(rot))
...