Python 剪切具有相同纵横比的旋转图像

Python 剪切具有相同纵横比的旋转图像,python,image-processing,rotation,crop,Python,Image Processing,Rotation,Crop,当输入图像旋转给定角度,然后进行裁剪以避免任何非图像区域,同时保持原始图像纵横比时,如何确定最终图像的宽度和高度 例如: 定义: W0和H0是原始矩形的宽度和高度 D0是原始矩形的对角线(斜边) W1和H1是旋转矩形的填充宽度和高度 W2和H2是目标矩形的宽度和高度 D2是目标矩形的对角线(斜边) E是复杂的、瞬时的 您可能需要预计算sin(A)、cos(A)和tan(A),因为它们被反复使用 计算W1和H1: 它们由两个组件组成,两个三角形边组成每个长度 W1=W0*co

当输入图像旋转给定角度,然后进行裁剪以避免任何非图像区域,同时保持原始图像纵横比时,如何确定最终图像的宽度和高度

例如:

定义:
  • W0和H0是原始矩形的宽度和高度

  • D0是原始矩形的对角线(斜边)

  • W1和H1是旋转矩形的填充宽度和高度

  • W2和H2是目标矩形的宽度和高度

  • D2是目标矩形的对角线(斜边)

  • E是复杂的、瞬时的

  • 您可能需要预计算sin(A)、cos(A)和tan(A),因为它们被反复使用

计算W1和H1: 它们由两个组件组成,两个三角形边组成每个长度

  • W1=W0*cos(A)+H0*sin(A)
  • H1=H0*cos(A)+W0*sin(A)
计算W2和H2:
  • E=W0/(1+tan(A)/W0*H0)
  • W2=E/tan(A)
  • H2=W2/W0*H0
作为Python: 免责声明:这都是未经测试的


编辑:根据请求,我对E的意思做出了最好的猜测:

r0 = w2/h2
h2 = (w0-e1) / sin(A)
h2 = e1/ cos(A) / r0
(w0-e1) / sin(A) = e1/ cos(A) / r0
x = cos(A) / sin(A)
e1 = w0 * x / (1/r0 + x)
E是w2的水平分量,通过线a+b延伸。然后是关于计算什么是
a
vs
b
,使用纵横比和sin/cos来计算。取消了条款,提高了声音,这就是我的结局。

  • 红色矩形是具有原始纵横比的原始图像
  • W/t
    旋转矩形(由绿色和黄色三角形包围) 图像宽高比,带
    extend=True
下面是如何获取
w
h

image = Image.open(...)
rotated = image.rotate(degrees, Image.BICUBIC, True)

aspect_ratio = float(image.size[0]) / image.size[1]
rotated_aspect_ratio = float(rotated.size[0]) / rotated.size[1]
angle = math.fabs(degrees) * math.pi / 180

if aspect_ratio < 1:
    total_height = float(image.size[0]) / rotated_aspect_ratio
else:
    total_height = float(image.size[1])

h = total_height / (aspect_ratio * math.sin(angle) + math.cos(angle))
w = h * aspect_ratio
image=image.open(…)
旋转=图像。旋转(度,image.BICUBIC,真)
纵横比=浮点(image.size[0])/image.size[1]
旋转的纵横比=浮动(旋转的.size[0])/rotated.size[1]
角度=math.fabs(度)*math.pi/180
如果纵横比<1:
总高度=浮动(图像大小[0])/旋转的纵横比
其他:
总高度=浮动(image.size[1])
h=总高度/(纵横比*数学sin(角度)+数学cos(角度))
w=h*纵横比
现在,旋转后的图像可以在中心用
w
x
h
尺寸裁剪到
获取最终图像。

此代码返回此块的坐标

我导入PIL仅用于获取图像真实大小。
您不能导入PIL,相反,您可以通过任何其他方式获取图像大小。

这是一个很好的问题,我也不介意知道答案,但这是否更适合数学堆栈交换?也许。我想也许有人知道这里发布的Python PIL中的一个技巧。祝你好运。我在努力…我实际上刚刚想出了怎么做。结果很简单。现在写解决方案。哦,感谢上帝。当我意识到我的方程依赖于知道一个变量时,我正准备弃船!如果
纵横比=a=w/h
那么它不是
w=a/h
不是
w=h*a
吗?你将两边乘以h,因此ha=hw/h,但h/h是1,所以被取消。在代码中发现一个错误:你需要取正弦和余弦的绝对值,否则它会因旋转>90°而中断。什么是E?可能是维基链接,没有链接。我自己推导了这个,E是我需要的一个维度。我会用图片更新帖子。它和你的大不相同!也许我错过了一些琐碎的东西,但我仍然没有理解什么是e。也许晚上我会再试一次。-1:这不可能是正确的:除以tan(alpha)。tan(ε)=ε。根据你的公式,微小的旋转会导致你除以一个微小的数字,从而导致完全错误的宽度。
image = Image.open(...)
rotated = image.rotate(degrees, Image.BICUBIC, True)

aspect_ratio = float(image.size[0]) / image.size[1]
rotated_aspect_ratio = float(rotated.size[0]) / rotated.size[1]
angle = math.fabs(degrees) * math.pi / 180

if aspect_ratio < 1:
    total_height = float(image.size[0]) / rotated_aspect_ratio
else:
    total_height = float(image.size[1])

h = total_height / (aspect_ratio * math.sin(angle) + math.cos(angle))
w = h * aspect_ratio
from PIL import Image
def cropp_rotated(image, degrees):
    x, y = image.size
    cosA = abs(math.cos(math.radians(degrees)))
    sinA = abs(math.sin(math.radians(degrees)))

    a = x * cosA 
    b = x * sinA

    relation = a / (a + b)
    right_indent1 = a - x * relation * cosA

    relation = b / (a + b)
    bottom_ident1 = b - x * relation *sinA


    c = y * cosA 
    d = y * sinA

    relation = c / (c + d)
    right_indent2 = c - y * relation * cosA

    relation = d / (c + d)
    bottom_ident2 = d - y * relation *sinA

    right_indent = max(right_indent1, right_indent2)
    top_indent = max(bottom_ident1, bottom_ident2)

    #size of rotated image:
    w_rotated = x * cosA + y * sinA
    h_rotated = y * cosA + x * sinA


    box = (
    int(right_indent), 
    int(top_indent), 
    int(w_rotated - right_indent), 
    int(h_rotated - top_indent))

    return box