天天看點

圖像中某點繞點旋轉後的坐标,圖像旋轉坐标位置

圖像中某點繞點旋轉後的坐标,圖像旋轉坐标位置

在平面坐标上,任意點P(x1,y1),繞一個坐标點Q(x2,y2)旋轉θ角度後,新的坐标設為(x, y)的計算公式:

x= (x1 - x2)*cos(θ) - (y1 - y2)*sin(θ) + x2 ;
y= (x1 - x2)*sin(θ) + (y1 - y2)*cos(θ) + y2 ;      

這是在平面上的坐标旋轉公式,但在圖像中某個像素點旋轉一個角度後的坐标不能用上述公式直接求出,因為圖像(0,0)點的坐标的原點是在圖像的左上角。

假設圖像的寬度x高度為col x row,圖像中某個像素P(x1,y1),繞某個像素點Q(x2,y2)旋轉θ角度後,則該像素點的新坐标位置為(x, y),其計算公式為:

x1 = x1; 
y1 = row - y1; 
x2 = x2; 
y2 = row - y2; 
x = (x1 - x2)*cos(pi / 180.0 * θ) - (y1 - y2)*sin(pi / 180.0 * θ) + x2; 
y = (x1 - x2)*sin(pi / 180.0 * θ) + (y1 - y2)*cos(pi / 180.0 * θ) + y2; 
x=x; 
y = row - y;      

下面給出OpenCV的實作代碼:原圖像的大小500x577,像素點P(100,100),繞圖像中心Q(250,288.5)旋轉θ角度後,則該像素點的新坐标位置為(173, 60)

   關于OpenCV實作圖像旋轉的方法,可參考本人的部落格:《OpenCV圖像旋轉,指定填充背景顔色邊界顔色》

#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> getRotatePoint(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("D:\\OpencvTest\\16.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;    
  //旋轉角度-20度      
  double angle =- 20;
  //輸出圖像的尺寸與原圖一樣    
  cv::Size dst_sz(src.cols, src.rows);
  //指定旋轉中心      
  cv::Point2f center(src.cols / 2., src.rows / 2.);
 
  //擷取旋轉矩陣(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 = getRotatePoint(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;
}      
def rotate_point(point1, point2, angle, height):
    """
    點point1繞點point2旋轉angle後的點
    ======================================
    在平面坐标上,任意點P(x1,y1),繞一個坐标點Q(x2,y2)旋轉θ角度後,新的坐标設為(x, y)的計算公式:
    x= (x1 - x2)*cos(θ) - (y1 - y2)*sin(θ) + x2 ;
    y= (x1 - x2)*sin(θ) + (y1 - y2)*cos(θ) + y2 ;
    ======================================
    将圖像坐标(x,y)轉換到平面坐标(x`,y`):
    x`=x
    y`=height-y
    :param point1:
    :param point2: base point (基點)
    :param angle: 旋轉角度,正:表示逆時針,負:表示順時針
    :param height:
    :return:
    """
    x1, y1 = point1
    x2, y2 = point2
    # 将圖像坐标轉換到平面坐标
    y1 = height - y1
    y2 = height - y2
    x = (x1 - x2) * np.cos(np.pi / 180.0 * angle) - (y1 - y2) * np.sin(np.pi / 180.0 * angle) + x2
    y = (x1 - x2) * np.sin(np.pi / 180.0 * angle) + (y1 - y2) * np.cos(np.pi / 180.0 * angle) + y2
    # 将平面坐标轉換到圖像坐标
    y = height - y
    return (x, y)