maxwoe commited on
Commit
fd9bd2c
·
verified ·
1 Parent(s): 6ddcdaf

Upload rotation_utils.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. rotation_utils.py +71 -0
rotation_utils.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Rotation utilities that preserve image content without artificial borders."""
2
+
3
+ import cv2
4
+ import numpy as np
5
+ import math
6
+
7
+
8
+ def rotate_image(img, angle, rotation_center=None, expand=False, border_mode=cv2.BORDER_CONSTANT, border_value=0):
9
+ """Rotates an image (angle in degrees) and optionally expands to avoid cropping."""
10
+ h, w = img.shape[:2]
11
+ if rotation_center is None:
12
+ rotation_center = (w/2, h/2)
13
+
14
+ M = cv2.getRotationMatrix2D(rotation_center, angle, 1.0)
15
+
16
+ if expand:
17
+ abs_cos = abs(M[0, 0])
18
+ abs_sin = abs(M[0, 1])
19
+ wn = int(h * abs_sin + w * abs_cos)
20
+ hn = int(h * abs_cos + w * abs_sin)
21
+ M[0, 2] += wn/2 - rotation_center[0]
22
+ M[1, 2] += hn/2 - rotation_center[1]
23
+ else:
24
+ wn, hn = w, h
25
+
26
+ rotated = cv2.warpAffine(
27
+ img, M, (wn, hn), borderMode=border_mode, borderValue=border_value)
28
+
29
+ return rotated, M
30
+
31
+
32
+ def largest_rotated_rect(w, h, angle):
33
+ """Compute the largest axis-aligned rectangle within a rotated rectangle."""
34
+ if w <= 0 or h <= 0:
35
+ return 0, 0
36
+
37
+ width_is_longer = w >= h
38
+ side_long, side_short = (w, h) if width_is_longer else (h, w)
39
+
40
+ sin_a, cos_a = abs(math.sin(angle)), abs(math.cos(angle))
41
+ if side_short <= 2.*sin_a*cos_a*side_long or abs(sin_a-cos_a) < 1e-10:
42
+ x = 0.5*side_short
43
+ wr, hr = (x/sin_a, x/cos_a) if width_is_longer else (x/cos_a, x/sin_a)
44
+ else:
45
+ cos_2a = cos_a*cos_a - sin_a*sin_a
46
+ wr, hr = (w*cos_a - h*sin_a)/cos_2a, (h*cos_a - w*sin_a)/cos_2a
47
+
48
+ return wr, hr
49
+
50
+
51
+ def rotate_image_crop_max_area(image, angle):
52
+ """Rotate image and crop to the largest inscribed rectangle (no borders).
53
+
54
+ Args:
55
+ image: numpy array (OpenCV image)
56
+ angle: Rotation angle in degrees
57
+
58
+ Returns:
59
+ Rotated and cropped numpy array
60
+ """
61
+ h, w = image.shape[:2]
62
+ rotated, _ = rotate_image(image, angle, expand=True)
63
+ wr, hr = largest_rotated_rect(w, h, math.radians(angle))
64
+
65
+ h_rot, w_rot = rotated.shape[:2]
66
+ y1 = h_rot//2 - int(hr/2)
67
+ y2 = y1 + int(hr)
68
+ x1 = w_rot//2 - int(wr/2)
69
+ x2 = x1 + int(wr)
70
+
71
+ return rotated[y1:y2, x1:x2]