vtk是著名的开源三维渲染库,在三维渲染过程中的一个非常重要的内容就是相机即vtkCamera类的设置。在VTK中,相机的实质是一个观测点。VTK的官方Doc对vtkCamera写的十分简略,暗坑很多。在学习和使用vtkCamera的过程中,我走了很多弯路。在我的应用中,我希望能够根据现实中相机的Transform Matrix完全模拟设置vtkCamera。下面根据我的经验和理解,介绍一下vtkCamera,希望对被人能有帮助。

vtkCamera参数

上图是vtkCamera模型示意图,虽然这个图来自于另一个3D库的文档,但是原理一样。要注意的是虽然左边画了个摄像机,但是其实图示的包括焦点在内都是在相机内部的。下面利用这个图来解释一下vtkCamera的各个成员变量的含义。

WindowCenter

WindowCenter按照字面意思是窗口的中心。在相机制造过程中难免存在一定的装配误差,所以透镜的中心往往不能完全对准传感器的中心,而是有非常微小的误差。所以我们在用vtk相机模拟现实中相机时也应该体现这一现象。WindowCenter实质上就是成像的一个offset偏移量。在vtk中WindowCenter的坐标范围是([-1,+1], [-1,+1])。比方说,如果理想情况,图像成像中心(Focal Point)就在窗口的中心,那么WindowCenter就是(0, 0)。如果希望把成像平移到窗口的右上角,那么就应该设置成(1, 1)。根据官方文档,这个量一般在同一窗口显示多个渲染器时才需要设置。但实际上,如果你需要vtk完全模拟现实相机,也要考虑设置这个量,否则永远有一个偏移量。反过来,如果希望图像平移也可以修改这个参数。

这里要注意的是,WindowCenter的正方向是向右向上的。而成像平面的坐标系往往是向右向下的。小心正负号的设置。另外,平移的对象是图像,而不是在三维空间移动相机。

FocalPoint

FocalPoint即焦点位置。在现实相机中焦点在成像平面中心,即在光心的后面(与被摄物体在光心的两侧)。但是在建模时为了简化我们往往对称到光心前面(与被摄物体在光心同侧)。注意这里要求的是焦点的三维坐标,而不仅仅是焦距。因为焦点不仅确定了成像平面的位置,还与光心位置Position一同确定了相机镜头的朝向。

Position

这里的Position指的实际上是光心的位置,或者说对应小孔相机模型中小孔的位置。

ViewUp

ViewUp指图像的正方向。由Position和FocalPoint我们可以确定5个自由度,相机仍然可以沿着主光轴任意旋转。所以这里要指定正方向,即ViewUp。这里注意,ViewUp是一个方向向量,不存在位置,或者说起点永远在原点。

ViewAngle

ViewAngle是视角。默认是30°。其实这个是一个很重要的参数,它决定了图像中内容的比例大小。或者说,通过设置这一变量可以实现图像的放缩。

ClippingRange

ClippingRange即剪切平面,分为前后两个。只有在这两个剪切平面之间的内容才会被渲染和显示。默认值是(0.1,1000)。这个量一般不需要修改,而是在vtkRenderer对象中调用ResetCameraClippingRange()方法来自动重设渲染范围。如果你的图像显示不完整,但是稍微用鼠标旋转或平移一下又变完整了。建议试一下调用一次这个方法。

ParallelProjection

如果为True那么按照平行投影进行渲染,否则默认是按照透视投影PerspectiveProjection进行渲染。透视投影即近大远小的投影,平行投影即用平行光照射得到的投影,没有近大远小的透视效应。如图所示:

DirectionOfProjection

DirectionOfProjection即一个三维矢量,从光心位置Position指向焦点位置FocalPoint。

ViewPlaneNormal

ViewPlaneNormal是投影面(成像面)的法向量。与DirectionOfProjection矢量正好相反。

Distance

Distance即焦距,即上面两个向量的模长。如果使用SetDistance()会沿着主光轴移动焦点FocalPoint,从而使FocalPoint与Position达到给定距离。

ModelTransformMatrix

这个变换矩阵将移动场景里除了相机的所有物体,然后渲染。理论上可以通过“ 相机不动物体动” 获得与 “物体不动相机动”一样的图片。但是标准的方法应该还是使相机移动,这样更符合实际。

ViewTransform

这个矩阵是相机矩阵的逆矩阵。相机矩阵是相机坐标系(原点Position,Z轴指向FocalPoint,Y轴与ViewUp平行)相对于世界坐标系的位置,而这个矩阵是世界坐标系相对于相机坐标系的位置。如果相机矩阵

那么ViewTransform为

单位正交矩阵的逆等于其转置矩阵。

CameraLightTransform

当我们设置了Position,FocalPoint和ViewUp后就会得到一个唯一的变换矩阵(相机矩阵),即从世界坐标系到相机坐标系的坐标变换矩阵,这个相机也就确定了唯一的位置。假设设置另一个相机起始值为Positon = (0, 0, 1),FocalPoint = (0, 0, 0),ViewUp = (0, 1, 0)。对这个相机施加一个怎样的变换,才能得到我们目前当前相机矩阵。这个变换就是CameraLightTransform。

成像过程

VTK背后的渲染过程非常复杂,这里只是简单解释一下原理。

人眼或相机的视野可以想象成一个圆椎体。这个圆椎体的尖端是我们的眼球中心或者说相机的光心,底端朝向被摄物体。这个视锥体将决定我们能看到什么,以及看到的物体的透视变形幅度是怎样的(见下图)。最右边图片中棍子的倾斜角度就是圆锥体的张角。所以在图像中,棍子恰好重合为一个圆点。

我们知道,可以通过顶点位置、张角和底面中心来唯一确定一个圆锥体。这里顶点位置对应光心Position,张角对应ViewAngle,底面中心就是焦点FocalPoint。(请看上面的模型图)这样一来,ViewAngle的计算也就一目了然了。

其中的成像平面高度“height of image plane”在现实相机中就对应传感器的高度。可能有人疑惑为什么不是焦距除以成像平面宽度。其实在vtk中我们也可以设置UseHorizontalViewAngle来决定是使用横向比例还是纵向比例。默认以及习惯上都是纵向比例。

所以,根据我们设置的Position,ViewAngle和FocalPoint VTK已经可以完全确定视锥体了。也就是说到目前为止,相机内到底拍到什么(或者说视野中到底能看到什么)已经确定了。注意,到目前为止,所有量都是没有单位的。没有单位也就意味着任意单位,你可以假设所有都是毫米,也可以说所有都是米甚至是英寸。那么如何将其转化为像素呢?这里就需要用到vtkRenderWindows。

在VTK中,相机vtkCamera可以视作胶片相机,也就是说分辨率可以达到无限高。而vtkRenderWindows对象的作用就是数字化。我们通过vtkRenderWindows::SetSize()来设置图像的分辨率。然后VTK会像切蛋糕一样,用一个长方形把视锥体底面套住(高度对齐),然后按照设置的分辨率把长方形内框住的内容切成一个一个的小像素,变成数字化的图片显示到屏幕上完成了渲染。下图为视锥体套上了一个高度对齐底面直径的渲染窗口RenderWindow。

由渲染窗口RenderWindow完成对图像的分割,形成一个又一个的像素点。如下图所示。(因为手头只有系统自带的画图工具,没有办法把成的像画在示意图里面,见谅。)

这一过程也就解释了,为什么增加VTK中的焦距时,图片内容没有放大的原因。当更改焦距(FocusPoint-Position)时,ViewAngle没有改变。所以对应的成像平面向外平移,视锥体底面成比例的放大了。vtkRenderWindows只能用一个更大的长方形套住视锥体体面。但是分辨率不变的,所以长方形被切分成同样多的小像素。虽然成像变大了,但是每个像素的大小也成比例变大了。所以最后表现在屏显图片上没有发生任何改变。

从相机矩阵到vtkCamera

如果已经知道相机外矩阵(可以通过标定Calibration获得)和硬件参数(焦距,传感器大小,传感器中心与镜头中心的偏移量),如何让vtkCamera完全模拟这个相机呢?根据上面的内容,这个问题应该不难解决。具体代码如下:

1 //新建一个相机对象

2 vtkSmartPointer camera =

3 vtkSmartPointer::New();4

5 //根据相机外矩阵,设置相机(光心)位置

6 camera->SetPosition(camTrans.at(0),7 camTrans.at(1),8 camTrans.at(2));9

10 //根据相机外矩阵,设置焦点位置。设置完这两项成像平面已经唯一确定。

11 camera->SetFocalPoint(camRot.at(0, 2) + camTrans.at(0),12 camRot.at(1, 2) + camTrans.at(1),13 camRot.at(2, 2) + camTrans.at(2));14

15 //根据相机外矩阵,设置成像y正方向。是否有负号取决于原始的相机坐标系中,y是朝向相机上方(正)还是下方(负)。

16 camera->SetViewUp(- camRot.at(0, 1),17 - camRot.at(1, 1),18 - camRot.at(2, 1));19

20 //计算视角。注意这里我的焦距值focus是负数,所以前面加负号。VTK中ViewAngle用角度表示。

21 viewAngle = - 2 * atan((sensorSize.height / 2) / focus) * 180 /CV_PI;22 camera->SetViewAngle(viewAngle);23

24 //计算窗口中心。xh和yh分别是光学中心相对于传感器中心的偏移量。注意正方向规定的差异导致的负号。建议正负号都试一下。

25 windowCenter.x = -xh / (sensorSize.width / 2);26 windowCenter.y = -yh / (sensorSize.height / 2);27 camera->SetWindowCenter(windowCenter.x, windowCenter.y);

另外关于vtkRenderWindow的设置如下:

1 vtkSmartPointer renderer =

2 vtkSmartPointer::New();3 renderer->AddActor(Actor);4 renderer->SetActiveCamera(camera);5 renderer->SetBackground(1, 1, 1);6 renderer->ResetCameraClippingRange(); //不加这一行可能会成像不完整。

7

8 vtkSmartPointer renderWindow =

9 vtkSmartPointer::New();10 renderWindow->AddRenderer(renderer);11 renderWindow->SetSize(windowSize.width, windowSize.height);

图像出现偏移往往和WindowCenter的设置有关系,图像的透视角度(近大远小)有问题往往与焦距的设置有关系,如果图像出现了大小的放缩比例错误,就要看看是不是ViewAngle设置有误。这个规律可以帮助定位错误。

vtk相机_VTK 相机类vtkCamera原理及用法相关推荐

  1. VTK:插值相机用法实战

    VTK:插值相机用法实战 程序输出 程序完整源代码 程序输出 程序完整源代码 #include <vtkActor.h> #include <vtkCamera.h> #

  2. Cesium 键盘鼠标控制相机漫游(源码+原理讲解)

    Cesium 键盘鼠标控制相机漫游(源码+原理讲解) 在各大博客平台上,Cesium使用键盘控制相机漫游的源码已经有不少人贴出源码,本人在浏览这些源码的过程中发现大家采用的方式基本一致,大部分代码都是 ...

  3. V---双相机定位贴合的原理和实现过程

    主要讲解上下双相机定位贴合的原理和实现过程,包括各种标定.组合使用及具体的halcon源码实现, 适用于的X.Y.Z三轴加一旋转轴系统,如模组组成的多轴系统.Scara四轴机器.六轴机器人(在运行过程 ...

  4. 双目相机标定以及立体测距原理及OpenCV实现

    转载 双目相机标定以及立体测距原理及OpenCV实现 http://blog.csdn.net/dcrmg/article/details/52986522?locationNum=15&fp ...

  5. 相机镜头镀膜运用的光学原理?

    相机镜头镀膜运用的光学原理? 今天上午做理综卷子的时候,碰到这么一道选择题: 现代照相机的镜头一般呈淡蓝紫色,是因为镜头表面有一层物理镀膜,没有加膜的镜片和空气的接触面约有4%左右的光线被反射掉,加膜 ...

  6. 相机标定(一)-原理及内参、外参

    >>>文章索引<<< 相机标定(一)-原理及内参.外参 相机标定(二)-畸变校正,张正友标定法 相机标定(三)-相机成像模型 在图像测量过程以及机器视觉应用中,为确 ...

  7. 双目相机标定以及立体测距原理及OpenCV实现(下)

    前篇:双目相机标定以及立体测距原理及实现(上) 双目相机标定后,可以看到左右相机对应匹配点基本上已经水平对齐. 之后在该程序基础上运行stereo_match.cpp,求左右相机的视差. 注:下边Op ...

  8. 双目相机标定以及立体测距原理及实现(上)

    作者丨童虎 编辑丨3D视觉开发者社区 单目相机标定的目标是获取相机的内参和外参,内参(1/dx,1/dy,Cx,Cy,f)表征了相机的内部结构参数,外参是相机的旋转矩阵R和平移向量t.内参中dx和dy ...

  9. Kinect与TOF、双目、结构光相机比较相机国产、非国产统计参数对比分析

    Kinect与TOF.双目.结构光相机比较相机国产.非国产统计参数对比分析 Kinect v1和Kinect v2之间的参数比较 从图中可以看出,Kinect v2的表现比Kinect v1要好得多: ...

最新文章

  1. 六面!终斩腾讯NLP暑期实习offer
  2. css3 线条出现动画效果,CSS3实现的线条波浪动画效果
  3. 基本数据类型float和double的区别
  4. 【Node】模块加载过程
  5. 第六次作业—例行报告
  6. LSA类型讲解——LSA-1【1类LSA——Router LSA】详解
  7. 12个很棒的Pandas和NumPy函数,让python数据分析事半功倍
  8. 小学音乐教学和计算机的融合,小学学科教学与计算机深度融合赛课心得体会(共4篇)...
  9. 关于学校计算机的情景剧剧本,有关学校后勤的情景剧剧本《默默奉献》
  10. 高级语言程序设计II 实验报告三c++使用文本文件和二进制文件的读写比较两者的区别和优劣...
  11. [XJTUSE编译原理]第四章 语法分析——自上而下分析
  12. [转载]INNO SETUP注册DLL文件
  13. 方正飞翔加密锁_方正飞翔6.0数字版注册机
  14. android 地址json文件,Android访问assets本地json文件的方法
  15. 0投入,高收益,门槛低,自媒体副业推荐
  16. Java switch使用详解
  17. 定义幂函数C语言,【知识点】幂函数定义与性质
  18. Linux系统扩容硬盘
  19. win10下卜卦占星工具
  20. 纹波测试方法(收集整理)

热门文章

  1. 场景中配置阴影(个人笔记)
  2. Model-Agnostic Meta-Learning for Fast Adaptation of Deep Networks阅读笔记
  3. OSI七层模型和TCPIP五层模型
  4. 考点图文详解 - 局域网与城域网(第四章)
  5. 计算机视觉—BOW图像检索
  6. 彻底搞懂基于Open3D的点云处理教程!
  7. 制作一个银行卡登录系统
  8. P7776 【模板】特征多项式 题解
  9. 步骤3_linux QQ install
  10. 麒麟 mips mysql_中标麒麟OS+龙芯MIPS适配开源中间件