zoukankan      html  css  js  c++  java
  • 透视变换 任意角度 三维透视 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('旋转矩阵:
    ', 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;
    }
    
    
  • 相关阅读:
    StatusBar
    iOS开发UI篇-UITabBarController简单介绍
    iOS最全梳理
    UITabbarController的UITabbarItem(例:"我的")点击时,判断是否登录
    iOS APP 发布上架流程
    IOS开发
    IT教育课程考评系统开发-26
    IT教育课程考评系统开发-25
    2020100201-1
    IT教育课程考评系统开发-24
  • 原文地址:https://www.cnblogs.com/yanghailin/p/11737085.html
Copyright © 2011-2022 走看看