3dmax,Opencv,OpenGL坐标系转换,渲染相关方法

在有些使用场景中,我们需要用到

1. 3dsMax

1.1外参数的导出

选中相机,点击菜单栏动画->保存动画->选择路径保存,用记事本打开这个 .xaf 文件,然后里面就会有相机的运动 变换矩阵T(R ,t),这里的R t是3dmax特有的格式,导出来的格式如下:

.........

<S t="0" v="0.933731 -0.357975 -0.001112 0.000814 -0.000983 0.999999 -0.357975 -0.933731 -0.000627 431.834839 -950.038086 100.185699" />

.........

其中,可以组成3dmax的变换矩阵:T,前半部分是R(3*3),后半部分是t(3*1),对于变换矩阵,3dmax的API文档定义为Matrix3 类型,其原文如下:

 

    http://docs.autodesk.com/3DSMAX/16/ENU/3ds-Max-SDK-Programmer-Guide/index.html?url=files/GUID-14497600-0839-4225-BA52-B571FCC8AEBF.htm,topicNumber=d30e24647

    A Matrix3 can also be used to specify an axis system. For example, the INode method Rotate() is used to rotate a node about a specified axis system. One of the arguments to this method is a Matrix3 that specifies this axis system. Essentially, a matrix is just an axis system.

    For example, if you think of an axis tripod in a viewport, this is basically all the information a matrix has. The axis tripod has three vectors (the directions of the axes: X, Y, Z) and a position in space (the point where the axes converge). A transformation matrix holds this same information. The 0th row of a matrix is the X vector, the 1st row of the matrix is the Y vector, the 2nd row of the matrix is the Z vector, and the 3rd row of the matrix is the position.

 

翻译过来就是这个矩阵是一个轴系统,对于矩阵中第一行是指定的X轴朝向,矩阵的第0行是X向量,矩阵的第1行是Y向量,矩阵的第2行是Z向量,矩阵的第3行是位置。

因此我猜测3dmax应该是按行存储的,由于3dmax和OpenGL一样是使用右手系的,因此,这里和计算及图形学定义的旋转与平移矩阵就匹配起来了,我们可以将导出的v="  ........."按行存入R,t中,而这里的R(3*3) 可以作为当前相机的观察坐标系,当前的t(3*1)可以作为当前观察坐标系原点,那么根据上面的定义我们可以计算出被拍摄物体转换到当前坐标系下面的变换矩阵,具体公式见书本吧。

1.2 内参数的计算

3dsMaxä¸­ï¼æå头ï¼FOVï¼æ°å­¦

设相机输出画幅为 Width*Hight

镜头焦距为  F(图中的Lens) ,水平视角为 a(图中的 横向FOV )) ,则 Film Back Size (w)= 2*F*Tan(a/2)

而内参数Fx,Fy = 缩放尺度( 像素/m ) * F( m )  

则  Fx  = Width  /  Film Back Size   *  F

            = Width  / (2*F*Tan(a/2))*F

            = Width  /   (2*Tan(a/2))

1.3 外参数转换,变换世界坐标系转换到观察坐标系(相机坐标系)

根据计算机图形学的世界坐标系到观察坐标系的转换公式,T(4*4)=R(4*4)*T(4*4)(具体公式见书本),计算出变换矩阵之后,就可以将被拍摄物体通过变换矩阵转换到观测的坐标系下了,此时设为Pc(x,y,z)。

2. 3dmax转换到OpenCV

由于这里3dmax的相机默认情况下是在世界坐标系原点朝向z轴负方向的,

参考:http://docs.autodesk.com/3DSMAX/16/ENU/3ds-Max-SDK-Programmer-Guide/index.html?url=files/GUID-14497600-0839-4225-BA52-B571FCC8AEBF.htm,topicNumber=d30e24647

此时观测坐标系的正方向是Y轴朝上,X轴朝向右边,Z轴朝屏幕外,根据OpenCV坐标系正方向,OpenCV坐标系相当于3dmax 的观测坐标系绕X轴旋转180度,那么将得到的坐标整体左乘以旋转矩阵{1,0,0,0,-1,0,0,0,-1},即得到OpenCV下的相机坐标,对此坐标进行归一化得到Pc(x/|z|,y/|z|,1),用内参K乘以Pc(x/|z|,y/|z|,1),得到像素坐标Puv(u,v,1),取前两位转换为像素坐标之后就可以直接显到屏幕上了。

3. 3dmax转换到OpenGL

3.1 modelViewMatrix计算

如果自己写 LookAt函数:

3dmax的相机默认朝向和OpenGL的默认朝向是一样的,因此,ModelViewMatrix就为上面的T,ProjectMatrix按照书本上的公式计算就OK了。

如果用glm::lookAt  函数需要一个位置、目标和上向量。它会创建一个和3.1的一样的观察矩阵

glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);

glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);

glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);

view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);

3.2 ProjectionMatrix计算

   先挖个坑,其他地方好像有蛮多类似教程,不重复造轮子了

3.3 模型使用

3.3.1 导入

 3dsMax选中模型,删除动画,旋转量归零,平移量归零,导出,只要顶点和面

然后用meshlab转换一下,不知道为什么,不转一下,好像显示不出来

3.3.2 控制

给模型设置好动画之后,选中模型,动画->保存动画,这里的模型RT导出来的格式为行优先,前三行为R,后一行为T,由于3dsMax的控制方式为先旋转,后平移,所以这里的使用的方法是T={R|t};

然后在渲染物体之前首先glMultMatrixd(T),就可以将物体转换到当前位置了

### 使用 OpenCV 实现双目视觉三维重建 #### 图像获取 为了进行双目视觉三维重建,首先需要从两个不同视角捕获同一场景的两幅图像。这两张图片通常被称为左图和右图。 ```cpp #include <opencv2/opencv.hpp> using namespace cv; using namespace std; int main() { Mat imgLeft = imread("left_image.jpg", IMREAD_COLOR); Mat imgRight = imread("right_image.jpg", IMREAD_COLOR); if (imgLeft.empty() || imgRight.empty()) { cout << "Could not open or find the images!" << endl; return -1; } } ``` #### 摄像机标定 摄像机标定是为了获得内参矩阵 K 和畸变系数 D 。这些参数对于后续处理至关重要[^1]。 ```cpp // 假设已经完成相机校准并得到如下参数 Mat cameraMatrix[2], distCoeffs[2]; stereoCalibrate(objectPoints, imagePointsL, imagePointsR, cameraMatrix[0], distCoeffs[0], cameraMatrix[1], distCoeffs[1], imageSize, R, T, E, F); ``` #### 特征提取与匹配 虽然在稠密匹配中可以直接跳过显式的特征检测阶段,在这里仍然展示一种简单的方法来找到左右图像之间的对应关系。 ```cpp Ptr<StereoBM> sbm = StereoBM::create(16, 9); // 创建立体块匹配对象 sbm->setPreFilterType(cv::StereoBM::PREFILTER_XSOBEL); sbm->compute(imgLeftGray, imgRightGray, disparity); normalize(disparity, disp8bit, 0, 255, NORM_MINMAX, CV_8UC1); imshow("Disparity Map", disp8bit); waitKey(); ``` #### 计算视差图 通过立体匹配算法计算出每一对像素间的视差值 d ,即相同物理位置上的物体在两张照片里水平位移的距离。 #### 构建点云数据 利用视差信息以及先前求得的内外参数,可以将二维平面坐标转换成三维空间坐标系下的点集表示形式。 ```cpp ReprojectImageTo3D(disparity, xyz, Q); vector<Point3f> points; for(int y=0;y<xyz.rows;++y){ for(int x=0;x<xyz.cols;++x){ Point3f pt = xyz.at<Vec3f>(y,x); if(!isnan(pt.x)){ points.push_back(pt); } } } ``` 其中 `Q` 是由 `stereoRectify()` 函数返回的一个四乘四变换矩阵,用于辅助重投影操作。 #### 数据可视化 最后一步是使用 OpenGL 或其他图形库渲染生成的 3D 点云模型,并为其添加合适的材质属性如颜色、光照效果等。 ```python import numpy as np from pyqtgraph.Qt import QtCore, QtGui import pyqtgraph.opengl as gl app = QtGui.QApplication([]) w = gl.GLViewWidget() w.opts[&#39;distance&#39;] = 40 w.show() gx = gl.GLGridItem() gy = gl.GLGridItem() gz = gl.GLGridItem() w.addItem(gx) w.addItem(gy) w.addItem(gz) pos = np.array(points).astype(float) sp1 = gl.GLScatterPlotItem(pos=pos, color=(1.0, 1.0, 1.0, 0.5), pxMode=False) w.addItem(sp1) if __name__ == &#39;__main__&#39;: import sys if (sys.flags.interactive != 1) or not hasattr(QtCore, &#39;PYQT_VERSION&#39;): QtGui.QApplication.instance().exec_() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值