Поворот изображения без обрезки в OpenCV в C ++

Я хотел бы повернуть изображение, но я не могу получить повернутое изображение без обрезки

Мое исходное изображение:

введите описание изображения здесь

Теперь я использую этот код:

#include  #include  #include  // 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; } 

И получите следующее изображение:

введите описание изображения здесь

Но я хотел бы получить следующее:

введите описание изображения здесь

Большое спасибо за Вашу помощь!

Мой ответ вдохновлен следующими сообщениями / блогами:

Основные идеи:

  • Настройка матрицы вращения путем добавления перевода в новый центр изображения
  • Использование cv::RotatedRect для cv::RotatedRect возможного использования существующих функций opencv

Код, проверенный с помощью opencv 3.4.1:

 #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 in pixel coordinates cv::Point2f center((src.cols-1)/2.0, (src.rows-1)/2.0); cv::Mat rot = cv::getRotationMatrix2D(center, angle, 1.0); // determine bounding rectangle, center not relevant cv::Rect2f bbox = cv::RotatedRect(cv::Point2f(), src.size(), angle).boundingRect2f(); // adjust transformation matrix rot.at(0,2) += bbox.width/2.0 - src.cols/2.0; rot.at(1,2) += bbox.height/2.0 - src.rows/2.0; cv::Mat dst; cv::warpAffine(src, dst, rot, bbox.size()); cv::imwrite("rotated_im.png", dst); return 0; } 

Просто попробуйте код ниже, идея проста:

  1. Вам нужно создать пустую картинку с максимальным размером, который вы ожидаете, при повороте под любым углом. Здесь вы должны использовать Pythagoras, как указано в приведенных выше комментариях.

  2. Теперь скопируйте исходное изображение на вновь созданное изображение и передайте его в warpAffine . Здесь вы должны использовать центр вновь созданного изображения для вращения.

  3. После warpAffine если вам нужно обрезать точное изображение для этого, переведите четыре угла исходного изображения в увеличенное изображение с использованием матрицы вращения, как описано здесь

  4. Найдите минимальный x и минимум y для верхнего угла и максимальный x и максимум y для нижнего угла из приведенного выше результата, чтобы обрезать изображение.

Это код:

 int theta = 0; Mat src,frame, frameRotated; src = imread("rotate.png",1); cout<(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(0,i)(0,i); //access smallest if(RotCo_Ordinate.at(1,i)(1,i); //access smallest y } for(int i=0;i<4;i++){ if(RotCo_Ordinate.at(0,i)>bound_Rect.width) bound_Rect.width=(int)RotCo_Ordinate.at(0,i); //access largest x if(RotCo_Ordinate.at(1,i)>bound_Rect.height) bound_Rect.height=RotCo_Ordinate.at(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; } в int theta = 0; Mat src,frame, frameRotated; src = imread("rotate.png",1); cout<(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(0,i)(0,i); //access smallest if(RotCo_Ordinate.at(1,i)(1,i); //access smallest y } for(int i=0;i<4;i++){ if(RotCo_Ordinate.at(0,i)>bound_Rect.width) bound_Rect.width=(int)RotCo_Ordinate.at(0,i); //access largest x if(RotCo_Ordinate.at(1,i)>bound_Rect.height) bound_Rect.height=RotCo_Ordinate.at(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; } 

введите описание изображения здесь

Обрезанное изображение

введите описание изображения здесьвведите описание изображения здесь

Спасибо, Робула! На самом деле вам не нужно дважды вычислять синус и косинус.

 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 

Спасибо @Haris! Вот версия 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 

После поиска для чистого и легкого для понимания решения и чтения ответов выше, пытаясь понять их, я в итоге придумал решение, использующее тригонометрию.

Надеюсь, это поможет кому-то 🙂

 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 

EDIT: см. Ответ @Remi Cuingnet ниже.

Увеличьте 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()); 

введите описание изображения здесь

Спасибо всем за этот пост, это было очень полезно. Тем не менее, я нашел несколько черных линий слева и вверх (используя версию python Роуза) при вращении на 90º. Проблема заключалась в том, что некоторые () округления. В дополнение к этому, я изменил знак угла, чтобы заставить его расти по часовой стрелке.

 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 gradleусов, возможно, этот код может быть полезен.

  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º здесь более эффективная + точная функция:

 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 
  • Преобразование одного цвета с помощью cvtColor
  • Как перевести эту обработку изображений из Matlab в OpenCV?
  • Различия в использовании функций «const cv :: Mat &», «cv :: Mat &», «cv :: Mat» или «const cv :: Mat» как параметры функции?
  • Eclipse успешно компилируется, но все же дает семантические ошибки
  • ошибка неразрешенного внешнего символа при соединении с OpenCV 3.0
  • Эффективно загружайте большой коврик в память в OpenCV
  • OpenCV Android Green Color Detection
  • неразрешенная ошибка внешнего символа при импорте библиотек для OpenCV2.3 в Visual Studios 2010 Express C ++
  • Утверждение не выполнено (size.width> 0 && size.height> 0)
  • Перестановка шумовой монеты в круглую форму
  • Не удалось найти модуль FindOpenCV.cmake (ошибка в процессе настройки)
  • Давайте будем гением компьютера.