旋转图像,而不用在C ++中的OpenCV中裁剪

我想旋转一个图像,但我无法获得旋转的图像没有裁剪

我的原始图像:

在这里输入图像描述

现在我使用这个代码:

#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> // Compile with g++ code.cpp -lopencv_core -lopencv_highgui -lopencv_imgproc int main() { cv::Mat src = cv::imread("im.png", CV_LOAD_IMAGE_UNCHANGED); cv::Mat dst; cv::Point2f pc(src.cols/2., src.rows/2.); cv::Mat r = cv::getRotationMatrix2D(pc, -45, 1.0); cv::warpAffine(src, dst, r, src.size()); // what size I should use? cv::imwrite("rotated_im.png", dst); return 0; } 

并获得以下图像:

在这里输入图像描述

但我想获得这个:

在这里输入图像描述

非常感谢您的帮助!

我的答案受以下文章/博客文章的启发:

主要观点:

  • 通过将转换添加到新图像中心来调整旋转matrix
  • 使用cv::RotatedRect尽可能依赖现有的opencvfunction

使用opencv 2.4.8testing代码:

 #include "opencv2/opencv.hpp" int main() { cv::Mat src = cv::imread("im.png", CV_LOAD_IMAGE_UNCHANGED); double angle = -45; // get rotation matrix for rotating the image around its center cv::Point2f center(src.cols/2.0, src.rows/2.0); cv::Mat rot = cv::getRotationMatrix2D(center, angle, 1.0); // determine bounding rectangle cv::Rect bbox = cv::RotatedRect(center,src.size(), angle).boundingRect(); // adjust transformation matrix rot.at<double>(0,2) += bbox.width/2.0 - center.x; rot.at<double>(1,2) += bbox.height/2.0 - center.y; cv::Mat dst; cv::warpAffine(src, dst, rot, bbox.size()); cv::imwrite("rotated_im.png", dst); return 0; } 

只要尝试下面的代码,这个想法很简单:

  1. 您需要创build一个空白图像,以任意angular度旋转时所期望的最大尺寸。 在这里你应该使用上面提到的评论中提到的毕达哥拉斯。

  2. 现在将源图像复制到新创build的图像,并将其传递给warpAffine 。 在这里你应该使用新创build的图像的中心旋转。

  3. warpAffine之后,如果您需要为此旋转精确图像,请使用此处所述的旋转matrix来转换放大图像中源图像的四个angular

  4. 从上面的结果到裁切图像,find顶angular的最小值x和最小值y,以及底angular的最大值x和最大值y。

这是代码:

 int theta = 0; Mat src,frame, frameRotated; src = imread("rotate.png",1); cout<<endl<<endl<<"Press '+' to rotate anti-clockwise and '-' for clockwise 's' to save" <<endl<<endl; int diagonal = (int)sqrt(src.cols*src.cols+src.rows*src.rows); int newWidth = diagonal; int newHeight =diagonal; int offsetX = (newWidth - src.cols) / 2; int offsetY = (newHeight - src.rows) / 2; Mat targetMat(newWidth, newHeight, src.type()); Point2f src_center(targetMat.cols/2.0F, targetMat.rows/2.0F); while(1){ src.copyTo(frame); double radians = theta * M_PI / 180.0; double sin = abs(std::sin(radians)); double cos = abs(std::cos(radians)); frame.copyTo(targetMat.rowRange(offsetY, offsetY + frame.rows).colRange(offsetX, offsetX + frame.cols)); Mat rot_mat = getRotationMatrix2D(src_center, theta, 1.0); warpAffine(targetMat, frameRotated, rot_mat, targetMat.size()); //Calculate bounding rect and for exact image //Reference:- https://stackoverflow.com/questions/19830477/find-the-bounding-rectangle-of-rotated-rectangle/19830964?noredirect=1#19830964 Rect bound_Rect(frame.cols,frame.rows,0,0); int x1 = offsetX; int x2 = offsetX+frame.cols; int x3 = offsetX; int x4 = offsetX+frame.cols; int y1 = offsetY; int y2 = offsetY; int y3 = offsetY+frame.rows; int y4 = offsetY+frame.rows; Mat co_Ordinate = (Mat_<double>(3,4) << x1, x2, x3, x4, y1, y2, y3, y4, 1, 1, 1, 1 ); Mat RotCo_Ordinate = rot_mat * co_Ordinate; for(int i=0;i<4;i++){ if(RotCo_Ordinate.at<double>(0,i)<bound_Rect.x) bound_Rect.x=(int)RotCo_Ordinate.at<double>(0,i); //access smallest if(RotCo_Ordinate.at<double>(1,i)<bound_Rect.y) bound_Rect.y=RotCo_Ordinate.at<double>(1,i); //access smallest y } for(int i=0;i<4;i++){ if(RotCo_Ordinate.at<double>(0,i)>bound_Rect.width) bound_Rect.width=(int)RotCo_Ordinate.at<double>(0,i); //access largest x if(RotCo_Ordinate.at<double>(1,i)>bound_Rect.height) bound_Rect.height=RotCo_Ordinate.at<double>(1,i); //access largest y } bound_Rect.width=bound_Rect.width-bound_Rect.x; bound_Rect.height=bound_Rect.height-bound_Rect.y; Mat cropedResult; Mat ROI = frameRotated(bound_Rect); ROI.copyTo(cropedResult); imshow("Result", cropedResult); imshow("frame", frame); imshow("rotated frame", frameRotated); char k=waitKey(); if(k=='+') theta+=10; if(k=='-') theta-=10; if(k=='s') imwrite("rotated.jpg",cropedResult); if(k==27) break; } 

在这里输入图像描述

裁剪的图像

在这里输入图像描述在这里输入图像描述

谢谢@哈里斯! 这里是Python版本:

 def rotate_image(image, angle): '''Rotate image "angle" degrees. How it works: - Creates a blank image that fits any rotation of the image. To achieve this, set the height and width to be the image's diagonal. - Copy the original image to the center of this blank image - Rotate using warpAffine, using the newly created image's center (the enlarged blank image center) - Translate the four corners of the source image in the enlarged image using homogenous multiplication of the rotation matrix. - Crop the image according to these transformed corners ''' diagonal = int(math.sqrt(pow(image.shape[0], 2) + pow(image.shape[1], 2))) offset_x = (diagonal - image.shape[0])/2 offset_y = (diagonal - image.shape[1])/2 dst_image = np.zeros((diagonal, diagonal, 3), dtype='uint8') image_center = (diagonal/2, diagonal/2) R = cv2.getRotationMatrix2D(image_center, angle, 1.0) dst_image[offset_x:(offset_x + image.shape[0]), \ offset_y:(offset_y + image.shape[1]), \ :] = image dst_image = cv2.warpAffine(dst_image, R, (diagonal, diagonal), flags=cv2.INTER_LINEAR) # Calculate the rotated bounding rect x0 = offset_x x1 = offset_x + image.shape[0] x2 = offset_x x3 = offset_x + image.shape[0] y0 = offset_y y1 = offset_y y2 = offset_y + image.shape[1] y3 = offset_y + image.shape[1] corners = np.zeros((3,4)) corners[0,0] = x0 corners[0,1] = x1 corners[0,2] = x2 corners[0,3] = x3 corners[1,0] = y0 corners[1,1] = y1 corners[1,2] = y2 corners[1,3] = y3 corners[2:] = 1 c = np.dot(R, corners) x = int(c[0,0]) y = int(c[1,0]) left = x right = x up = y down = y for i in range(4): x = int(c[0,i]) y = int(c[1,i]) if (x < left): left = x if (x > right): right = x if (y < up): up = y if (y > down): down = y h = down - up w = right - left cropped = np.zeros((w, h, 3), dtype='uint8') cropped[:, :, :] = dst_image[left:(left+w), up:(up+h), :] return cropped 

感谢Robula! 实际上,你不需要计算正弦和余弦两次。

 import cv2 def rotate_image(mat, angle): # angle in degrees height, width = mat.shape[:2] image_center = (width/2, height/2) rotation_mat = cv2.getRotationMatrix2D(image_center, angle, 1.) abs_cos = abs(rotation_mat[0,0]) abs_sin = abs(rotation_mat[0,1]) bound_w = int(height * abs_sin + width * abs_cos) bound_h = int(height * abs_cos + width * abs_sin) rotation_mat[0, 2] += bound_w/2 - image_center[0] rotation_mat[1, 2] += bound_h/2 - image_center[1] rotated_mat = cv2.warpAffine(mat, rotation_mat, (bound_w, bound_h)) return rotated_mat 

在四处搜寻一个干净而易懂的解决scheme,并通过上面的答案阅读试图了解他们,我最终想出了一个解决scheme,使用三angular。

我希望这有助于某人:)

 import cv2 import math def rotate_image(mat, angle): height, width = mat.shape[:2] image_center = (width / 2, height / 2) rotation_mat = cv2.getRotationMatrix2D(image_center, angle, 1) radians = math.radians(angle) sin = math.sin(radians) cos = math.cos(radians) bound_w = int((height * abs(sin)) + (width * abs(cos))) bound_h = int((height * abs(cos)) + (width * abs(sin))) rotation_mat[0, 2] += ((bound_w / 2) - image_center[0]) rotation_mat[1, 2] += ((bound_h / 2) - image_center[1]) rotated_mat = cv2.warpAffine(mat, rotation_mat, (bound_w, bound_h)) return rotated_mat 

编辑:请参阅下面的@Remi Cuingnet的答案。

你可以在下面的Github仓库中获得接受的答案的代码:

在2D中旋转图像matrix而不裁剪

随意分享和改进!

增加图像canvas(同样从中心不改变图像大小),以便它可以适应旋转后的图像,然后应用warpAffine

 Mat img = imread ("/path/to/image", 1); double offsetX, offsetY; double angle = -45; double width = img.size().width; double height = img.size().height; Point2d center = Point2d (width / 2, height / 2); Rect bounds = RotatedRect (center, img.size(), angle).boundingRect(); Mat resized = Mat::zeros (bounds.size(), img.type()); offsetX = (bounds.width - width) / 2; offsetY = (bounds.height - height) / 2; Rect roi = Rect (offsetX, offsetY, width, height); img.copyTo (resized (roi)); center += Point2d (offsetX, offsetY); Mat M = getRotationMatrix2D (center, angle, 1.0); warpAffine (resized, resized, M, resized.size()); 

在这里输入图像描述

感谢这个职位的每个人,它已经超级有用。 不过,在旋转90度时,我发现了一些黑线(使用玫瑰的python版本)。 这个问题似乎是一些int()圆整。 除此之外,我已经改变了angular度的标志,使其顺时针增长。

 def rotate_image(image, angle): '''Rotate image "angle" degrees. How it works: - Creates a blank image that fits any rotation of the image. To achieve this, set the height and width to be the image's diagonal. - Copy the original image to the center of this blank image - Rotate using warpAffine, using the newly created image's center (the enlarged blank image center) - Translate the four corners of the source image in the enlarged image using homogenous multiplication of the rotation matrix. - Crop the image according to these transformed corners ''' diagonal = int(math.ceil(math.sqrt(pow(image.shape[0], 2) + pow(image.shape[1], 2)))) offset_x = (diagonal - image.shape[0])/2 offset_y = (diagonal - image.shape[1])/2 dst_image = np.zeros((diagonal, diagonal, 3), dtype='uint8') image_center = (float(diagonal-1)/2, float(diagonal-1)/2) R = cv2.getRotationMatrix2D(image_center, -angle, 1.0) dst_image[offset_x:(offset_x + image.shape[0]), offset_y:(offset_y + image.shape[1]), :] = image dst_image = cv2.warpAffine(dst_image, R, (diagonal, diagonal), flags=cv2.INTER_LINEAR) # Calculate the rotated bounding rect x0 = offset_x x1 = offset_x + image.shape[0] x2 = offset_x + image.shape[0] x3 = offset_x y0 = offset_y y1 = offset_y y2 = offset_y + image.shape[1] y3 = offset_y + image.shape[1] corners = np.zeros((3,4)) corners[0,0] = x0 corners[0,1] = x1 corners[0,2] = x2 corners[0,3] = x3 corners[1,0] = y0 corners[1,1] = y1 corners[1,2] = y2 corners[1,3] = y3 corners[2:] = 1 c = np.dot(R, corners) x = int(round(c[0,0])) y = int(round(c[1,0])) left = x right = x up = y down = y for i in range(4): x = c[0,i] y = c[1,i] if (x < left): left = x if (x > right): right = x if (y < up): up = y if (y > down): down = y h = int(round(down - up)) w = int(round(right - left)) left = int(round(left)) up = int(round(up)) cropped = np.zeros((w, h, 3), dtype='uint8') cropped[:, :, :] = dst_image[left:(left+w), up:(up+h), :] return cropped 

如果只是旋转90度,也许这个代码可能是有用的。

  Mat img = imread("images.jpg"); Mat rt(img.rows, img.rows, CV_8U); Point2f pc(img.cols / 2.0, img.rows / 2.0); Mat r = getRotationMatrix2D(pc, 90, 1); warpAffine(img, rt, r, rt.size()); imshow("rotated", rt); 

希望它是有用的。

顺便说一下,只有90º旋转,这是一个更有效的+准确的function:

 def rotate_image_90(image, angle): angle = -angle rotated_image = image if angle == 0: pass elif angle == 90: rotated_image = np.rot90(rotated_image) elif angle == 180 or angle == -180: rotated_image = np.rot90(rotated_image) rotated_image = np.rot90(rotated_image) elif angle == -90: rotated_image = np.rot90(rotated_image) rotated_image = np.rot90(rotated_image) rotated_image = np.rot90(rotated_image) return rotated_image