使用matplotlib补丁的同源变换(非仿射)

时间:2015-02-09 02:05:16

标签: python matrix matplotlib homography perspectivecamera

我有一个应用程序,我使用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)

在我的应用中有一点,使用单应矩阵将一个图像中的椭圆与来自第二图像的椭圆对应。到目前为止,我一直用它来将像素从image1转变为image2。

我希望能够直观地了解这些椭圆如何变成image2。我可以用这个单应矩阵来转换我的仿射矩阵,但得到的矩阵不再是仿射的。 (我相信它代表一般圆锥曲线,圆形,椭圆形,双曲线或抛物线)

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(或任何其他补丁)。文档似乎表明它是可能的,但我没有看到任何方法去做。

我有

1 个答案:

答案 0 :(得分:0)

我能够通过查看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