Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>So, after investigating many claimed solutions, I have finally found a method that works; The answer by <a href="https://stackoverflow.com/users/671973/andri">Andri</a> and <a href="https://stackoverflow.com/users/2971/magnus-hoff">Magnus Hoff</a> on <a href="https://stackoverflow.com/questions/5789239/calculate-largest-rectangle-in-a-rotated-rectangle#7519376">Calculate largest rectangle in a rotated rectangle</a>.</p> <p>The below Python code contains the method of interest - <code>largest_rotated_rect</code> - and a short demo.</p> <pre><code>import math import cv2 import numpy as np def rotate_image(image, angle): """ 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 """ # 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) # 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 &gt; 0] x_neg = [x for x in x_coords if x &lt; 0] y_coords = [pt[1] for pt in rotated_coords] y_pos = [y for y in y_coords if y &gt; 0] y_neg = [y for y in y_coords if y &lt; 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(new_w * 0.5 - image_w2)], [0, 1, int(new_h * 0.5 - image_h2)], [0, 0, 1] ]) # Compute the tranform for the combined rotation and translation affine_mat = (np.matrix(trans_mat) * np.matrix(rot_mat))[0:2, :] # Apply the transform result = cv2.warpAffine( image, affine_mat, (new_w, new_h), flags=cv2.INTER_LINEAR ) return result def largest_rotated_rect(w, h, angle): """ Given a rectangle of size wxh that has been rotated by 'angle' (in radians), computes the width and height of the largest possible axis-aligned rectangle within the rotated rectangle. Original JS code by 'Andri' and Magnus Hoff from Stack Overflow Converted to Python by Aaron Snoswell """ quadrant = int(math.floor(angle / (math.pi / 2))) &amp; 3 sign_alpha = angle if ((quadrant &amp; 1) == 0) else math.pi - angle alpha = (sign_alpha % math.pi + math.pi) % math.pi bb_w = w * math.cos(alpha) + h * math.sin(alpha) bb_h = w * math.sin(alpha) + h * math.cos(alpha) gamma = math.atan2(bb_w, bb_w) if (w &lt; h) else math.atan2(bb_w, bb_w) delta = math.pi - alpha - gamma length = h if (w &lt; h) else w d = length * math.cos(alpha) a = d * math.sin(alpha) / math.sin(delta) y = a * math.cos(gamma) x = y * math.tan(gamma) return ( bb_w - 2 * x, bb_h - 2 * y ) def crop_around_center(image, width, height): """ Given a NumPy / OpenCV 2 image, crops it to the given width and height, around it's centre point """ image_size = (image.shape[1], image.shape[0]) image_center = (int(image_size[0] * 0.5), int(image_size[1] * 0.5)) if(width &gt; image_size[0]): width = image_size[0] if(height &gt; image_size[1]): height = image_size[1] x1 = int(image_center[0] - width * 0.5) x2 = int(image_center[0] + width * 0.5) y1 = int(image_center[1] - height * 0.5) y2 = int(image_center[1] + height * 0.5) return image[y1:y2, x1:x2] def demo(): """ Demos the largest_rotated_rect function """ image = cv2.imread("lenna_rectangle.png") image_height, image_width = image.shape[0:2] cv2.imshow("Original Image", image) print "Press [enter] to begin the demo" print "Press [q] or Escape to quit" key = cv2.waitKey(0) if key == ord("q") or key == 27: exit() for i in np.arange(0, 360, 0.5): image_orig = np.copy(image) image_rotated = rotate_image(image, i) image_rotated_cropped = crop_around_center( image_rotated, *largest_rotated_rect( image_width, image_height, math.radians(i) ) ) key = cv2.waitKey(2) if(key == ord("q") or key == 27): exit() cv2.imshow("Original Image", image_orig) cv2.imshow("Rotated Image", image_rotated) cv2.imshow("Cropped Image", image_rotated_cropped) print "Done" if __name__ == "__main__": demo() </code></pre> <p><img src="https://i.stack.imgur.com/76nJM.jpg" alt="Image Rotation Demo"></p> <p>Simply place <a href="https://i.stack.imgur.com/vWdWB.png" rel="noreferrer">this image</a> (cropped to demonstrate that it works with non-square images) in the same directory as the above file, then run it.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload