Использование гомогенных преобразований (неаффинных) с патчами matplotlib

У меня есть приложение, в котором я использую matplotlib для отображения эллиптических областей на изображении. Для этого я использую mpl.patches.Circle вместе с mp.patches.Affine2D, чтобы деформировать единичные круги в эллиптическую форму.

import numpy as np
import matplotlib as mpl
import pyplot as plt

invVR_mats = np.array([
   [[   7.80247545,    0.        ,   92.9254837 ],
    [  -3.46026921,   10.85727882,   17.53866959],
    [   0.        ,    0.        ,    1.        ]],

   [[  11.42656994,    0.        ,   76.86006927],
    [  -3.26515651,    9.61946297,   24.79440498],
    [   0.        ,    0.        ,    1.        ]],

   [[  10.40444851,    0.        ,  140.62428284],
    [ -10.94557095,   10.59212685,   24.91024971],
    [   0.        ,    0.        ,    1.       ]],])

invVR_aff2Ds = [mpl.transforms.Affine2D(invVR)
                for invVR in invVR_mats]
ell_actors = [mpl.patches.Circle((0, 0), 1, transform=invVR)
              for invVR in invVR_aff2Ds]
coll = mpl.collections.PatchCollection(ell_actors) 

plt.figure()
ax = plt.gca()
ax.set_ylim(0, 100)
ax.set_xlim(0, 300)

ax.add_collection(coll)

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

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

from numpy.core.umath_tests import matrix_multiply
H = np.array([[ -0.70098,   0.12273,   5.18734],
              [  0.12444,  -0.63474,  14.13995],
              [  0.00004,   0.00025,  -0.64873]]) 

HinvVR_mats = matrix_multiply(H, invVR_mats)
print(HinvVR_mats)
#---------
np.array([
   [[ -5.89405808e+00,   1.33251383e+00,  -5.77990446e+01],
    [  3.16731132e+00,  -6.89154916e+00,   1.45711021e+01],
    [ -5.52968284e-04,   2.71431970e-03,  -6.40628313e-01]],

   [[ -8.41052966e+00,   1.18059669e+00,  -4.56470140e+01],
    [  3.49444781e+00,  -6.10585793e+00,   7.96641640e+00],
    [ -3.59226330e-04,   2.40486574e-03,  -6.39456996e-01]],

   [[ -8.63666024e+00,   1.29997173e+00,  -9.03302348e+01],
    [  8.24232128e+00,  -6.72324660e+00,   1.58277039e+01],
    [ -2.32021480e-03,   2.64803171e-03,  -6.36877466e-01]]])

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

До сих пор лучшее, что я сделал, это просто де-гомогенизация последнего столбца и игнорирование значений в [:, 2, 0] и [:, 2, 1]

HinvVR_mats = np.divide(HinvVR_mats , HinvVR_mats[:, None, None, 2, 2])
print(HinvVR_mats)

array([[[  9.20043332e+00,  -2.08001083e+00,   9.02224323e+01],
    [ -4.94407015e+00,   1.07574845e+01,  -2.27450173e+01],
    [  8.63165541e-04,  -4.23696494e-03,   1.00000000e+00]],

   [[  1.31526118e+01,  -1.84624877e+00,   7.13840248e+01],
    [ -5.46471120e+00,   9.54850438e+00,  -1.24580956e+01],
    [  5.61767769e-04,  -3.76079354e-03,   1.00000000e+00]],

   [[  1.35609449e+01,  -2.04116458e+00,   1.41832989e+02],
    [ -1.29417694e+01,   1.05565779e+01,  -2.48520394e+01],
    [  3.64311021e-03,  -4.15783546e-03,   1.00000000e+00]]])

Есть ли способ преобразовать mpl.patches.Circle (или любой другой патч, если на то пошло), используя неаффинную матрицу. Документация, кажется, предполагает, что это возможно, но я не вижу никакого способа сделать это.

у меня есть


person Erotemic    schedule 09.02.2015    source источник
comment
Я недостаточно хорошо разбираюсь в стеке преобразований, но mpl поддерживает неаффинные преобразования matplotlib. org/users/transforms_tutorial.html — неплохое место для начала.   -  person tacaswell    schedule 09.02.2015


Ответы (1)


Я смог решить эту проблему, посмотрев учебник, опубликованный tcaswell.

Мне пришлось создать свой собственный класс трансформации, который выглядел так:

class HomographyTransform(mpl.transforms.Transform):
    """
    References: 
        http://stackoverflow.com/questions/28401788/using-homogeneous-transforms-non-affine-with-matplotlib-patches?noredirect=1#comment45156353_28401788
        http://matplotlib.org/users/transforms_tutorial.html
    """
    input_dims = 2
    output_dims = 2
    is_separable = False

    def __init__(self, H, axis=None, use_rmin=True):
        mpl.transforms.Transform.__init__(self)
        self._axis = axis
        self._use_rmin = use_rmin
        self.H = H

    def transform_non_affine(self, input_xy):
        """
        The input and output are Nx2 numpy arrays.
        """
        import vtool as vt
        _xys = input_xy.T
        xyz  = vt.add_homogenous_coordinate(_xys)
        xyz_t = vt.matrix_multiply(self.H, xyz)
        xy_t  = vt.remove_homogenous_coordinate(xyz_t)
        output_xy = xy_t.T
        return output_xy
    #transform_non_affine.__doc__ = mpl.transforms.Transform.transform_non_affine.__doc__

    def transform_path_non_affine(self, path):
        vertices = path.vertices
        if len(vertices) == 2 and vertices[0, 0] == vertices[1, 0]:
            return mpl.path.Path(self.transform(vertices), path.codes)
        ipath = path.interpolated(path._interpolation_steps)
        return mpl.path.Path(self.transform(ipath.vertices), ipath.codes)
    #transform_path_non_affine.__doc__ = mpl.transforms.Transform.transform_path_non_affine.__doc__

Функции, вызываемые моей собственной библиотекой vtool:

def add_homogenous_coordinate(_xys):
    assert _xys.shape[0] == 2
    _zs = np.ones((1, _xys.shape[1]), dtype=_xys.dtype)
    _xyzs = np.vstack((_xys, _zs))
    return _xyzs


def remove_homogenous_coordinate(_xyzs):
    assert _xyzs.shape[0] == 3
    _xys = np.divide(_xyzs[0:2], _xyzs[None, 2])
    return _xys

и matrix_multiply — это тот же самый matrix_multiply, который использовался ранее.

и моя функция для создания матриц преобразования в настоящее время выглядит так:

def get_invVR_aff2Ds(kpts, H=None):
    """ Returns matplotlib keypoint transformations (circle -> ellipse) """
    #invVR_mats = ktool.get_invV_mats(kpts, with_trans=True, with_ori=True)
    invVR_mats = ktool.get_invVR_mats3x3(kpts)
    if H is None:
        invVR_aff2Ds = [mpl.transforms.Affine2D(invVR)
                        for invVR in invVR_mats]
    else: 
        # not actually affine
        invVR_aff2Ds = [HomographyTransform(H.dot(invVR))
                        for invVR in invVR_mats]
    return invVR_aff2Ds
person Erotemic    schedule 09.02.2015