Python/PIL仿射转换 [英] Python/PIL affine transformation

查看:134
本文介绍了Python/PIL仿射转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是PIL中的基本转换问题.我至少尝试过几次 在过去的几年中正确地实现了这一点,似乎有 我对PIL中的Image.transform不太了解.我想要 在我可以的地方实施相似度转换(或仿射转换) 清楚说明图像的限制.为了确保我的方法可行,我 在Matlab中实现.

This is a basic transform question in PIL. I've tried at least a couple of times in the past few years to implement this correctly and it seems there is something I don't quite get about Image.transform in PIL. I want to implement a similarity transformation (or an affine transformation) where I can clearly state the limits of the image. To make sure my approach works I implemented it in Matlab.

Matlab实现如下:

The Matlab implementation is the following:

im = imread('test.jpg');
y = size(im,1);
x = size(im,2);
angle = 45*3.14/180.0;
xextremes = [rot_x(angle,0,0),rot_x(angle,0,y-1),rot_x(angle,x-1,0),rot_x(angle,x-1,y-1)];
yextremes = [rot_y(angle,0,0),rot_y(angle,0,y-1),rot_y(angle,x-1,0),rot_y(angle,x-1,y-1)];
m = [cos(angle) sin(angle) -min(xextremes); -sin(angle) cos(angle) -min(yextremes); 0 0 1];
tform = maketform('affine',m')
round( [max(xextremes)-min(xextremes), max(yextremes)-min(yextremes)])
im = imtransform(im,tform,'bilinear','Size',round([max(xextremes)-min(xextremes), max(yextremes)-min(yextremes)]));
imwrite(im,'output.jpg');

function y = rot_x(angle,ptx,pty),
    y = cos(angle)*ptx + sin(angle)*pty

function y = rot_y(angle,ptx,pty),
    y = -sin(angle)*ptx + cos(angle)*pty

这按预期工作.这是输入:

this works as expected. This is the input:

这是输出:

这是实现相同功能的Python/PIL代码 转换:

This is the Python/PIL code that implements the same transformation:

import Image
import math

def rot_x(angle,ptx,pty):
    return math.cos(angle)*ptx + math.sin(angle)*pty

def rot_y(angle,ptx,pty):
    return -math.sin(angle)*ptx + math.cos(angle)*pty

angle = math.radians(45)
im = Image.open('test.jpg')
(x,y) = im.size
xextremes = [rot_x(angle,0,0),rot_x(angle,0,y-1),rot_x(angle,x-1,0),rot_x(angle,x-1,y-1)]
yextremes = [rot_y(angle,0,0),rot_y(angle,0,y-1),rot_y(angle,x-1,0),rot_y(angle,x-1,y-1)]
mnx = min(xextremes)
mxx = max(xextremes)
mny = min(yextremes)
mxy = max(yextremes)
im = im.transform((int(round(mxx-mnx)),int(round((mxy-mny)))),Image.AFFINE,(math.cos(angle),math.sin(angle),-mnx,-math.sin(angle),math.cos(angle),-mny),resample=Image.BILINEAR)
im.save('outputpython.jpg')

这是Python的输出:

and this is the output from Python:

多年来,我已经在多个操作系统上使用多个版本的Python和PIL进行了尝试,结果始终是相同的.

I've tried this with several versions of Python and PIL on multiple OSs through the years and the results is always mostly the same.

这是说明问题的最简单的情况,我知道如果是我想要的旋转,则可以使用im.rotate调用进行旋转,但是我也想剪切和缩放,这只是一个示例来说明一个问题.对于所有仿射变换,我都希望获得相同的输出.我希望能够做到这一点.

This is the simplest possible case that illustrates the problem, I understand that if it was a rotation I wanted, I could do the rotation with the im.rotate call but I want to shear and scale too, this is just an example to illustrate a problem. I would like to get the same output for all affine transformations. I would like to be able to get this right.

如果我将变换线更改为此:

If I change the transform line to this:

im = im.transform((int(round(mxx-mnx)),int(round((mxy-mny)))),Image.AFFINE,(math.cos(angle),math.sin(angle),0,-math.sin(angle),math.cos(angle),0),resample=Image.BILINEAR)

这是我得到的输出:

编辑#2

我旋转了-45度,并将偏移量更改为-0.5 * mnx和-0.5 * mny并获得了此结果:

I rotated by -45 degrees and changed the offset to -0.5*mnx and -0.5*mny and obtained this:

推荐答案

好!所以我一直在努力理解整个周末,我想我有一个 令我满意的答案.谢谢大家的评论和建议!

OK! So I've been working on understanding this all weekend and I think I have an answer that satisfies me. Thank you all for your comments and suggestions!

我首先看一下这个:

在PIL python中进行仿射变换?

虽然我看到作者可以进行任意相似性转换 没有解释为什么我的代码不起作用,也没有解释空间 我们需要变换的图像的布局,也不提供线性 解决我的问题的代数方法.

while I see that the author can make arbitrary similarity transformations it does not explain why my code was not working, nor does he explain the spatial layout of the image that we need to transform nor does he provide a linear algebraic solution to my problems.

但是我确实从他的代码中看到,我确实看到他正在将 矩阵(a,b,d和e)变成了使我震惊的标度.我回去看书 我引用的PIL文档:

But I do see from his code I do see that he's dividing the rotation part of the matrix (a,b,d and e) into the scale which struck me as odd. I went back to read the PIL documentation which I quote:

"im.transform(大小,仿射,数据,过滤器)=>图片

"im.transform(size, AFFINE, data, filter) => image

对图像应用仿射变换,并将结果放置在新图像中 具有给定的大小.

Applies an affine transform to the image, and places the result in a new image with the given size.

数据是6元组(a,b,c,d,e,f),其中包含来自 仿射变换矩阵.对于输出图像中的每个像素(x,y),新 值取自输入中的位置(a x + b y + c,d x + e y + f) 图片,四舍五入到最接近的像素.

Data is a 6-tuple (a, b, c, d, e, f) which contain the first two rows from an affine transform matrix. For each pixel (x, y) in the output image, the new value is taken from a position (a x + b y + c, d x + e y + f) in the input image, rounded to nearest pixel.

此功能可用于缩放,平移,旋转和剪切原稿 图片."

This function can be used to scale, translate, rotate, and shear the original image."

所以参数(a,b,c,d,e,f)是一个变换矩阵,但映射的是 目标图像中的(x,y)到源图像中的(a x + b y + c,d x + e y + f) 图像.但不是您要应用的变换矩阵的参数,而是 它的逆.那是:

so the parameters (a,b,c,d,e,f) are a transform matrix, but the one that maps (x,y) in the destination image to (a x + b y + c, d x + e y + f) in the source image. But not the parameters of the transform matrix you want to apply, but its inverse. That is:

  • 怪异
  • 不同于Matlab
  • 但幸运的是,现在我已完全理解

我要附加我的代码:

import Image
import math
from numpy import matrix
from numpy import linalg

def rot_x(angle,ptx,pty):
    return math.cos(angle)*ptx + math.sin(angle)*pty

def rot_y(angle,ptx,pty):
    return -math.sin(angle)*ptx + math.cos(angle)*pty

angle = math.radians(45)
im = Image.open('test.jpg')
(x,y) = im.size
xextremes = [rot_x(angle,0,0),rot_x(angle,0,y-1),rot_x(angle,x-1,0),rot_x(angle,x-1,y-1)]
yextremes = [rot_y(angle,0,0),rot_y(angle,0,y-1),rot_y(angle,x-1,0),rot_y(angle,x-1,y-1)]
mnx = min(xextremes)
mxx = max(xextremes)
mny = min(yextremes)
mxy = max(yextremes)
print mnx,mny
T = matrix([[math.cos(angle),math.sin(angle),-mnx],[-math.sin(angle),math.cos(angle),-mny],[0,0,1]])
Tinv = linalg.inv(T);
print Tinv
Tinvtuple = (Tinv[0,0],Tinv[0,1], Tinv[0,2], Tinv[1,0],Tinv[1,1],Tinv[1,2])
print Tinvtuple
im = im.transform((int(round(mxx-mnx)),int(round((mxy-mny)))),Image.AFFINE,Tinvtuple,resample=Image.BILINEAR)
im.save('outputpython2.jpg')

和python的输出:

and the output from python:

让我在最终摘要中再次说明该问题的答案:

Let me state the answer to this question again in a final summary:

PIL要求您要应用仿射变换的逆函数.

这篇关于Python/PIL仿射转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆