Photoshop algorithm with OpenCV (1): image rotation

Posted by pr0x on Sun, 12 May 2019 13:37:37 +0200

https://blog.csdn.net/c80486/article/details/51867128

For a photo, the general processing steps of PS include:

1. Rotate the picture and correct the position.

2. Cut, resize and reconstruct.

3. Adjust the color order and curve to make the pictures exposed correctly and contrast moderately.

4. Adjust contrast and saturation

5. Seals remove unwanted items and liquefy to adjust body lines.

6. For portrait pictures, skin and whitening

7. Use color balance and optional color to adjust the tone to form the tone of the photo.

8. Add some light efficiency

9, sharpen


In the future, a series of blogs will use OpenCV to realize the algorithm and function of Photoshop one by one, and try to surpass Photoshop a little by using computer vision artificial intelligence.


This series of blog posts is based on OpenCV and the programming language is C++. Because of the cross-platform nature of OpenCV, the code can be used in Windows, Linux, Android,IOS as an interface.


I. Image Rotation

In OpenCV, the warpAffine() affine transformation function is used to realize rotation.

For example, write a rotation function imageRotate1() as follows:

  1. #include <opencv2/core.hpp>  
  2. #include <opencv2/imgproc.hpp>  
  3.   
  4. //src is the original image, dst is the new image, and angle is the rotation angle (positive value is clockwise rotation, negative value is counterclockwise rotation)  
  5. int imageRotate1(InputArray src, OutputArray dst, double angle)  
  6. {  
  7.     Mat input = src.getMat();  
  8.     if( input.empty() ) {  
  9.         return -1;  
  10.     }  
  11.   
  12.     //Get image size  
  13.     int width = input.cols;  
  14.     int height = input.rows;  
  15.   
  16.     //Computing image centers  
  17.     Point2f center;  
  18.     center.x = width / 2.0;  
  19.     center.y = height / 2.0;  
  20.   
  21.     //Obtaining Rotation Transform Matrix  
  22.     double scale = 1.0;  
  23.     Mat trans_mat = getRotationMatrix2D( center, -angle, scale );  
  24.   
  25.     //affine transformation  
  26.     warpAffine( input, dst, trans_mat, Size(width, height));  
  27.   
  28.     return 0;  
  29. }  


Result of image rotation - 17 degrees


In the function imageRotate1(), the new image follows the original image size. After rotation, the corner of the image is cut off.

This is obviously incorrect, and the image size needs to be adjusted.


Adjustment 1: Enlarge the picture and include the original picture. The calculation sketch is as follows:


The new image size is: out_width = width * cos (a) + height * sin (a); out_height = height*cos(a)+width*sin(a)).


Modify the original function to imageRotate2():

  1. //Image rotation: src is the original image, dst is the new image, and angle is the rotation angle  
  2. int imageRotate2(InputArray src, OutputArray dst, double angle)  
  3. {  
  4.     Mat input = src.getMat();  
  5.     if( input.empty() ) {  
  6.         return -1;  
  7.     }  
  8.   
  9.     //Get image size  
  10.     int width = input.cols;  
  11.     int height = input.rows;  
  12.   
  13.     //Computing image centers  
  14.     Point2f center;  
  15.     center.x = width / 2.0;  
  16.     center.y = height / 2.0;  
  17.   
  18.     //Obtaining Rotation Transform Matrix  
  19.     double scale = 1.0;  
  20.     Mat trans_mat = getRotationMatrix2D( center, -angle, scale );  
  21.   
  22.     //Calculate new image size  
  23.     double angle1 = angle  * CV_PI / 180. ;  
  24.     double a = sin(angle1) * scale;  
  25.     double b = cos(angle1) * scale;  
  26.     double out_width = height * fabs(a) + width * fabs(b);  
  27.     double out_height = width * fabs(a) + height * fabs(b);  
  28.   
  29.     //affine transformation  
  30.     warpAffine( input, dst, trans_mat, Size(out_width, out_height));  
  31.   
  32.     return 0;  
  33. }  

Result of image rotation - 17 degrees



Or not, the new image becomes larger, but the center of the image is not right. It needs to add translation in the rotation matrix, complete rotation and translation simultaneously in a transformation, and move the center of the new image to the correct position.  

Modify the function again to: imageRotate3()

  1. //Image rotation: src is the original image, dst is the new image, and angle is the rotation angle  
  2. int imageRotate3(InputArray src, OutputArray dst, double angle)  
  3. {  
  4.     Mat input = src.getMat();  
  5.     if( input.empty() ) {  
  6.         return -1;  
  7.     }  
  8.   
  9.     //Get image size  
  10.     int width = input.cols;  
  11.     int height = input.rows;  
  12.   
  13.     //Computing image centers  
  14.     Point2f center;  
  15.     center.x = width / 2.0;  
  16.     center.y = height / 2.0;  
  17.   
  18.     //Obtaining Rotation Transform Matrix  
  19.     double scale = 1.0;  
  20.     Mat trans_mat = getRotationMatrix2D( center, -angle, scale );  
  21.   
  22.     //Calculate new image size  
  23.     double angle1 = angle  * CV_PI / 180. ;  
  24.     double a = sin(angle1) * scale;  
  25.     double b = cos(angle1) * scale;  
  26.     double out_width = height * fabs(a) + width * fabs(b);  
  27.     double out_height = width * fabs(a) + height * fabs(b);  
  28.   
  29.     //Adding translations to the rotation transformation matrix  
  30.     trans_mat.at<double>(0, 2) += cvRound( (out_width - width) / 2 );  
  31.     trans_mat.at<double>(1, 2) += cvRound( (out_height - height) / 2);  
  32.   
  33.     //affine transformation  
  34.     warpAffine( input, dst, trans_mat, Size(out_width, out_height));  
  35.   
  36.     return 0;  
  37. }  

This time correctly, the new image becomes larger, and the center of the image moves to the new center, the original image can be displayed.




In actual photo rotation, we often use another way of adjusting the cut form: after image rotation, reduce the image, so that no black edges appear in every corner of the picture. The following red box is the new image size, as follows:


In this way, the calculation of the size of the new image is a little complicated, and there is no example found on the Internet, so it can only be calculated by itself.

1. As above, the size of the outer border after rotation is as follows: out_width= (width*cos(a)+height*sin(a); (out_height=height*cos(a)+width*sin(a).)

2. Draw some auxiliary lines as follows: (Note the pink triangle in the right-hand picture)

The longest side length len = width*cos(a)
Angle a is the rotation angle.
Since the size of the outer border is known, the angle b can be calculated.
Solution Y: Y = len / 1 / Tan (a) + 1 / Tan (b)
                          X =  Y * 1 /  tan( b )

Finally, the length and width of the red box are: new_width = out_width - 2 * X; new_height = out_height - 2 * Y.



Modify the function again to: imageRotate4()

Added a parameter: isClip, when isClip is true, take the cut mode of reducing the picture, otherwise take the way of enlarging the picture.

  1. //Image rotation: src is the original image, dst is the new image, angle is the rotation angle, isClip means to reduce the image.  
  2. int imageRotate4(InputArray src, OutputArray dst, double angle, bool isClip)  
  3. {  
  4.     Mat input = src.getMat();  
  5.     if( input.empty() ) {  
  6.         return -1;  
  7.     }  
  8.   
  9.     //Get image size  
  10.     int width = input.cols;  
  11.     int height = input.rows;  
  12.   
  13.     //Computing image centers  
  14.     Point2f center;  
  15.     center.x = width / 2.0;  
  16.     center.y = height / 2.0;  
  17.   
  18.     //Obtaining Rotation Transform Matrix  
  19.     double scale = 1.0;  
  20.     Mat trans_mat = getRotationMatrix2D( center, -angle, scale );  
  21.   
  22.     //Calculate new image size  
  23.     double angle1 = angle  * CV_PI / 180. ;  
  24.     double a = sin(angle1) * scale;  
  25.     double b = cos(angle1) * scale;  
  26.     double out_width = height * fabs(a) + width * fabs(b); //Outer border length  
  27.     double out_height = width * fabs(a) + height * fabs(b);//Outer frame height  
  28.   
  29.     int new_width, new_height;  
  30.     if ( ! isClip ) {  
  31.         new_width = cvRound(out_width);  
  32.         new_height = cvRound(out_height);  
  33.     } else {  
  34.         //calculate width and height of clip rect  
  35.         double angle2 = fabs(atan(height * 1.0 / width)); //Angle b  
  36.         double len = width * fabs(b);  
  37.         double Y = len / ( 1 / fabs(tan(angle1)) + 1 / fabs(tan(angle2)) );  
  38.         double X = Y * 1 / fabs(tan(angle2));  
  39.         new_width = cvRound(out_width - X * 2);  
  40.         new_height= cvRound(out_height - Y * 2);  
  41.     }  
  42.   
  43.     //Adding translations to the rotation transformation matrix  
  44.     trans_mat.at<double>(0, 2) += cvRound( (new_width - width) / 2 );  
  45.     trans_mat.at<double>(1, 2) += cvRound( (new_height - height) / 2);  
  46.   
  47.     //affine transformation  
  48.     warpAffine( input, dst, trans_mat, Size(new_width, new_height));  
  49.   
  50.     return 0;  
  51. }  

Following is the result of isClip's true rotation angle of 10. It can be seen that the image has been rotated and shrunk with no black edge.



Because of the lack of attention, people often take pictures skewed, usually not much, but the pictures are not good-looking.

Therefore, there is a problem: whether the image can be judged intelligently, and if it is skewed, the angle to be rotated can be calculated automatically. As a result, people take photos automatically.

PS: This function is not available in Photoshop, if it can be implemented, it is not a little bit more than Photoshop?


The solution is as follows:

1. The image usually has one or two long straight lines (usually this may be the horizon, buildings, etc.) and the tilt angle is small.

2. Using OpenCV image recognition ability, we can identify which lines are in the graph.

3. Analyse these lines. If the length is long enough and the position is relatively in the middle, choose the longest two lines and calculate the angle needed to set them right as the return value.


In fact, the same is true of the manual Photoshop operation: we find a baseline for the human eye in the picture, draw a line with the Measuring Tool, and then click on the menu "Image/Rotary Canvas/Arbitrary Angle", then Photoshop will calculate the angle that needs to be rotated.


We try to write a function: detectRotation(). It is used to automatically detect the rotation angle of the pendulum image.

  1. /** 
  2.  * Intelligent Detection of Image Tilt 
  3.  * Return value: Return 0 indicates no detection result, return non-zero indicates the angle of rotation of the pendulum image (-10 to 10 degrees) 
  4.  */  
  5. double detectRotation(InputArray src)  
  6. {  
  7.     double max_angle = 6; //Maximum Rotating Angle  
  8.   
  9.     Mat in = src.getMat();  
  10.     if( in.empty() ) return 0;  
  11.   
  12.     Mat input;  
  13.   
  14.     //Conversion to grayscale  
  15.     if ( in.type() == CV_8UC1 )  
  16.         input = in;  
  17.     else if ( in.type() == CV_8UC3 )  
  18.         cvtColor(in, input, CV_BGR2GRAY);  
  19.     else if ( in.type() == CV_8UC3 )  
  20.         cvtColor(in, input, CV_BGRA2GRAY);  
  21.     else  
  22.         return 0;  
  23.   
  24.     Mat dst, cdst;  
  25.   
  26.     //Perform Canny edge detection (detection result is dst, black-and-white image)  
  27.     double threshold1 = 90;  
  28.     Canny(src, dst, threshold1, threshold1 * 3, 3);  
  29.   
  30.     //Converting Canny edge detection results into gray scale images (cdst)  
  31.     cvtColor(dst, cdst, CV_GRAY2BGR);  
  32.   
  33.     //Perform Hough Line Transform to Detect Lines  
  34.     vector<Vec4i> lines; //vector for storing test results  
  35.     double minLineLength = std::min(dst.cols, dst.rows) * 0.25; //Minimum Line Length  
  36.     double maxLineGap = std::min(dst.cols, dst.rows) * 0.03 ; //Minimum line spacing  
  37.     int threshold = 90;  
  38.     HoughLinesP(dst, lines, 1, CV_PI / 180, threshold, minLineLength, maxLineGap );  
  39.   
  40.     //Analysis of required variables  
  41.     int x1, y1, x2 , y2; //Two Endpoints of a Line  
  42.     int x, y;  //The midpoint of a straight line  
  43.     double angle, rotate_angle; //The angle at which a straight line needs to be rotated.  
  44.     double line_length; //Straight line length  
  45.     double position_weighted; //Line position weight: Line weight by the center of the image is 1, the smaller the line weight by the edge is.  
  46.     double main_lens[2]; //An array for storing the longest two straight lines (the two lines are the main lines)  
  47.     double main_angles[2];//The angle of rotation required for the alignment of the longest two straight lines  
  48.     main_lens[0] = main_lens[1] = 0;  
  49.     main_angles[0] = main_angles[1] = 0;  
  50.   
  51.     //Analyse each line one by one to determine which is the main line.  
  52.     forsize_t i = 0; i < lines.size(); i++ ) {  
  53.         //Get the coordinates of two endpoints of a straight line  
  54.         x1 = lines[i][0]; y1 = lines[i][1]; x2 = lines[i][2]; y2 = lines[i][3];  
  55.         x = (x1 + x2 ) / 2; y = (y1 + y2) / 2;  
  56.         //Calculate the angle of a straight line  
  57.         angle = (x1 == x2) ? 90 : ( atan ( (y1 - y2) * 1.0 / (x2 - x1) ) ) / CV_PI * 180;  
  58.         //Orthogonal alignment requires an angle of rotation. If the maximum angle of rotation is exceeded, the line is ignored.  
  59.         if ( fabs(angle - 0) <= max_angle ) {  
  60.             rotate_angle = angle - 0;  
  61.         } else if ( fabs(angle - 90) <= max_angle ) {  
  62.             rotate_angle = angle - 90;  
  63.         } else {  
  64.             continue;  
  65.         }  
  66.   
  67.         //Calculate the length of the line  
  68.         line_length = sqrt( (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)  );  
  69.         //Calculate the position weight of straight line: The line weight is 1 in the center of the image, and the smaller the line weight is, the more the line weight is, the smaller the line weight is.  
  70.         position_weighted = 1;  
  71.         if ( x < dst.cols / 4 || x > dst.cols * 3 / 4  ) position_weighted *= 0.8;  
  72.         if ( x < dst.cols / 6 || x > dst.cols * 5 / 6  ) position_weighted *= 0.5;  
  73.         if ( x < dst.cols / 8 || x > dst.cols * 7 / 8  ) position_weighted *= 0.5;  
  74.         if ( y < dst.rows / 4 || y > dst.rows * 3 / 4  ) position_weighted *= 0.8;  
  75.         if ( y < dst.rows / 6 || y > dst.rows * 5 / 6  ) position_weighted *= 0.5;  
  76.         if ( y < dst.rows / 8 || y > dst.rows * 7 / 8  ) position_weighted *= 0.5;  
  77.   
  78.         //If the line length * position weight < minimum length, the line is invalid  
  79.         line_length = line_length * position_weighted;  
  80.         if ( line_length < minLineLength ) continue;  
  81.   
  82.   
  83.   
  84.         //If the length is the first two, the data is stored  
  85.         if ( line_length > main_lens[1] )  {  
  86.             if (line_length > main_lens[0]) {  
  87.                  main_lens[1] = main_lens[0];  
  88.                  main_lens[0] = line_length;  
  89.                  main_angles[1] = main_angles[0];  
  90.                  main_angles[0] = rotate_angle;  
  91.                  //If SHOW_LINE is defined, the line is drawn.  
  92.                  #ifdef SHOW_LINE  
  93.                  line( cdst, Point(x1, y1), Point(x2, y2), Scalar(0,0,255), 3, CV_AA);  
  94.                  #endif  
  95.             } else {  
  96.                 main_lens[1] = line_length;  
  97.                 main_angles[1] = rotate_angle;  
  98.             }  
  99.         }  
  100.     }  
  101.   
  102.     //If SHOW_LINE is defined, cdst is displayed in source_window  
  103.        #ifdef SHOW_LINE  
  104.     imshow(source_window, cdst);  
  105.     #endif  
  106.   
  107.     //Finally, the longest two straight lines are analyzed and the results are obtained.  
  108.     if ( main_lens[0] > 0 ) {  
  109.         //If the length of the longest line is similar to that of the second line, return the average of the angles at which they need to rotate.  
  110.         if (main_lens[1] > 0 && (main_lens[0] - main_lens[1] / main_lens[0] < 0.2 )) {  
  111.             return (main_angles[0] + main_angles[1] ) / 2;  
  112.         } else {  
  113.             return main_angles[0];   //Otherwise, returning to the longest line requires an angle of rotation.  
  114.         }  
  115.     } else {  
  116.         return 0;  
  117.     }  
  118. }  


The detection Rotation () function is used to automatically test the angle and display the main lines.


Well, it's a little interesting. Find out several main lines and get a rotation of - 5 degrees. Then you can put the picture right.


Of course, the detectRotation() function is not very intelligent, and its usability needs to be improved.



Finally, paste all the code and the main program in this article (a bit long, but easy to copy). Configure the OpenCV development environment, copy the code and debug it.

It should be noted in the code that the scroll bar of opencv can only display positive values. In this case, the rotation scroll bar, with a value of 100, indicates that the rotation angle is 0. If less than 100, the rotation angle is negative.

  1. #include <iostream>  
  2. #include "opencv2/core.hpp"  
  3. #include "opencv2/imgproc.hpp"  
  4. #include "opencv2/highgui.hpp"  
  5. #include <cmath>  
  6.   
  7. using namespace std;  
  8. using namespace cv;  
  9.   
  10.   
  11. #define SHOW_LINE  
  12.   
  13. #define BASE 100  
  14.   
  15. static string source_window = "source";  
  16. static string window_name = "image rotate";  
  17. static Mat src;  
  18. static int rotateDegree = 0 + BASE;  
  19. static int clip = 0;  
  20.   
  21. //Image rotation: src is the original image, dst is the new image, and angle is the rotation angle (positive value is clockwise rotation, negative value is counterclockwise rotation)  
  22. int imageRotate1(InputArray src, OutputArray dst, double angle)  
  23. {  
  24.     Mat input = src.getMat();  
  25.     if( input.empty() ) {  
  26.         return -1;  
  27.     }  
  28.   
  29.     //Get image size  
  30.     int width = input.cols;  
  31.     int height = input.rows;  
  32.   
  33.     //Computing image centers  
  34.     Point2f center;  
  35.     center.x = width / 2.0;  
  36.     center.y = height / 2.0;  
  37.   
  38.     //Obtaining Rotation Transform Matrix  
  39.     double scale = 1.0;  
  40.     Mat trans_mat = getRotationMatrix2D( center, -angle, scale );  
  41.   
  42.     //affine transformation  
  43.     warpAffine( input, dst, trans_mat, Size(width, height));  
  44.   
  45.     return 0;  
  46. }  
  47.   
  48. //Image rotation: src is the original image, dst is the new image, and angle is the rotation angle  
  49. int imageRotate2(InputArray src, OutputArray dst, double angle)  
  50. {  
  51.     Mat input = src.getMat();  
  52.     if( input.empty() ) {  
  53.         return -1;  
  54.     }  
  55.   
  56.     //Get image size  
  57.     int width = input.cols;  
  58.     int height = input.rows;  
  59.   
  60.     //Computing image centers  
  61.     Point2f center;  
  62.     center.x = width / 2.0;  
  63.     center.y = height / 2.0;  
  64.   
  65.     //Obtaining Rotation Transform Matrix  
  66.     double scale = 1.0;  
  67.     Mat trans_mat = getRotationMatrix2D( center, -angle, scale );  
  68.   
  69.     //Calculate new image size  
  70.     double angle1 = angle  * CV_PI / 180. ;  
  71.     double a = sin(angle1) * scale;  
  72.     double b = cos(angle1) * scale;  
  73.     double out_width = height * fabs(a) + width * fabs(b);  
  74.     double out_height = width * fabs(a) + height * fabs(b);  
  75.   
  76.     //affine transformation  
  77.     warpAffine( input, dst, trans_mat, Size(out_width, out_height));  
  78.   
  79.     return 0;  
  80. }  
  81.   
  82. //Image rotation: src is the original image, dst is the new image, and angle is the rotation angle  
  83. int imageRotate3(InputArray src, OutputArray dst, double angle)  
  84. {  
  85.     Mat input = src.getMat();  
  86.     if( input.empty() ) {  
  87.         return -1;  
  88.     }  
  89.   
  90.     //Get image size  
  91.     int width = input.cols;  
  92.     int height = input.rows;  
  93.   
  94.     //Computing image centers  
  95.     Point2f center;  
  96.     center.x = width / 2.0;  
  97.     center.y = height / 2.0;  
  98.   
  99.     //Obtaining Rotation Transform Matrix  
  100.     double scale = 1.0;  
  101.     Mat trans_mat = getRotationMatrix2D( center, -angle, scale );  
  102.   
  103.     //Calculate new image size  
  104.     double angle1 = angle  * CV_PI / 180. ;  
  105.     double a = sin(angle1) * scale;  
  106.     double b = cos(angle1) * scale;  
  107.     double out_width = height * fabs(a) + width * fabs(b);  
  108.     double out_height = width * fabs(a) + height * fabs(b);  
  109.   
  110.     //Adding translations to the rotation transformation matrix  
  111.     trans_mat.at<double>(0, 2) += cvRound( (out_width - width) / 2 );  
  112.     trans_mat.at<double>(1, 2) += cvRound( (out_height - height) / 2);  
  113.   
  114.     //affine transformation  
  115.     warpAffine( input, dst, trans_mat, Size(out_width, out_height));  
  116.   
  117.     return 0;  
  118. }  
  119.   
  120.   
  121. //Image rotation: src is the original image, dst is the new image, angle is the rotation angle, isClip means to reduce the image.  
  122. int imageRotate4(InputArray src, OutputArray dst, double angle, bool isClip)  
  123. {  
  124.     Mat input = src.getMat();  
  125.     if( input.empty() ) {  
  126.         return -1;  
  127.     }  
  128.   
  129.     //Get image size  
  130.     int width = input.cols;  
  131.     int height = input.rows;  
  132.   
  133.     //Computing image centers  
  134.     Point2f center;  
  135.     center.x = width / 2.0;  
  136.     center.y = height / 2.0;  
  137.   
  138.     //Obtaining Rotation Transform Matrix  
  139.     double scale = 1.0;  
  140.     Mat trans_mat = getRotationMatrix2D( center, -angle, scale );  
  141.   
  142.     //Calculate new image size  
  143.     double angle1 = angle  * CV_PI / 180. ;  
  144.     double a = sin(angle1) * scale;  
  145.     double b = cos(angle1) * scale;  
  146.     double out_width = height * fabs(a) + width * fabs(b); //Outer border length  
  147.     double out_height = width * fabs(a) + height * fabs(b);//Outer frame height  
  148.   
  149.     int new_width, new_height;  
  150.     if ( ! isClip ) {  
  151.         new_width = cvRound(out_width);  
  152.         new_height = cvRound(out_height);  
  153.     } else {  
  154.         //calculate width and height of clip rect  
  155.         double angle2 = fabs(atan(height * 1.0 / width)); //Angle b  
  156.         double len = width * fabs(b);  
  157.         double Y = len / ( 1 / fabs(tan(angle1)) + 1 / fabs(tan(angle2)) );  
  158.         double X = Y * 1 / fabs(tan(angle2));  
  159.         new_width = cvRound(out_width - X * 2);  
  160.         new_height= cvRound(out_height - Y * 2);  
  161.     }  
  162.   
  163.     //Adding translations to the rotation transformation matrix  
  164.     trans_mat.at<double>(0, 2) += cvRound( (new_width - width) / 2 );  
  165.     trans_mat.at<double>(1, 2) += cvRound( (new_height - height) / 2);  
  166.   
  167.     //affine transformation  
  168.     warpAffine( input, dst, trans_mat, Size(new_width, new_height));  
  169.   
  170.     return 0;  
  171. }  
  172.   
  173. /** 
  174.  * Detection of image tilt 
  175.  * Return value: Return 0 indicates no detection result, return non-zero indicates the angle of rotation of the pendulum image (-10 to 10 degrees) 
  176.  */  
  177. double detectRotation(InputArray src)  
  178. {  
  179.     double max_angle = 6; //Maximum Rotating Angle  
  180.   
  181.     Mat in = src.getMat();  
  182.     if( in.empty() ) return 0;  
  183.   
  184.     Mat input;  
  185.   
  186.     //Conversion to grayscale  
  187.     if ( in.type() == CV_8UC1 )  
  188.         input = in;  
  189.     else if ( in.type() == CV_8UC3 )  
  190.         cvtColor(in, input, CV_BGR2GRAY);  
  191.     else if ( in.type() == CV_8UC3 )  
  192.         cvtColor(in, input, CV_BGRA2GRAY);  
  193.     else  
  194.         return 0;  
  195.   
  196.     Mat dst, cdst;  
  197.   
  198.     //Perform Canny edge detection (detection result is dst, black-and-white image)  
  199.     double threshold1 = 90;  
  200.     Canny(src, dst, threshold1, threshold1 * 3, 3);  
  201.   
  202.     //Converting Canny edge detection results into gray scale images (cdst)  
  203.     cvtColor(dst, cdst, CV_GRAY2BGR);  
  204.   
  205.     //Perform Hough Line Transform to Detect Lines  
  206.     vector<Vec4i> lines; //vector for storing test results  
  207.     double minLineLength = std::min(dst.cols, dst.rows) * 0.25; //Minimum Line Length  
  208.     double maxLineGap = std::min(dst.cols, dst.rows) * 0.03 ; //Minimum line spacing  
  209.     int threshold = 90;  
  210.     HoughLinesP(dst, lines, 1, CV_PI / 180, threshold, minLineLength, maxLineGap );  
  211.   
  212.     //Analysis of required variables  
  213.     int x1, y1, x2 , y2; //Two Endpoints of a Line  
  214.     int x, y;  //The midpoint of a straight line  
  215.     double angle, rotate_angle; //The angle at which a straight line needs to be rotated.  
  216.     double line_length; //Straight line length  
  217.     double position_weighted; //Line position weight: Line weight by the center of the image is 1, the smaller the line weight by the edge is.  
  218.     double main_lens[2]; //An array for storing the longest two straight lines (the two lines are the main lines)  
  219.     double main_angles[2];//The angle of rotation required for the alignment of the longest two straight lines  
  220.     main_lens[0] = main_lens[1] = 0;  
  221.     main_angles[0] = main_angles[1] = 0;  
  222.   
  223.     //Analyse each line one by one to determine which is the main line.  
  224.     forsize_t i = 0; i < lines.size(); i++ ) {  
  225.         //Get the coordinates of two endpoints of a straight line  
  226.         x1 = lines[i][0]; y1 = lines[i][1]; x2 = lines[i][2]; y2 = lines[i][3];  
  227.         x = (x1 + x2 ) / 2; y = (y1 + y2) / 2;  
  228.         //Calculate the angle of a straight line  
  229.         angle = (x1 == x2) ? 90 : ( atan ( (y1 - y2) * 1.0 / (x2 - x1) ) ) / CV_PI * 180;  
  230.         //Orthogonal alignment requires an angle of rotation. If the maximum angle of rotation is exceeded, the line is ignored.  
  231.         if ( fabs(angle - 0) <= max_angle ) {  
  232.             rotate_angle = angle - 0;  
  233.         } else if ( fabs(angle - 90) <= max_angle ) {  
  234.             rotate_angle = angle - 90;  
  235.         } else {  
  236.             continue;  
  237.         }  
  238.   
  239.         //Calculate the length of the line  
  240.         line_length = sqrt( (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)  );  
  241.         //Calculate the position weight of straight line: The line weight is 1 in the center of the image, and the smaller the line weight is, the more the line weight is, the smaller the line weight is.  
  242.         position_weighted = 1;  
  243.         if ( x < dst.cols / 4 || x > dst.cols * 3 / 4  ) position_weighted *= 0.8;  
  244.         if ( x < dst.cols / 6 || x > dst.cols * 5 / 6  ) position_weighted *= 0.5;  
  245.         if ( x < dst.cols / 8 || x > dst.cols * 7 / 8  ) position_weighted *= 0.5;  
  246.         if ( y < dst.rows / 4 || y > dst.rows * 3 / 4  ) position_weighted *= 0.8;  
  247.         if ( y < dst.rows / 6 || y > dst.rows * 5 / 6  ) position_weighted *= 0.5;  
  248.         if ( y < dst.rows / 8 || y > dst.rows * 7 / 8  ) position_weighted *= 0.5;  
  249.   
  250.         //If the line length * position weight < minimum length, the line is invalid  
  251.         line_length = line_length * position_weighted;  
  252.         if ( line_length < minLineLength ) continue;  
  253.   
  254.   
  255.   
  256.         //If the length is the first two, the data is stored  
  257.         if ( line_length > main_lens[1] )  {  
  258.             if (line_length > main_lens[0]) {  
  259.                  main_lens[1] = main_lens[0];  
  260.                  main_lens[0] = line_length;  
  261.                  main_angles[1] = main_angles[0];  
  262.                  main_angles[0] = rotate_angle;  
  263.                  //If SHOW_LINE is defined, the line is drawn.  
  264.                  #ifdef SHOW_LINE  
  265.                  line( cdst, Point(x1, y1), Point(x2, y2), Scalar(0,0,255), 3, CV_AA);  
  266.                  #endif  
  267.             } else {  
  268.                 main_lens[1] = line_length;  
  269.                 main_angles[1] = rotate_angle;  
  270.             }  
  271.         }  
  272.     }  
  273.   
  274.     //If SHOW_LINE is defined, cdst is displayed in source_window  
  275.     #ifdef SHOW_LINE  
  276.     imshow(source_window, cdst);  
  277.     #endif  
  278.   
  279.     //Finally, the longest two straight lines are analyzed and the results are obtained.  
  280.     if ( main_lens[0] > 0 ) {  
  281.         //If the length of the longest line is similar to that of the second line, return the average of the angles at which they need to rotate.  
  282.         if (main_lens[1] > 0 && (main_lens[0] - main_lens[1] / main_lens[0] < 0.2 )) {  
  283.             return (main_angles[0] + main_angles[1] ) / 2;  
  284.         } else {  
  285.             return main_angles[0];   //Otherwise, returning to the longest line requires an angle of rotation.  
  286.         }  
  287.     } else {  
  288.         return 0;  
  289.     }  
  290. }  
  291.   
  292.   
  293. static void callbackAdjust(int , void *)  
  294. {  
  295.     Mat dst;  
  296.   
  297.     //imageRotate1(src, dst, rotateDegree - BASE);  
  298.     //imageRotate2(src, dst, rotateDegree - BASE);  
  299.     //imageRotate3(src, dst, rotateDegree - BASE);  
  300.   
  301.     bool isClip = ( clip == 1 );  
  302.     imageRotate4(src, dst, rotateDegree - BASE,  isClip );  
  303.   
  304.     imshow(window_name, dst);  
  305. }  
  306.   
  307.   
  308. int main()  
  309. {  
  310.     src = imread("building.jpg");  
  311.   
  312.     if ( !src.data ) {  
  313.         cout << "error read image" << endl;  
  314.         return -1;  
  315.     }  
  316.   
  317.     namedWindow(source_window);  
  318.     imshow(source_window, src);  
  319.   
  320.     namedWindow(window_name);  
  321.     createTrackbar("rotate", window_name, &rotateDegree, BASE * 2, callbackAdjust);  
  322.     createTrackbar("clip", window_name, &clip, 1, callbackAdjust);  
  323.   
  324.     //Automatic Detection of Rotation Angle  
  325.     double angle = detectRotation(src);  
  326.     if ( angle != 0 ) {  
  327.         rotateDegree = angle + BASE;  
  328.         setTrackbarPos("rotate", window_name, rotateDegree);  
  329.     }  
  330.   
  331.     callbackAdjust(0, 0);  
  332.   
  333.     waitKey();  
  334.   
  335.         return 0;  
  336.   
  337. }  




Topics: OpenCV Programming Windows Linux