Skip to content

Instantly share code, notes, and snippets.

@jdhao
Last active June 2, 2025 11:05
Show Gist options
  • Save jdhao/1cb4c8f6561fbdb87859ac28a84b0201 to your computer and use it in GitHub Desktop.
Save jdhao/1cb4c8f6561fbdb87859ac28a84b0201 to your computer and use it in GitHub Desktop.
Given an image and a 4 points in the image (no 3 points are co-linear). Find the rotated rectangle enclosing the polygon formed by the 4 points and crop the rotated rectangle from the image. All done by OpenCV.
import cv2
import numpy as np
def main():
img = cv2.imread("test_image.jpg")
# assume coord is a list with 8 float values, the points of the rectangle area should
# have be clockwise
x1, y1, x2, y2, x3, y3, x4, y4 = coord
cnt = np.array([[[x1, y1]],
[[x2, y2]],
[[x3, y3]],
[[x4, y4]]
])
# cv2.drawContours(img, [cnt], 0, (128, 255, 0), 3)
# find the rotated rectangle enclosing the contour
# rect has 3 elments, the first is rectangle center, the second is
# width and height of the rectangle and the third is the rotation angle
rect = cv2.minAreaRect(cnt)
print("rect: {}".format(rect))
# convert rect to 4 points format
box = cv2.boxPoints(rect)
box = np.int0(box)
print("bounding box: {}".format(box))
# draw the roated rectangle box in the image
cv2.drawContours(img, [box], 0, (0, 0, 255), 2)
# crop the rotated rectangle from the image
im_crop, img_rot = crop_rect(img, rect)
# print("size of original img: {}".format(img.shape))
# print("size of rotated img: {}".format(img_rot.shape))
# print("size of cropped img: {}".format(im_crop.shape))
cv2.imshow("cropped_box", im_crop)
cv2.imshow("original contour", img)
cv2.imshow("rotated image", img_rot)
cv2.waitKey(0)
# this function is base on post at https://goo.gl/Q92hdp
def crop_rect(img, rect):
# get the parameter of the small rectangle
center = rect[0]
size = rect[1]
angle = rect[2]
center, size = tuple(map(int, center)), tuple(map(int, size))
# get row and col num in img
rows, cols = img.shape[0], img.shape[1]
M = cv2.getRotationMatrix2D(center, angle, 1)
img_rot = cv2.warpAffine(img, M, (cols, rows))
out = cv2.getRectSubPix(img_rot, size, center)
return out, img_rot
if __name__ == "__main__":
main()
@jdhao
Copy link
Author

jdhao commented Dec 21, 2018

The rotation angle of the rectangle is a bit tricky. The angle is in range [-90, 0] (expressed in degrees), see https://goo.gl/kymHsS for a discussion.

The shape of the cropped rectangle may not be what you want. You may need to rotate the cropped rectangle to get the desired shape.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment