Reputation: 27861
How can I find out the width and height of the final image when the input image is rotated by given amount of degrees and then cropped to avoid any non-image areas while maintaining the original image aspect ratio.
example:
Upvotes: 5
Views: 3978
Reputation: 1
This code returns coords of this block
returned box - is the coords of this block
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
I import PIL only for get image real size. You can not import PIL, instead of this you can get image size any other way.
Upvotes: 0
Reputation: 23231
W0 and H0 are the original rectangle's width and height
D0 is the diagonal (hypotenuse) of the original rectangle
W1 and H1 are the padded width and height of the rotated rectangle
W2 and H2 are the width and height of the target rectangle
D2 is the diagonal (hypotenuse) of the target rectangle
E is complicated and transient
You probably want to precompute sin(A), cos(A), and tan(A) as they are used repeatedly
These are made up of two components, the two triangle sides that make up each length
W0 = # original rectangle width
H0 = # original rectangle height
cosA = cos(A)
sinA = sin(A)
tanA = tan(A)
W1 = W0 * cosA + H0 * sinA
H1 = H0 * cosA + W0 * sinA
E = W0 / (1 + tanA / W0 * H0)
W2 = E / tanA # requested width
H2 = W2 / W0 * H0 # requested height
Disclaimer: this is all untested
Edit: by request, my best guess of what I meant by 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 was the horizontal component of w2, extended through the line a+b. Then it was about computing what was a
vs b
, using the aspect ratio and sin/cos to figure that out. Terms cancelled, voices were raised, and that's what I ended up with.
Upvotes: 1
Reputation: 27861
W/t
rectangle (enclosed by green and yellow triangles) is rotated
image aspect ratio with extend=True
.Here is how to get the w
and 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
Now the rotated image can be cropped in the center with w
xh
dimensions to
get the final image.
Upvotes: 8