用OpenCV實現Photoshop算法(一): 圖像旋轉

分類:IT技術 時間:2016-10-10


最近學習了OpenCV,於是想用它實現Photoshop的主要功能,用於照片處理。


對於一張照片,PS的一般處理步驟包括:

1, 旋轉圖片,校正位置。

2,剪切,調整大小,重新構圖。

3,調整色階、曲線,使圖片曝光正確、對比適中。

4,調整對比度、飽和度

5,印章去掉不想要的東西,液化調整形體線條

6,對於人像圖片,美膚、美白

7, 用色彩平衡、可選顏色等調整色調,形成照片調性

8,加一些光效

9,銳化


以後的一系列博文將采用OpenCV逐一實現Photoshop的算法和功能, 並用計算機視覺人工智能方式,嘗試超越Photoshop一點點。


本系列博文基於OpenCV,  編程語言為C++.    由於OpenCV的跨平臺性,代碼可以在用於Windows, linux, 作個接口後可用於android,IOS.


一、圖像旋轉

OpenCV中, 用 warpAffine()  仿射變換函數即可以實現旋轉。

例如,寫一個 旋轉函數 imageRotate1() 如下:

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>

//src為原圖像, dst為新圖像, angle為旋轉角度(正值為順時針旋轉,負值為逆時針旋轉)
int imageRotate1(InputArray src, OutputArray dst, double angle)
{
	Mat input = src.getMat();
	if( input.empty() ) {
		return -1;
	}

	//得到圖像大小
	int width = input.cols;
	int height = input.rows;

	//計算圖像中心點
	Point2f center;
	center.x = width / 2.0;
	center.y = height / 2.0;

	//獲得旋轉變換矩陣
	double scale = 1.0;
	Mat trans_mat = getRotationMatrix2D( center, -angle, scale );

	//仿射變換
	warpAffine( input, dst, trans_mat, Size(width, height));

	return 0;
}


圖像旋轉 -17度 的結果


在函數 imageRotate1()中,新圖像沿用原圖像大小。旋轉後,圖像的角部被切掉了。

這樣顯然不正確,需要調整圖像尺寸。


調整方式一: 擴大圖片,將原圖片包含進去,計算示意圖如下:


新圖片大小為: out_width = (width*cos(a)+height*sin(a);   out_height = height*cos(a)+width*sin(a))


修改原函數為 imageRotate2() :

//圖像旋轉: src為原圖像, dst為新圖像, angle為旋轉角度
int imageRotate2(InputArray src, OutputArray dst, double angle)
{
	Mat input = src.getMat();
	if( input.empty() ) {
		return -1;
	}

	//得到圖像大小
	int width = input.cols;
	int height = input.rows;

	//計算圖像中心點
	Point2f center;
	center.x = width / 2.0;
	center.y = height / 2.0;

	//獲得旋轉變換矩陣
	double scale = 1.0;
	Mat trans_mat = getRotationMatrix2D( center, -angle, scale );

	//計算新圖像大小
	double angle1 = angle  * CV_PI / 180. ;
	double a = sin(angle1) * scale;
	double b = cos(angle1) * scale;
	double out_width = height * fabs(a) + width * fabs(b);
	double out_height = width * fabs(a) + height * fabs(b);

	//仿射變換
	warpAffine( input, dst, trans_mat, Size(out_width, out_height));

	return 0;
}

圖像旋轉 -17度 的結果



還是不對,新圖像變大了,但圖像中心點不對,需要在旋轉矩陣中加入平移,在一次變換中同時完成旋轉和平移,將新圖像的中心點移到正確位置。 

再次修改函數為: imageRotate3()

//圖像旋轉: src為原圖像, dst為新圖像, angle為旋轉角度
int imageRotate3(InputArray src, OutputArray dst, double angle)
{
	Mat input = src.getMat();
	if( input.empty() ) {
		return -1;
	}

	//得到圖像大小
	int width = input.cols;
	int height = input.rows;

	//計算圖像中心點
	Point2f center;
	center.x = width / 2.0;
	center.y = height / 2.0;

	//獲得旋轉變換矩陣
	double scale = 1.0;
	Mat trans_mat = getRotationMatrix2D( center, -angle, scale );

	//計算新圖像大小
	double angle1 = angle  * CV_PI / 180. ;
	double a = sin(angle1) * scale;
	double b = cos(angle1) * scale;
	double out_width = height * fabs(a) + width * fabs(b);
	double out_height = width * fabs(a) + height * fabs(b);

	//在旋轉變換矩陣中加入平移量
	trans_mat.at<double>(0, 2) += cvRound( (out_width - width) / 2 );
	trans_mat.at<double>(1, 2) += cvRound( (out_height - height) / 2);

	//仿射變換
	warpAffine( input, dst, trans_mat, Size(out_width, out_height));

	return 0;
}

這一次正確了,新圖像變大了,同時圖像中心點移到了新的中心點,原圖像全部能顯示出來。




在實際照片旋轉中,我們經常采用另一種剪切形式的調整方式:圖像旋轉後,縮小圖片,使圖片各個邊角均不出現黑邊。 下圖紅框即為新圖象大小,如下:


這種調整方式下,新圖像大小的計算稍為有點復雜,在網上也沒有找到範例,只能自己計算了。

1,如上,旋轉後的外邊框大小為:    out_width =(width*cos(a)+height*sin(a);     out_height = height*cos(a)+width*sin(a))

2,  畫幾根輔助線,如下圖:(註意右邊圖中的粉紅三角形)

     其最長的邊長 len =  width*cos(a)
      角a 即旋轉角度
      由於外邊框大小已知,則角b 可計算出來。
      求解 Y:    Y = len / ( 1 / tan( a ) + 1 / tan( b ) )
                          X =  Y * 1 /  tan( b )

     最後求得  紅框的長、寬為:   new_width = out_width - 2 * X;     new_height = out_height - 2 * Y



再次修改函數為: imageRotate4()

增加了一個參數: isClip ,    當isClip為true時,采取縮小圖片的剪切方式,否則采取放大圖片的方式。

//圖像旋轉: src為原圖像, dst為新圖像, angle為旋轉角度, isClip表示是采取縮小圖片的方式
int imageRotate4(InputArray src, OutputArray dst, double angle, bool isClip)
{
	Mat input = src.getMat();
	if( input.empty() ) {
		return -1;
	}

	//得到圖像大小
	int width = input.cols;
	int height = input.rows;

	//計算圖像中心點
	Point2f center;
	center.x = width / 2.0;
	center.y = height / 2.0;

	//獲得旋轉變換矩陣
	double scale = 1.0;
	Mat trans_mat = getRotationMatrix2D( center, -angle, scale );

	//計算新圖像大小
	double angle1 = angle  * CV_PI / 180. ;
	double a = sin(angle1) * scale;
	double b = cos(angle1) * scale;
	double out_width = height * fabs(a) + width * fabs(b); //外邊框長度
	double out_height = width * fabs(a) + height * fabs(b);//外邊框高度

	int new_width, new_height;
	if ( ! isClip ) {
		new_width = cvRound(out_width);
		new_height = cvRound(out_height);
	} else {
		//calculate width and height of clip rect
		double angle2 = fabs(atan(height * 1.0 / width)); //即角度 b
		double len = width * fabs(b);
		double Y = len / ( 1 / fabs(tan(angle1)) + 1 / fabs(tan(angle2)) );
		double X = Y * 1 / fabs(tan(angle2));
		new_width = cvRound(out_width - X * 2);
		new_height= cvRound(out_height - Y * 2);
	}

	//在旋轉變換矩陣中加入平移量
	trans_mat.at<double>(0, 2) += cvRound( (new_width - width) / 2 );
	trans_mat.at<double>(1, 2) += cvRound( (new_height - height) / 2);

	//仿射變換
	warpAffine( input, dst, trans_mat, Size(new_width, new_height));

	return 0;
}

以下是 isClip為true,  旋轉角度為 10 的結果,可見圖片旋轉了、縮小了,沒有黑邊



由於不註意,人們拍照時經常拍歪了,一般歪得也不多,但照片就不好看了。

因此,有這麽一個問題:  能否智能判別圖像是否拍歪了,如果歪了,則自動計算出要旋轉擺正的角度。從而使得人們一拍照,就自動拍正。

(PS:這個功能是Photoshop沒有的,如果能實現,算不算超越Photoshop一點點呢?)


解決思路是這樣的:

    1, 圖像一般有一個或兩條長直線(通常這個可能是地平線、建築物等),且傾斜角度不大

    2, 利用 OpenCV圖像識別能力,識別出圖中有哪些直線。

    3, 分析這些直線,  如果長度足夠長、且位置相對居中,選取最長的兩條直線,測算擺正它所需的角度,做為返回值。


事實上,人工糾正圖片的Photoshop操作方式也是這樣的:我們在圖中人眼找一個基準線,用“度量工具”畫一條線,再點菜單“圖象/ 旋轉畫布/ 任意角度", 則Photoshop將計算出需要旋轉的角度。


嘗試寫了一個函數:   detectRotation(),  用於自動檢測擺正圖像的所需的旋轉角度, 如下: 

/**
 * 智能檢測圖像傾斜度
 * 返回值:返回0表示無檢測結果,返回非0表示擺正圖象需要旋轉的角度(-10至10度)
 */
double detectRotation(InputArray src)
{
	double max_angle = 6; //可旋轉的最大角度

	Mat in = src.getMat();
	if( in.empty() ) return 0;

	Mat input;

	//轉為灰度圖
	if ( in.type() == CV_8UC1 )
		input = in;
	else if ( in.type() == CV_8UC3 )
		cvtColor(in, input, CV_BGR2GRAY);
	else if ( in.type() == CV_8UC3 )
		cvtColor(in, input, CV_BGRA2GRAY);
	else
		return 0;

	Mat dst, cdst;

	//執行Canny邊緣檢測(檢測結果為dst, 為黑白圖)
	double threshold1 = 90;
	Canny(src, dst, threshold1, threshold1 * 3, 3);

	//將Canny邊緣檢測結果轉化為灰度圖像(cdst)
	cvtColor(dst, cdst, CV_GRAY2BGR);

	//執行霍夫線變換,檢測直線
	vector<Vec4i> lines; //存放檢測結果的vector
	double minLineLength = std::min(dst.cols, dst.rows) * 0.25; //最短線長度
	double maxLineGap = std::min(dst.cols, dst.rows) * 0.03 ; //最小線間距
	int threshold = 90;
	HoughLinesP(dst, lines, 1, CV_PI / 180, threshold, minLineLength, maxLineGap );

	//分析所需變量
	int x1, y1, x2 , y2; //直線的兩個端點
	int x, y;  //直線的中點
	double angle, rotate_angle; //直線的角度,擺正直線需要旋轉的角度
	double line_length; //直線長度
	double position_weighted; //直線的位置權重:靠圖像中央的線權重為1, 越靠邊的線權重越小
	double main_lens[2]; //用於存放最長的二條直線長度的數組 (這兩條直線即是主線條)
	double main_angles[2];//用於存放最長的二條直線的擺正需要旋轉的角度
	main_lens[0] = main_lens[1] = 0;
	main_angles[0] = main_angles[1] = 0;

	//逐個分析各條直線,判斷哪個是主線條
	for( size_t i = 0; i < lines.size(); i++ ) {
		//取得直線的兩個端點座標
		x1 = lines[i][0]; y1 = lines[i][1]; x2 = lines[i][2]; y2 = lines[i][3];
		x = (x1 + x2 ) / 2; y = (y1 + y2) / 2;
		//計算直線的角度
		angle =	(x1 == x2) ? 90 : ( atan ( (y1 - y2) * 1.0 / (x2 - x1) ) ) / CV_PI * 180;
		//擺正直線需要旋轉的角度. 如果超出可旋轉的最大角度,則忽略這個線。
		if ( fabs(angle - 0) <= max_angle ) {
			rotate_angle = angle - 0;
		} else if ( fabs(angle - 90) <= max_angle ) {
			rotate_angle = angle - 90;
		} else {
			continue;
		}

		//計算線的長度
		line_length = sqrt( (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)  );
		//計算直線的位置權重:靠圖像中央的線權重為1, 越靠邊的線權重越小
		position_weighted = 1;
		if ( x < dst.cols / 4 || x > dst.cols * 3 / 4  ) position_weighted *= 0.8;
		if ( x < dst.cols / 6 || x > dst.cols * 5 / 6  ) position_weighted *= 0.5;
		if ( x < dst.cols / 8 || x > dst.cols * 7 / 8  ) position_weighted *= 0.5;
		if ( y < dst.rows / 4 || y > dst.rows * 3 / 4  ) position_weighted *= 0.8;
		if ( y < dst.rows / 6 || y > dst.rows * 5 / 6  ) position_weighted *= 0.5;
		if ( y < dst.rows / 8 || y > dst.rows * 7 / 8  ) position_weighted *= 0.5;

		//如果 直線長度 * 位置權重 < 最小長度, 則這條線無效
		line_length = line_length * position_weighted;
		if ( line_length < minLineLength ) continue;



		//如果長度為前兩名,則存入數據
		if ( line_length > main_lens[1] )  {
			if (line_length > main_lens[0]) {
				 main_lens[1] = main_lens[0];
				 main_lens[0] = line_length;
				 main_angles[1] = main_angles[0];
				 main_angles[0] = rotate_angle;
				 //如果定義了 SHOW_LINE, 則將該線條畫出來
				 #ifdef SHOW_LINE
				 line( cdst, Point(x1, y1), Point(x2, y2), Scalar(0,0,255), 3, CV_AA);
				 #endif
			} else {
				main_lens[1] = line_length;
				main_angles[1] = rotate_angle;
			}
		}
	}

	//如果定義了 SHOW_LINE, 則在source_window中顯示cdst
       #ifdef SHOW_LINE
	imshow(source_window, cdst);
	#endif

	//最後,分析最長的二條直線,得出結果
	if ( main_lens[0] > 0 ) {
		//如果最長的線 與 次長的線 兩者長度相近,則返回兩者需要旋轉的角度的平均值
		if (main_lens[1] > 0 && (main_lens[0] - main_lens[1] / main_lens[0] < 0.2 )) {
			return (main_angles[0] + main_angles[1] ) / 2;
		} else {
			return main_angles[0];   //否則,返回最長的線需要旋轉的角度
		}
	} else {
		return 0;
	}
}


使用detectRotation()函數自動測試角度,並顯示出主要線條,運行結果:


恩,有那麽一點意思, 找出了幾個主線條,得出旋轉 -5 度,則可以擺正圖片。


當然,這個 detectRotation()函數還不是很智能,可用性還有待改進。



最後, 把本文所有代碼和主程序貼上來(有點長,不過方便復制)。配置好OpenCV開發環境,把代碼復制下來,就可以調試了。

代碼中需要說明的是:  由於opencv的滾動條只能顯示正值。 本例中rotation 的 滾動條,值為100時表示旋轉角度為0。 如果小於100, 表示旋轉角度為負。

#include <iostream>
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <cmath>

using namespace std;
using namespace cv;


#define SHOW_LINE

#define BASE 100

static string source_window = "source";
static string window_name = "image rotate";
static Mat src;
static int rotateDegree = 0 + BASE;
static int clip = 0;

//圖像旋轉: src為原圖像, dst為新圖像, angle為旋轉角度(正值為順時針旋轉,負值為逆時針旋轉)
int imageRotate1(InputArray src, OutputArray dst, double angle)
{
	Mat input = src.getMat();
	if( input.empty() ) {
		return -1;
	}

	//得到圖像大小
	int width = input.cols;
	int height = input.rows;

	//計算圖像中心點
	Point2f center;
	center.x = width / 2.0;
	center.y = height / 2.0;

	//獲得旋轉變換矩陣
	double scale = 1.0;
	Mat trans_mat = getRotationMatrix2D( center, -angle, scale );

	//仿射變換
	warpAffine( input, dst, trans_mat, Size(width, height));

	return 0;
}

//圖像旋轉: src為原圖像, dst為新圖像, angle為旋轉角度
int imageRotate2(InputArray src, OutputArray dst, double angle)
{
	Mat input = src.getMat();
	if( input.empty() ) {
		return -1;
	}

	//得到圖像大小
	int width = input.cols;
	int height = input.rows;

	//計算圖像中心點
	Point2f center;
	center.x = width / 2.0;
	center.y = height / 2.0;

	//獲得旋轉變換矩陣
	double scale = 1.0;
	Mat trans_mat = getRotationMatrix2D( center, -angle, scale );

	//計算新圖像大小
	double angle1 = angle  * CV_PI / 180. ;
	double a = sin(angle1) * scale;
	double b = cos(angle1) * scale;
	double out_width = height * fabs(a) + width * fabs(b);
	double out_height = width * fabs(a) + height * fabs(b);

	//仿射變換
	warpAffine( input, dst, trans_mat, Size(out_width, out_height));

	return 0;
}

//圖像旋轉: src為原圖像, dst為新圖像, angle為旋轉角度
int imageRotate3(InputArray src, OutputArray dst, double angle)
{
	Mat input = src.getMat();
	if( input.empty() ) {
		return -1;
	}

	//得到圖像大小
	int width = input.cols;
	int height = input.rows;

	//計算圖像中心點
	Point2f center;
	center.x = width / 2.0;
	center.y = height / 2.0;

	//獲得旋轉變換矩陣
	double scale = 1.0;
	Mat trans_mat = getRotationMatrix2D( center, -angle, scale );

	//計算新圖像大小
	double angle1 = angle  * CV_PI / 180. ;
	double a = sin(angle1) * scale;
	double b = cos(angle1) * scale;
	double out_width = height * fabs(a) + width * fabs(b);
	double out_height = width * fabs(a) + height * fabs(b);

	//在旋轉變換矩陣中加入平移量
	trans_mat.at<double>(0, 2) += cvRound( (out_width - width) / 2 );
	trans_mat.at<double>(1, 2) += cvRound( (out_height - height) / 2);

	//仿射變換
	warpAffine( input, dst, trans_mat, Size(out_width, out_height));

	return 0;
}


//圖像旋轉: src為原圖像, dst為新圖像, angle為旋轉角度, isClip表示是采取縮小圖片的方式
int imageRotate4(InputArray src, OutputArray dst, double angle, bool isClip)
{
	Mat input = src.getMat();
	if( input.empty() ) {
		return -1;
	}

	//得到圖像大小
	int width = input.cols;
	int height = input.rows;

	//計算圖像中心點
	Point2f center;
	center.x = width / 2.0;
	center.y = height / 2.0;

	//獲得旋轉變換矩陣
	double scale = 1.0;
	Mat trans_mat = getRotationMatrix2D( center, -angle, scale );

	//計算新圖像大小
	double angle1 = angle  * CV_PI / 180. ;
	double a = sin(angle1) * scale;
	double b = cos(angle1) * scale;
	double out_width = height * fabs(a) + width * fabs(b); //外邊框長度
	double out_height = width * fabs(a) + height * fabs(b);//外邊框高度

	int new_width, new_height;
	if ( ! isClip ) {
		new_width = cvRound(out_width);
		new_height = cvRound(out_height);
	} else {
		//calculate width and height of clip rect
		double angle2 = fabs(atan(height * 1.0 / width)); //即角度 b
		double len = width * fabs(b);
		double Y = len / ( 1 / fabs(tan(angle1)) + 1 / fabs(tan(angle2)) );
		double X = Y * 1 / fabs(tan(angle2));
		new_width = cvRound(out_width - X * 2);
		new_height= cvRound(out_height - Y * 2);
	}

	//在旋轉變換矩陣中加入平移量
	trans_mat.at<double>(0, 2) += cvRound( (new_width - width) / 2 );
	trans_mat.at<double>(1, 2) += cvRound( (new_height - height) / 2);

	//仿射變換
	warpAffine( input, dst, trans_mat, Size(new_width, new_height));

	return 0;
}

/**
 * 檢測圖像傾斜度
 * 返回值:返回0表示無檢測結果,返回非0表示擺正圖象需要旋轉的角度(-10至10度)
 */
double detectRotation(InputArray src)
{
	double max_angle = 6; //可旋轉的最大角度

	Mat in = src.getMat();
	if( in.empty() ) return 0;

	Mat input;

	//轉為灰度圖
	if ( in.type() == CV_8UC1 )
		input = in;
	else if ( in.type() == CV_8UC3 )
		cvtColor(in, input, CV_BGR2GRAY);
	else if ( in.type() == CV_8UC3 )
		cvtColor(in, input, CV_BGRA2GRAY);
	else
		return 0;

	Mat dst, cdst;

	//執行Canny邊緣檢測(檢測結果為dst, 為黑白圖)
	double threshold1 = 90;
	Canny(src, dst, threshold1, threshold1 * 3, 3);

	//將Canny邊緣檢測結果轉化為灰度圖像(cdst)
	cvtColor(dst, cdst, CV_GRAY2BGR);

	//執行霍夫線變換,檢測直線
	vector<Vec4i> lines; //存放檢測結果的vector
	double minLineLength = std::min(dst.cols, dst.rows) * 0.25; //最短線長度
	double maxLineGap = std::min(dst.cols, dst.rows) * 0.03 ; //最小線間距
	int threshold = 90;
	HoughLinesP(dst, lines, 1, CV_PI / 180, threshold, minLineLength, maxLineGap );

	//分析所需變量
	int x1, y1, x2 , y2; //直線的兩個端點
	int x, y;  //直線的中點
	double angle, rotate_angle; //直線的角度,擺正直線需要旋轉的角度
	double line_length; //直線長度
	double position_weighted; //直線的位置權重:靠圖像中央的線權重為1, 越靠邊的線權重越小
	double main_lens[2]; //用於存放最長的二條直線長度的數組 (這兩條直線即是主線條)
	double main_angles[2];//用於存放最長的二條直線的擺正需要旋轉的角度
	main_lens[0] = main_lens[1] = 0;
	main_angles[0] = main_angles[1] = 0;

	//逐個分析各條直線,判斷哪個是主線條
	for( size_t i = 0; i < lines.size(); i++ ) {
		//取得直線的兩個端點座標
		x1 = lines[i][0]; y1 = lines[i][1]; x2 = lines[i][2]; y2 = lines[i][3];
		x = (x1 + x2 ) / 2; y = (y1 + y2) / 2;
		//計算直線的角度
		angle =	(x1 == x2) ? 90 : ( atan ( (y1 - y2) * 1.0 / (x2 - x1) ) ) / CV_PI * 180;
		//擺正直線需要旋轉的角度. 如果超出可旋轉的最大角度,則忽略這個線。
		if ( fabs(angle - 0) <= max_angle ) {
			rotate_angle = angle - 0;
		} else if ( fabs(angle - 90) <= max_angle ) {
			rotate_angle = angle - 90;
		} else {
			continue;
		}

		//計算線的長度
		line_length = sqrt( (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)  );
		//計算直線的位置權重:靠圖像中央的線權重為1, 越靠邊的線權重越小
		position_weighted = 1;
		if ( x < dst.cols / 4 || x > dst.cols * 3 / 4  ) position_weighted *= 0.8;
		if ( x < dst.cols / 6 || x > dst.cols * 5 / 6  ) position_weighted *= 0.5;
		if ( x < dst.cols / 8 || x > dst.cols * 7 / 8  ) position_weighted *= 0.5;
		if ( y < dst.rows / 4 || y > dst.rows * 3 / 4  ) position_weighted *= 0.8;
		if ( y < dst.rows / 6 || y > dst.rows * 5 / 6  ) position_weighted *= 0.5;
		if ( y < dst.rows / 8 || y > dst.rows * 7 / 8  ) position_weighted *= 0.5;

		//如果 直線長度 * 位置權重 < 最小長度, 則這條線無效
		line_length = line_length * position_weighted;
		if ( line_length < minLineLength ) continue;



		//如果長度為前兩名,則存入數據
		if ( line_length > main_lens[1] )  {
			if (line_length > main_lens[0]) {
				 main_lens[1] = main_lens[0];
				 main_lens[0] = line_length;
				 main_angles[1] = main_angles[0];
				 main_angles[0] = rotate_angle;
				 //如果定義了 SHOW_LINE, 則將該線條畫出來
				 #ifdef SHOW_LINE
				 line( cdst, Point(x1, y1), Point(x2, y2), Scalar(0,0,255), 3, CV_AA);
				 #endif
			} else {
				main_lens[1] = line_length;
				main_angles[1] = rotate_angle;
			}
		}
	}

	//如果定義了 SHOW_LINE, 則在source_window中顯示cdst
    #ifdef SHOW_LINE
	imshow(source_window, cdst);
	#endif

	//最後,分析最長的二條直線,得出結果
	if ( main_lens[0] > 0 ) {
		//如果最長的線 與 次長的線 兩者長度相近,則返回兩者需要旋轉的角度的平均值
		if (main_lens[1] > 0 && (main_lens[0] - main_lens[1] / main_lens[0] < 0.2 )) {
			return (main_angles[0] + main_angles[1] ) / 2;
		} else {
			return main_angles[0];   //否則,返回最長的線需要旋轉的角度
		}
	} else {
		return 0;
	}
}


static void callbackAdjust(int , void *)
{
	Mat dst;

	//imageRotate1(src, dst, rotateDegree - BASE);
	//imageRotate2(src, dst, rotateDegree - BASE);
	//imageRotate3(src, dst, rotateDegree - BASE);

	bool isClip = ( clip == 1 );
	imageRotate4(src, dst, rotateDegree - BASE,  isClip );

	imshow(window_name, dst);
}


int main()
{
	src = http://blog.csdn.net/c80486/article/details/imread("building.jpg");

	if ( !src.data ) {
		cout << "error read image" << endl;
		return -1;
	}

	namedWindow(source_window);
	imshow(source_window, src);

	namedWindow(window_name);
	createTrackbar("rotate", window_name, &rotateDegree, BASE * 2, callbackAdjust);
	createTrackbar("clip", window_name, &clip, 1, callbackAdjust);

	//自動檢測旋轉角度
	double angle = detectRotation(src);
	if ( angle != 0 ) {
		rotateDegree = angle + BASE;
		setTrackbarPos("rotate", window_name, rotateDegree);
	}

	callbackAdjust(0, 0);

	waitKey();

        return 0;

}






Tags: Photoshop Android 人工智能 Windows 照片處理

文章來源:


ads
ads

相關文章
ads

相關文章

ad