title: Align images based on a detected features in Opencv
body: <p>Hi I've a base image and other images that I'd like to rotate with the same angle as the base image. </p>
  
  <p>this is my base image.</p>
  
  <p><img src="https://i.stack.imgur.com/lt5ub.jpg" alt="enter image description here"></p>
  
  <p>this is an example image that I'd like to rotate. </p>
  
  <p><img src="https://i.stack.imgur.com/eb5G2.jpg" alt="enter image description here"></p>
  
  <p>here my full code. </p>
  
  <pre><code>  #include &lt;stdio.h&gt;
  #include &lt;iostream&gt;
  #include "opencv2/core/core.hpp"
  #include "opencv2/features2d/features2d.hpp"
  #include "opencv2/highgui/highgui.hpp"
  #include "opencv2/calib3d/calib3d.hpp"
  #include "opencv2/nonfree/nonfree.hpp"
  #include "opencv2/imgproc/imgproc.hpp"
  
  #define PI 3.14159265
  
  using namespace cv;
  using namespace std;
  
  
  void rotate(cv::Mat&amp; src, double angle, cv::Mat&amp; dst)
  {
      int len = std::max(src.cols, src.rows);
       cv::Point2f pt(len/2., len/2.);
       cv::Mat r = cv::getRotationMatrix2D(pt, angle, 1.0);
  
       cv::warpAffine(src, dst, r, cv::Size(len, len));
  }
  
  
  
  float angleBetween(const Point &amp;v1, const Point &amp;v2)
  {
      float len1 = sqrt(v1.x * v1.x + v1.y * v1.y);
      float len2 = sqrt(v2.x * v2.x + v2.y * v2.y);
  
      float dot = v1.x * v2.x + v1.y * v2.y;
  
      float a = dot / (len1 * len2);
  
      if (a &gt;= 1.0)
          return 0.0;
      else if (a &lt;= -1.0)
          return PI;
      else{
          int degree;
          degree = acos(a)*180/PI;
          return degree;
          };
  }
  
  
  
  int main()
  {
  
      Mat char1 = imread( "/Users/Rodrane/Documents/XCODE/OpenCV/mkedenemeleri/anarev/rotated.jpg",CV_LOAD_IMAGE_GRAYSCALE );
  
      Mat image = imread("/Users/Rodrane/Documents/XCODE/OpenCV/mkedenemeleri/anarev/gain2000_crop.jpg", CV_LOAD_IMAGE_GRAYSCALE );
  
  
  
  
      if( !char1.data )
      {
          std::cout&lt;&lt; "Error reading object " &lt;&lt; std::endl;
          return -1;
      }
  
      GaussianBlur( char1, char1, Size(3, 3), 2, 2 );
      GaussianBlur( image, image, Size(3, 3), 2, 2 );
      adaptiveThreshold(char1,char1,255,CV_ADAPTIVE_THRESH_MEAN_C,CV_THRESH_BINARY,9,14);
      adaptiveThreshold(image,image,255,CV_ADAPTIVE_THRESH_MEAN_C,CV_THRESH_BINARY,9,14);
  
      //Detect the keypoints using SURF Detector
      int minHessian = 200;
  
      SurfFeatureDetector detector( minHessian );
      std::vector&lt;KeyPoint&gt; kp_object;
  
      detector.detect( char1, kp_object );
  
      //Calculate descriptors (feature vectors)
      SurfDescriptorExtractor extractor;
      Mat des_object;
  
      extractor.compute( char1, kp_object, des_object );
  
      FlannBasedMatcher matcher;
  
  
      namedWindow("Good Matches");
  
      std::vector&lt;Point2f&gt; obj_corners(4);
  
      //Get the corners from the object
      obj_corners[0] = cvPoint(0,0);
      obj_corners[1] = cvPoint( char1.cols, 0 );
      obj_corners[2] = cvPoint( char1.cols, char1.rows );
      obj_corners[3] = cvPoint( 0, char1.rows );
  
  
  
      Mat frame;
  
  
  
  
      Mat des_image, img_matches;
      std::vector&lt;KeyPoint&gt; kp_image;
      std::vector&lt;vector&lt;DMatch &gt; &gt; matches;
      std::vector&lt;DMatch &gt; good_matches;
      std::vector&lt;Point2f&gt; obj;
      std::vector&lt;Point2f&gt; scene;
      std::vector&lt;Point2f&gt; scene_corners(4);
      Mat H;
  
  
      detector.detect( image, kp_image );
      extractor.compute( image, kp_image, des_image );
  
      matcher.knnMatch(des_object, des_image, matches, 2);
  
      for(int i = 0; i &lt; min(des_image.rows-1,(int) matches.size()); i++) //THIS LOOP IS SENSITIVE TO SEGFAULTS
      {
          if((matches[i][0].distance &lt; 0.6*(matches[i][1].distance)) &amp;&amp; ((int) matches[i].size()&lt;=2 &amp;&amp; (int) matches[i].size()&gt;0))
          {
              good_matches.push_back(matches[i][0]);
          }
      }
  
  
  
      //Draw only "good" matches
  
  
      drawMatches( char1, kp_object, image, kp_image, good_matches, img_matches, Scalar::all(-1), Scalar::all(-1), vector&lt;char&gt;(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
  
      if (good_matches.size() &gt;= 4)
      {
          for( int i = 0; i &lt; good_matches.size(); i++ )
          {
              //Get the keypoints from the good matches
              obj.push_back( kp_object[ good_matches[i].queryIdx ].pt );
              scene.push_back( kp_image[ good_matches[i].trainIdx ].pt );
              cout&lt;&lt;angleBetween(obj[i],scene[i])&lt;&lt;endl; //angles between images
  
          }
  
          H = findHomography( obj, scene, CV_RANSAC );
  
  
          perspectiveTransform( obj_corners, scene_corners, H);
  
         // cout&lt;&lt;angleBetween(obj[0], scene[0])&lt;&lt;endl;
  
  
          //Draw lines between the corners (the mapped object in the scene image )
  
      }
  
      //Show detected matches
      // resize(img_matches, img_matches, Size(img_matches.cols/2, img_matches.rows/2));
  
      imshow( "Good Matches", img_matches );
      waitKey();
  
      return 0;
  }
  </code></pre>
  
  <p>what actually my code doing is; </p>
  
  <ul>
  <li>I do detect features of both images</li>
  <li>Calculate degrees between point of my base image and example image</li>
  </ul>
  
  <p>since all degrees between points are different how can I rotate my image depending on a features? </p>
  
  <p>also for example lets say features of character <strong>M</strong> is detected and the angle is 30 in some conditions rotating image for degree 30 will give me horizontally aligned but vertically wrong. </p>
  
  <p>the problem is even the first features are in the same line this doesn't mean example image rotated correctly (it might need rotate 180 degrees more for example) </p>