反转枕头图像库旋转的平移

问题描述 投票:0回答:1

我在这方面有点新手,尝试在Python枕头中旋转图像而不更改旋转图像中心的位置。或在枕头上旋转事物的外观...将中心返回到其原始旋转位置。

在枕头(Image.py)中,有一个旋转图像的功能。该函数如下:-

def rotate(
        self,
        angle,
        resample=NEAREST,
        expand=0,
        center=None,
        translate=None,
        fillcolor=None,
    ):
        """
        Returns a rotated copy of this image.  This method returns a
        copy of this image, rotated the given number of degrees counter
        clockwise around its centre.
        :param angle: In degrees counter clockwise.
        :param resample: An optional resampling filter.  This can be
           one of :py:attr:`PIL.Image.NEAREST` (use nearest neighbour),
           :py:attr:`PIL.Image.BILINEAR` (linear interpolation in a 2x2
           environment), or :py:attr:`PIL.Image.BICUBIC`
           (cubic spline interpolation in a 4x4 environment).
           If omitted, or if the image has mode "1" or "P", it is
           set to :py:attr:`PIL.Image.NEAREST`. See :ref:`concept-filters`.
        :param expand: Optional expansion flag.  If true, expands the output
           image to make it large enough to hold the entire rotated image.
           If false or omitted, make the output image the same size as the
           input image.  Note that the expand flag assumes rotation around
           the center and no translation.
        :param center: Optional center of rotation (a 2-tuple).  Origin is
           the upper left corner.  Default is the center of the image.
        :param translate: An optional post-rotate translation (a 2-tuple).
        :param fillcolor: An optional color for area outside the rotated image.
        :returns: An :py:class:`~PIL.Image.Image` object.
        """

        angle = angle % 360.0

        # Fast paths regardless of filter, as long as we're not
        # translating or changing the center.
        if not (center or translate):
            if angle == 0:
                return self.copy()
            if angle == 180:
                return self.transpose(ROTATE_180)
            if angle == 90 and expand:
                return self.transpose(ROTATE_90)
            if angle == 270 and expand:
                return self.transpose(ROTATE_270)

        # Calculate the affine matrix.  Note that this is the reverse
        # transformation (from destination image to source) because we
        # want to interpolate the (discrete) destination pixel from
        # the local area around the (floating) source pixel.

        # The matrix we actually want (note that it operates from the right):
        # (1, 0, tx)   (1, 0, cx)   ( cos a, sin a, 0)   (1, 0, -cx)
        # (0, 1, ty) * (0, 1, cy) * (-sin a, cos a, 0) * (0, 1, -cy)
        # (0, 0,  1)   (0, 0,  1)   (     0,     0, 1)   (0, 0,   1)

        # The reverse matrix is thus:
        # (1, 0, cx)   ( cos -a, sin -a, 0)   (1, 0, -cx)   (1, 0, -tx)
        # (0, 1, cy) * (-sin -a, cos -a, 0) * (0, 1, -cy) * (0, 1, -ty)
        # (0, 0,  1)   (      0,      0, 1)   (0, 0,   1)   (0, 0,   1)

        # In any case, the final translation may be updated at the end to
        # compensate for the expand flag.

        w, h = self.size

        if translate is None:
            post_trans = (0, 0)
        else:
            post_trans = translate
        if center is None:
            # FIXME These should be rounded to ints?
            rotn_center = (w / 2.0, h / 2.0)
        else:
            rotn_center = center

        angle = -math.radians(angle)
        matrix = [
            round(math.cos(angle), 15),
            round(math.sin(angle), 15),
            0.0,
            round(-math.sin(angle), 15),
            round(math.cos(angle), 15),
            0.0,
        ]

        def transform(x, y, matrix):
            (a, b, c, d, e, f) = matrix
            return a * x + b * y + c, d * x + e * y + f

        matrix[2], matrix[5] = transform(
            -rotn_center[0] - post_trans[0], -rotn_center[1] - post_trans[1], matrix
        )
        matrix[2] += rotn_center[0]
        matrix[5] += rotn_center[1]

        if expand:
            # calculate output size
            xx = []
            yy = []
            for x, y in ((0, 0), (w, 0), (w, h), (0, h)):
                x, y = transform(x, y, matrix)
                xx.append(x)
                yy.append(y)
            nw = math.ceil(max(xx)) - math.floor(min(xx))
            nh = math.ceil(max(yy)) - math.floor(min(yy))

            # We multiply a translation matrix from the right.  Because of its
            # special form, this is the same as taking the image of the
            # translation vector as new translation vector.
            matrix[2], matrix[5] = transform(-(nw - w) / 2.0, -(nh - h) / 2.0, matrix)
            w, h = nw, nh

        return self.transform((w, h), AFFINE, matrix, resample, fillcolor=fillcolor)

此功能还应用了一些平移(位置偏移),以将旋转的图像角保持在图像内部。适用翻译的代码部分是此行

matrix[2], matrix[5] = transform(-(nw - w) / 2.0, -(nh - h) / 2.0, matrix)

我想做的是提取矩阵[2]和矩阵[5]的值,以便当在moviepy中调用旋转时,我可以反转此转换。

要实现这样的目标...

import moviepy.editor as mped
image_clip = mped.ImageClip("image.jpg", duration=3)
rotated_image = image_clip.rotate(20).set_position((pillow_rotate_x.
                (-matrix[2]),pillow_rotate_y.(-matrix[5]))

以便取消枕形平移,并将图像中心返回到其最初旋转的位置。

我想知道如何通过最少的代码重复来实现?

例如,使用以下代码:-

import moviepy.editor as mped
import sys
import numpy as np

print("Python Version", sys.version)

baboon = mped.ImageClip("baboon.png", duration=3)
colour_clip = mped.ColorClip(size=[500, 50], color=np.array([250, 90, 0]).astype(np.uint8), duration=3) # important to use .astype(np.uint8)
cameraman = mped.ImageClip("cameraman.jpg", duration=3)
print("baboon_size", baboon.size)
print("colour_clip size", colour_clip.size)
print("cameraman size", cameraman.size)

rot_trans_col_clip = colour_clip.add_mask().rotate(20)
rot_trans_cameraman = cameraman.add_mask().rotate(20)
stacked_clips = mped.CompositeVideoClip([baboon, rot_trans_col_clip, rot_trans_cameraman])
stacked_clips.write_videofile('rotated_imagery_on_baboon.mp4', fps=5)

使用以上代码,您可以分层一些不同类型的内容并将其旋转。

狒狒和摄影师的两个输入图像文件可以在这里下载:-https://drive.google.com/file/d/17_s1IunwIAy1npJrsLRicieTG4NZYV4o/view?usp=sharinghttps://drive.google.com/file/d/1G5YbApGX035-9mJtuz9GNgLr6jGywk-Z/view?usp=sharing

带有下面的翻译代码(位于枕头image.py文件中)

matrix[2], matrix[5] = transform(-(nw - w) / 2.0, -(nh - h) / 2.0, matrix)

它对图像的影响在这里显示:-

https://drive.google.com/file/d/1d_prYqb-fqizFcV0MD0rMXOIny2L0KW5/view?usp=sharing您可以在此处看到两个旋转图像的中心已移动,因此它们的角仍然可见(未裁剪)。

没有枕头旋转功能内的枕头转换代码,它看起来像这样:-

https://drive.google.com/file/d/17POoZcuk9QAxJrnwD2LFsYd--SXdR9JA/view?usp=sharing

您可以在这里看到,尽管拐角处有一些裁剪,但是图像的中心并未移动。

这是我想要的结果。但是,枕头旋转会在最后应用平移。

有趣的是,如果在枕头旋转上将expand = False设置为:-

rot_trans_cameraman = cameraman.add_mask().rotate(20, unit='deg', expand=False)

您得到这个:-

https://drive.google.com/open?id=1QEzJN3NlWK_sjxPLGC_BNs2xfxxfhAIH

具有相同的中心点。因此,似乎在没有将expanding flag设置为false的情况下,中心点会移动,但是在将其设置为false的情况下,所有角都是对称裁剪的。

之所以有用,是因为如果您通过某个角度进行枕形旋转,则结果是确定性的,而不是合并依赖于图像大小的平移。

所以我的问题是,如何还原旋转中心位置?

python python-3.x matrix python-imaging-library moviepy
1个回答
0
投票

这个问题的答案在这里:-

https://github.com/python-pillow/Pillow/issues/4556

新参考是在扩展和中心重新定位之后。然后可以在全局系统中使用它来重新定位元素。

© www.soinside.com 2019 - 2024. All rights reserved.