Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Just another solution. You can specify an arbitrary angle but not the center point of the rotation. The output size of the image is automatically calculated.

#include <iostream>
#include "opencv2/opencv.hpp"


// Return the rotation matrices for each rotation
void rotate(cv::Mat& src, double angle, cv::Mat& dst) {
  cv::Mat r = getRotationMatrix2D(cv::Point2f(), angle, 1.0);

  //4 coordinates of the image
  std::vector<cv::Point2f> corners(4);
  corners[0] = cv::Point2f(0, 0);
  corners[1] = cv::Point2f(0, src.rows);
  corners[2] = cv::Point2f(src.cols, 0);
  corners[3] = cv::Point2f(src.cols, src.rows);

  std::vector<cv::Point2f> cornersTransform(4);
  cv::transform(corners, cornersTransform, r);

  //Copy the 2x3 transformation matrix into a 3x3 transformation matrix
  cv::Mat H = cv::Mat::eye(3, 3, CV_64F);
  for(int i = 0; i < 2; i++) {
    for(int j = 0; j < 3; j++) {
      H.at<double>(i, j) = r.at<double>(i, j);
    }
  }

  double offsetX = 0.0, offsetY = 0.0, maxX = 0.0, maxY = 0.0;
  //Get max offset outside of the image and max width / height
  for(size_t i = 0; i < 4; i++) {
    if(cornersTransform[i].x < offsetX) {
      offsetX = cornersTransform[i].x;
    }

    if(cornersTransform[i].y < offsetY) {
      offsetY = cornersTransform[i].y;
    }

    if(cornersTransform[i].x > maxX) {
      maxX = cornersTransform[i].x;
    }

    if(cornersTransform[i].y > maxY) {
      maxY = cornersTransform[i].y;
    }
  }

  offsetX = -offsetX;
  offsetY = -offsetY;
  maxX += offsetX;
  maxY += offsetY;

  cv::Size size_warp(maxX, maxY);

  //Create the transformation matrix to be able to have all the pixels
  cv::Mat H2 = cv::Mat::eye(3, 3, CV_64F);
  H2.at<double>(0,2) = offsetX;
  H2.at<double>(1,2) = offsetY;

  warpPerspective(src, dst, H2*H, size_warp);
}

int main() {
  // Read in the image
  cv::Mat input;
  cv::VideoCapture capture("http://answers.opencv.org/upfiles/14303105806441826.jpg");
  if(!capture.isOpened()) {
    return -1;
  }
  capture >> input;
  if(input.empty()) {
    return -1;
  }

  cv::resize(input, input, cv::Size(), 0.5, 0.5);
  imshow("input", input);

  cv::Mat rotated;
  for(double angle = 0; angle < 360; angle += 1.0) {
    rotate(input, angle, rotated);
    cv::imshow("rotated", rotated);
    char c = cv::waitKey(30);
    if(c == 27) {
      break;
    }
  }

  return 0;
}