Skip to content

Commit

Permalink
Fix rotation of rectangular images
Browse files Browse the repository at this point in the history
  • Loading branch information
d4nst committed Mar 25, 2018
1 parent 1d934ba commit 2a4fe4b
Showing 1 changed file with 39 additions and 9 deletions.
48 changes: 39 additions & 9 deletions utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,26 +49,57 @@ def binarize_images(x):

def rotate(image, angle):
"""
Rotate an OpenCV 2 / NumPy image around it's centre by the given angle
(in degrees). The returned image will have the same size as the new image.
Rotates an OpenCV 2 / NumPy image about it's centre by the given angle
(in degrees). The returned image will be large enough to hold the entire
new image, with a black background
Adapted from: http://stackoverflow.com/questions/16702966/rotate-image-and-crop-out-black-borders
Source: http://stackoverflow.com/questions/16702966/rotate-image-and-crop-out-black-borders
"""

# Get the image size
# No that's not an error - NumPy stores image matricies backwards
image_size = (image.shape[1], image.shape[0])
image_center = tuple(np.array(image_size) / 2 - 0.5)
image_center = tuple(np.array(image_size) / 2)

# Convert the OpenCV 3x2 rotation matrix to 3x3
rot_mat = np.vstack(
[cv2.getRotationMatrix2D(image_center, angle, 1.0), [0, 0, 1]]
)

rot_mat_notranslate = np.matrix(rot_mat[0:2, 0:2])

# Shorthand for below calcs
image_w2 = image_size[0] * 0.5
image_h2 = image_size[1] * 0.5

# Obtain the rotated coordinates of the image corners
rotated_coords = [
(np.array([-image_w2, image_h2]) * rot_mat_notranslate).A[0],
(np.array([ image_w2, image_h2]) * rot_mat_notranslate).A[0],
(np.array([-image_w2, -image_h2]) * rot_mat_notranslate).A[0],
(np.array([ image_w2, -image_h2]) * rot_mat_notranslate).A[0]
]

# Find the size of the new image
x_coords = [pt[0] for pt in rotated_coords]
x_pos = [x for x in x_coords if x > 0]
x_neg = [x for x in x_coords if x < 0]

y_coords = [pt[1] for pt in rotated_coords]
y_pos = [y for y in y_coords if y > 0]
y_neg = [y for y in y_coords if y < 0]

right_bound = max(x_pos)
left_bound = min(x_neg)
top_bound = max(y_pos)
bot_bound = min(y_neg)

new_w = int(abs(right_bound - left_bound))
new_h = int(abs(top_bound - bot_bound))

# We require a translation matrix to keep the image centred
trans_mat = np.matrix([
[1, 0, int(image_size[0] * 0.5 - image_center[1])],
[0, 1, int(image_size[0] * 0.5 - image_center[1])],
[1, 0, int(new_w * 0.5 - image_w2)],
[0, 1, int(new_h * 0.5 - image_h2)],
[0, 0, 1]
])

Expand All @@ -79,7 +110,7 @@ def rotate(image, angle):
result = cv2.warpAffine(
image,
affine_mat,
image_size,
(new_w, new_h),
flags=cv2.INTER_LINEAR
)

Expand Down Expand Up @@ -179,7 +210,6 @@ def generate_rotated_image(image, angle, size=None, crop_center=False,
height = width
else:
width = height
image = crop_around_center(image, height, width)

image = rotate(image, angle)

Expand Down

0 comments on commit 2a4fe4b

Please sign in to comment.