1. 程式人生 > >影象處理(二)——影象仿射變換

影象處理(二)——影象仿射變換

這次實驗是要設計一個可以讓圖形進行繞任意中心任意角度旋轉的函式WarpAffine,其核心大概就是使用雙線性差值進行重取樣。
在數學上,雙線性插值是有兩個變數的插值函式的線性插值擴充套件,其核心思想是在兩個方向分別進行一次線性插值。

在程式碼中實現雙線性插值要注意原影象和目標影象的原點均旋轉左上角,然後根據插值公式計算目標影象每點畫素,得到結果大致如下:

簡單來說,就是使用
int x=(i+0.5)m/a-0.5
int y=(j+0.5)n/b-0.5
來代替
int x=i
m/a
int y=j
n/b

除了雙線性插值之外,還需要的就是影象旋轉操作了。我在做影象旋轉時,首先新建立了和原影象大小相等的新影象,還有指定旋轉中心,然後使用getRotationMatrix2D方法來獲取旋轉矩陣(2*3矩陣)。
在getRotatePoint()函式裡,使用了這樣一個for迴圈來完成所需功能:
在這裡插入圖片描述


得到結果如圖所示:
在這裡插入圖片描述

在這裡插入圖片描述改變旋轉中心和旋轉角度:
在這裡插入圖片描述
在這裡插入圖片描述
在完成影象旋轉的操作之後,我又想更方便的、不需要在命令列介面手動輸入旋轉中心和旋轉角度的操作,於是想到了上個實驗中使用的滑動條語句,便把對旋轉角度和旋轉中心的設定都放到了滑動條中,可以實現在影象視窗中完成任意角度和中心的選擇。
在這裡插入圖片描述
———————————————————————————————————
圖片和程式碼請自取
在這裡插入圖片描述

#include "stdafx.h"
#include <iostream>  
#include<vector>
#include<algorithm>
#include <opencv2\opencv.hpp>  
#include <opencv2\highgui\highgui.hpp>  
using namespace std;
using namespace cv;
#define pi 3.1415926

vector<cv::Point2i> Rotate(cv::Mat srcImage, vector<cv::Point2i> Points, const cv::Point rotate_center, const double angle) {
   vector<cv::Point2i> dstPoints;
   int x1 = 0, y1 = 0;
   int row = srcImage.rows;
   for (size_t i = 0; i < Points.size(); i++)
   {
   	x1 = Points.at(i).x;
   	y1 = row - Points.at(i).y;
   	int x2 = rotate_center.x;
   	int y2 = row - rotate_center.y;
   	int x = cvRound((x1 - x2)*cos(pi / 180.0 * angle) - (y1 - y2)*sin(pi / 180.0 * angle) + x2);
   	int y = cvRound((x1 - x2)*sin(pi / 180.0 * angle) + (y1 - y2)*cos(pi / 180.0 * angle) + y2);
   	y = row - y;
   	dstPoints.push_back(Point2i(x, y));
   }
   return dstPoints;
}

int main() {
   Mat src = imread("../res/圖片1.jpg");
   Point2i point(100, 100);
   vector<cv::Point2i> Points;
   Points.push_back(point);
   cv::circle(src, point, 2, cv::Scalar(255, 0, 0), 2);
   cv::imshow("src image ", src);

   cv::Mat dst;
   //旋轉角度      
   double angle ;
   //旋轉中心
   int m,n;
   cout << "請輸入旋轉角度、旋轉中心x軸座標、旋轉中心y軸座標:" << endl;
   cin >> angle >> m >> n;
   //輸出影象的尺寸與原圖一樣    
   cv::Size dst_sz(src.cols, src.rows);
   //指定旋轉中心      
   cv::Point2f center(src.cols / m, src.rows / n);

   //獲取旋轉矩陣(2x3矩陣)      
   cv::Mat rot_mat = cv::getRotationMatrix2D(center, angle, 1.0);
      
   cv::Scalar borderColor = Scalar(0, 238, 0);
   cv::warpAffine(src, dst, rot_mat, dst_sz, INTER_LINEAR, BORDER_CONSTANT, borderColor);
   //cv::warpAffine(src, dst, rot_mat, dst_sz, INTER_LINEAR, BORDER_REPLICATE);  

   vector<cv::Point2i> dstPoints = Rotate(dst, Points, center, angle);
   cv::circle(dst, dstPoints.at(0), 5, cv::Scalar(0, 0, 255), 2);
   cv::imshow("Rotation Image", dst);
   waitKey(0);
   return 0;
}