これは、PIL の基本的な変換の質問です。これを正しく実装するために、過去数年間で少なくとも数回試しましたが、PIL の Image.transform についてよくわからないことがあるようです。画像の限界を明確に示すことができる相似変換 (またはアフィン変換) を実装したいと考えています。私のアプローチが機能することを確認するために、Matlab に実装しました。
Matlab の実装は次のとおりです。
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
これは期待どおりに機能します。これは入力です:
これは出力です:
これは、同じ変換を実装する Python/PIL コードです。
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 からの出力です。
私は何年もの間、複数の OS で複数のバージョンの Python と PIL を使用してこれを試してきましたが、結果は常にほとんど同じです。
これは問題を説明する最も単純なケースです。必要な回転であれば、 im.rotate 呼び出しで回転を実行できますが、せん断とスケーリングも行いたいと考えています。これは、説明するための単なる例です。問題。すべてのアフィン変換で同じ出力を得たいと考えています。これを正しく取得できるようにしたいと思います。
編集:
変換行を次のように変更すると:
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 に変更すると、次のようになりました。