透视变换 任意角度 三维透视 python c++ opencv两种语言

效果图:键盘控制各个x,y,z,还有fov数值

一开始的w, h = img.shape[0:2]这里宽、高错乱,原因未知,只能这么用
python版本的:

# -*- coding:utf-8 -*-
import cv2
import numpy as np

def rad(x):
  return x * np.pi / 180


img = cv2.imread("./dog.jpeg")
cv2.namedWindow("original",0)
cv2.imshow("original", img)

# 扩展图像,保证内容不超出可视范围
img = cv2.copyMakeBorder(img, 200, 200, 200, 200, cv2.BORDER_CONSTANT, 0)
w, h = img.shape[0:2]

anglex = 0
angley = 30
anglez = 0 #是旋转
fov = 42
while 1:
  # 镜头与图像间的距离,21为半可视角,算z的距离是为了保证在此可视角度下恰好显示整幅图像
  z = np.sqrt(w ** 2 + h ** 2) / 2 / np.tan(rad(fov / 2))
  # 齐次变换矩阵
  rx = np.array([[1, 0, 0, 0],
          [0, np.cos(rad(anglex)), -np.sin(rad(anglex)), 0],
          [0, -np.sin(rad(anglex)), np.cos(rad(anglex)), 0, ],
          [0, 0, 0, 1]], np.float32)

  ry = np.array([[np.cos(rad(angley)), 0, np.sin(rad(angley)), 0],
          [0, 1, 0, 0],
          [-np.sin(rad(angley)), 0, np.cos(rad(angley)), 0, ],
          [0, 0, 0, 1]], np.float32)

  rz = np.array([[np.cos(rad(anglez)), np.sin(rad(anglez)), 0, 0],
          [-np.sin(rad(anglez)), np.cos(rad(anglez)), 0, 0],
          [0, 0, 1, 0],
          [0, 0, 0, 1]], np.float32)

  r = rx.dot(ry).dot(rz)

  # 四对点的生成
  pcenter = np.array([h / 2, w / 2, 0, 0], np.float32)

  p1 = np.array([0, 0, 0, 0], np.float32) - pcenter
  p2 = np.array([w, 0, 0, 0], np.float32) - pcenter
  p3 = np.array([0, h, 0, 0], np.float32) - pcenter
  p4 = np.array([w, h, 0, 0], np.float32) - pcenter

  dst1 = r.dot(p1)
  dst2 = r.dot(p2)
  dst3 = r.dot(p3)
  dst4 = r.dot(p4)

  list_dst = [dst1, dst2, dst3, dst4]

  org = np.array([[0, 0],
          [w, 0],
          [0, h],
          [w, h]], np.float32)

  dst = np.zeros((4, 2), np.float32)

  # 投影至成像平面
  for i in range(4):
    dst[i, 0] = list_dst[i][0] * z / (z - list_dst[i][2]) + pcenter[0]
    dst[i, 1] = list_dst[i][1] * z / (z - list_dst[i][2]) + pcenter[1]

  warpR = cv2.getPerspectiveTransform(org, dst)

  result = cv2.warpPerspective(img, warpR, (h, w))
  cv2.namedWindow("result",0)
  cv2.imshow("result", result)
  c = cv2.waitKey(30)

  # anglex += 3      #auto rotate
  # anglez += 1       #auto rotate
  # angley += 2      #auto rotate

  # 键盘控制
  if 27 == c: # Esc quit
    break;
  if c == ord('w'):
    anglex += 1
  if c == ord('s'):
    anglex -= 1
  if c == ord('a'):
    angley += 1
    # dx=0
  if c == ord('d'):
    angley -= 1
  if c == ord('u'):
    anglez += 1
  if c == ord('p'):
    anglez -= 1
  if c == ord('t'):
    fov += 1
  if c == ord('r'):
    fov -= 1
  if c == ord(' '):
    anglex = angley = anglez = 0
  if c == ord('q'):
    print("======================================")
    print('旋转矩阵:\n', r)
    print("angle alpha: ", anglex, 'angle beta: ', angley, "dz: ", anglez, ": ", z)

cv2.destroyAllWindows()

c++ 版本:

#include <iostream>
#include <math.h>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;

double rad(double x)
{
    return x * CV_PI / 180.0;
}

int main(int argc, char *argv[])
{
    Mat img = imread("dog.jpeg");
    namedWindow("original",0);
    imshow("original",img);
    copyMakeBorder(img,img,200,200,200,200,BORDER_CONSTANT,0);

    //    int w = img.cols;
    //    int h = img.rows;
    int h = img.cols;
    int w = img.rows;
    double anglex = 0;
    double angley = -62.72;
    double anglez = 32;
    double fov = 56;
    while(1)
    {
        double z = sqrt(w*w + h*h)/2.0/tan(rad(fov/2.0));

        double arr_x[4][4] = {1,0,0,0,
                              0,cos(rad(anglex)),-sin(rad(anglex)),0,
                              0,-sin(rad(anglex)),cos(rad(anglex)),0,
                              0,0,0,1};
        Mat rx(4,4,CV_64F,arr_x);

        double arr_y[4][4] = {cos(rad(angley)),0,sin(rad(angley)),0,
                              0,1,0,0,
                              -sin(rad(angley)),0,cos(rad(angley)),0,
                              0,0,0,1};
        Mat ry(4,4,CV_64F,arr_y);

        double arr_z[4][4] = {cos(rad(anglez)),sin(rad(anglez)),0,0,
                              -sin(rad(anglez)),cos(rad(anglez)),0,0,
                              0,0,1,0,
                              0,0,0,1};
        Mat rz(4,4,CV_64F,arr_z);
        Mat r = rx*ry*rz;
        double arr_center[4] = {h/2.0,w/2.0,0,0};
        Mat pcenter(1,4,CV_64F,arr_center);
        double arr_t1[4] = {0,0,0,0},arr_t2[4] = {w,0,0,0}, arr_t3[4] = {0,h,0,0}, arr_t4[4] = {w,h,0,0};
        Mat m_t1(1,4,CV_64F,arr_t1),m_t2(1,4,CV_64F,arr_t2),m_t3(1,4,CV_64F,arr_t3),m_t4(1,4,CV_64F,arr_t4);
        Mat p1 = m_t1 - pcenter;
        Mat p2 = m_t2 - pcenter;
        Mat p3 = m_t3 - pcenter;
        Mat p4 = m_t4 - pcenter;

        Mat r_transpose;
        transpose(r,r_transpose);
        Mat dst1 = p1 * r_transpose;
        Mat dst2 = p2 * r_transpose;
        Mat dst3 = p3 * r_transpose;
        Mat dst4 = p4 * r_transpose;
        vector<Mat> list_dst = {dst1,dst2,dst3,dst4};
        Point2f org[4] = {Point2f(0,0),Point2f(w,0),Point2f(0,h),Point2f(w,h)};
        Point2f dst[4];
        for(int i=0;i<4;i++)
        {
            dst[i].x = list_dst[i].at<double>(0,0) * z / (z - list_dst[i].at<double>(0,2)) + pcenter.at<double>(0,0);
            dst[i].y = list_dst[i].at<double>(0,1) * z / (z - list_dst[i].at<double>(0,2)) + pcenter.at<double>(0,1);
        }
        Mat result;
        cv::Mat warpMatrix = cv::getPerspectiveTransform(org, dst);
        cv::warpPerspective(img, result, warpMatrix, Size(h,w));
        namedWindow("result",0);
        imshow("result",result);
        char c = waitKey(0);
        if(27 == c)
        {
            break;
        }
        if('w' == c)
        {
            anglex += 1;
        }
        if('s' == c)
        {
            anglex -= 1;
        }
        if('a' == c)
        {
            angley += 1;
        }
        if('d' == c)
        {
            angley -= 1;
        }
        if('u' == c)
        {
            anglez += 1;
        }
        if('p' == c)
        {
            anglez -= 1;
        }
        if('t' == c)
        {
            fov += 1;
        }
        if('r' == c)
        {
            fov -= 1;
        }
        if(' ' == c)
        {
            anglex = 0;
            angley = 0;
            anglez = 0;
        }
        if('q' == c)
        {
            cout<<"angle alpha(anglex): "<<anglex<<" angle beta(angley): "<<angley<<" dz(anglez): "<<anglez<<" z="<<z<<" fov="<<fov<<endl;
        }
    }
    return 0;
}

posted @ 2019-10-25 11:30  无左无右  阅读(1989)  评论(0编辑  收藏  举报