# mult_graph_project **Repository Path**: BugPeddle/mult_graph_project ## Basic Information - **Project Name**: mult_graph_project - **Description**: 计算机视觉多视图几何课程大作业 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-11-06 - **Last Updated**: 2024-01-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 如想使用本工程,请转至文件夹`./rectify/`内,使用`python3 main.py`命令运行。 本说明文件仅记录本工程的早期开发说明,如需查看使用说明,请转至[使用说明](./rectify/README.md)。 # 说明 本课程大作业使用matlab完成,本着尽量不浪费过多时间的原则,就直接使用matlab写完了,仿真环境还是用最熟悉的Python吧,后面有空可以把代码用C++实现以求高性能,现在不需要这个性能。 # 问题说明 问题是虚构一个环境,在虚构的环境中产生一个虚构的相机,利用这个虚构的相机对虚构场景中的棋盘格图像成像,得到虚构场景下的射影变换图像,然后对这个图像进行恢复并分析讨论其误差。设置不同的畸变形式,例如相机的一阶或二阶畸变、散粒噪声以及对应的噪声强度。 首先需要搭建这样的一个仿真环境,需要提供一个仿真环境接口、仿真相机、仿真图像,为了简单起见,就假设在一间黑屋子里,面前放着一个棋盘格子,一个射影摄像机对棋盘格子成像,只要能够保证成像结果是棋盘格子的局部,就能够让棋盘格子的图案占据整个成像框。 # 相机模型接口设计 输入是一个场景信息,包含有三维的深度信息、物方的点,应当包括棋盘格子相对相机的摆放位置(旋转和平移),输出是二维图像信息。 相机自身的参数,例如相机内参矩阵、相机的畸变参数。这部分应该作为可以替换的类,用于继承。仿真的分辨力有限,直接生成得到的图像中有规律噪声点,使用了中值滤波。 这部分的内容放置在 [照相机文件夹](./photograph/cam/) 内,其中的`cam_base.py`文件是相机模型基类,目前只实现了常规相机,后期有需要可以搭事件相机或者畸变的相机;`cameras.josnl`内是对应相机的参数列表,以相同格式增减并在命令行参数里使用即可。 ## 相机模型成像环境 这部分内容放置在[环境文件夹](./photograph/env/)内,其中的只有一个基类文件,包含了成像三维环境,以及从图像中的加载。 ## 相机成像仿真主程序 [主程序](./photograph/main.py)中,首先加载相机模型,然后加载环境,最后进行成像,得到图像。对应的命令行列表参数有: ```bash usage: main.py [-h] [--rx RX] [--ry RY] [--rz RZ] [--x X] [--y Y] [--z Z] [--scale SCALE] [--mate_path MATE_PATH] [--cam_ind CAM_IND] options: -h, --help show this help message and exit --rx RX --ry RY --rz RZ --x X --y Y --z Z --scale SCALE --mate_path MATE_PATH --cam_ind CAM_IND corespond to the camera.jsonl indexes. ``` 其中的`--scale`参数是对加载的图像进行放缩的选项,`--mate_path`是对应的场景文件(可以只是一张图片),`--cam_ind`是对应的相机参数文件(对应参数列表里面的序号)。输出的照片文件和对应的内外参数矩阵将存入`./photograph/output`文件夹内。 # UI界面说明 得到了仿真照片,或者实物射影变换照片后,需要选取角点完成校正,这里规定不让使用匹配校正,而是使用五条正交直线解绝对对偶二次曲线的表达式。 ## 界面文件说明 界面文件放置在[界面文件夹](./rectify/ui/)内,其中`ui.py`是界面的基类文件,另一个`geo_base.py`是几何图形基本类型文件,包含了点类型和直线类型,以及一个形状管理器,用于实现对选点的增加和删除,目前没有实现对线的删除功能,仅能连线,而不能删除线。 使用按键`Finish Choice`,可以完成选交叉点,程序将自动将交叉点对应的两条正交直线组合在一起,以嵌套列表的形式输出给接口程序`pocket`,接口程序将嵌套列表解算为嵌套的齐次直线组,转换为张量形式给解算工具。 ## 解算工具说明 解算工作放置在[工具文件夹](./rectify/ulibs/),其中有一个`rectify.py`文件,就是对从界面输入的五条正交直线的齐次表达式进行解算,解算从接口程序得到的张量,从而得到射影变换矩阵以及校正后的图像。目前,这里使用的解算方法SVD是不对的。自行推导的方法也不对,得到的绝对对偶二次曲线甚至都不对,这里需要重新推导。 使用matlab完成的校正图像如图所示: ![校正图像](./doc/matlab校正结果.png) 校正得到的标准射影变换矩阵为: ```python H =[[0.44882336706879,-0.0100040983001050, 0.000248570921030526], [0.0164203670878828, 0.402664956579217 ,-0.000129876982276601], [-98.9447204502630 ,-83.7997743222271, 1]] ``` # 目前进度 问题三的照相环境、照相机模型的程序已经完成,相应的选线选点UI也已经搭好了,只是在反解射影变换矩阵时,遇到了问题,不能直接使用SVD求,解算也得不到正确的结果,告一段落,等老师发正式的作业通知。 ## 问题 ### 一种结果 选点结果: ![Alt text](./doc/image.png) 和这个选点结果 ![Alt text](./doc/image2.png) 得到的都是这个运行结果:![Alt text](./doc/rectified_img_2023-11-15-23-57-03.png) ### 二种结果 选点结果: ![Alt text](./doc/image3.png) 运行结果 ![Alt text](./doc/rectified_img_2023-11-16-00-18-31.png) 而对于没有完全平行直线的选点结果,则可以重构出类似于仿射图像: ![Alt text](doc/rectified_img_2023-11-16-00-15-26.png) (总是出现重构完的图像不在中间,且不完整的问题,我使用自己的函数图像甚至都没有,充分说明了自己写的重构函数有问题,且深刻阻拦了之前的调试过程) 多选很多点后,选择结果为: ![Alt text](./doc/image4.png) 运行结果为: ![Alt text](doc/rectified_img_2023-11-16-00-36-15.png) 个人感觉垂直度有了明显的提升,综上所述,这种方法对噪声的效果实在是太差了,稍微一选得不恰当,就完全得不到正确的结果,选择的正交直线应当远远多于5组才对。 解决思路:不能使用SVD,而是使用三角分解和矩阵求逆解出来,直接SVD得不到真实的结果,原因出在SVD的求解,这里只选五条线,还差一个约束,即最后一个数是1或者总范数为1,加上这个约束才能保证解出来的结果是对的,奇异值分解理论上能够得到这样的结果,但是噪声的影响可能让它解不出来,最好多于六对。 总算找到了问题,问题不在于校正的原理(确实解出来的矩阵是对的)而在于校正使用的函数,我发现直着校正都不对,那一定是校正函数搞了鬼。问题找到了,在射影变换的矩阵里面不能使用旋转矩阵,才能正常校正。 ## 部分实验数据 各个实验对应的`lines.pt`文件存放在`./rectify/lines_cache`里面,使用时将名称改回即可。 ### 0.001射影 原始变换矩阵: H:[[1. 0. 0. ] [0. 1. 0. ] [0.001 0.001 1. ]] 选中的点: [3, 2, 5], [7, 5, 2], [13, 1, 5], [10, 3, 5], [1, 0, 3], [12, 4, 3], [8, 2, 3], [2, 2, 5], [4, 1, 5], [11, 5, 2], 校正矩阵: H_rect:tensor([[ 9.9579e-01, -3.2487e-04, 0.0000e+00], [ 0.0000e+00, 1.0042e+00, 0.0000e+00], [-1.0130e-03, -1.0421e-03, 1.0000e+00]], device='cuda:0') ### 0.002射影 原始矩阵: H:[[1. 0. 0. ] [0. 1. 0. ] [0.002 0.002 1. ]] 选中的点: [0, 3, 4], [6, 3, 1], [2, 1, 2], [1, 5, 1], [2, 3, 4], [4, 4, 1], [3, 0, 5], [5, 5, 1], [7, 4, 2], 校正矩阵: tensor([[ 1.0064e+00, 3.5903e-04, 0.0000e+00], [ 0.0000e+00, 9.9362e-01, 0.0000e+00], [-2.0144e-03, -2.0029e-03, 1.0000e+00]], device='cuda:0') ### 0.0001射影 原始矩阵: H:[[1.e+00 0.e+00 0.e+00] [0.e+00 1.e+00 0.e+00] [1.e-04 1.e-04 1.e+00]] 选中的点: [0, 4, 2], [8, 0, 2], [12, 5, 3], [7, 5, 4], [3, 1, 4], [11, 1, 4], [6, 5, 2], 校正矩阵: tensor([[ 1.0022e+00, -5.0837e-04, 0.0000e+00], [ 0.0000e+00, 9.9782e-01, 0.0000e+00], [-9.7673e-05, -8.2244e-05, 1.0000e+00]], device='cuda:0') ### 0.0001射影,0.9仿射 原始矩阵: [[9.00000000e-01 0.00000000e+00 0.00000000e+00] [0.00000000e+00 1.11111111e+00 0.00000000e+00] [1.00000000e-04 1.00000000e-04 1.00000000e+00]] 选中的点: [0, 2, 0], [8, 5, 3], [7, 1, 3], [3, 1, 5], [9, 1, 4], [4, 4, 1], [11, 2, 3], [5, 5, 0], [1, 1, 4], [13, 5, 3], 校正矩阵: tensor([[ 1.1092e+00, 1.7551e-03, 0.0000e+00], [ 0.0000e+00, 9.0151e-01, 0.0000e+00], [-9.4443e-05, -1.2433e-04, 1.0000e+00]], device='cuda:0') ### 0.0001射影,0.8仿射 原始矩阵: H:[[8.00e-01 0.00e+00 0.00e+00] [0.00e+00 1.25e+00 0.00e+00] [1.00e-04 1.00e-04 1.00e+00]] 选中的点: [0, 4, 1], [8, 0, 2], [1, 0, 2], [5, 2, 1], [10, 2, 4], [11, 5, 0], [6, 4, 3], [12, 1, 2], 校正矩阵: tensor([[ 1.2613e+00, 7.6074e-03, 0.0000e+00], [ 0.0000e+00, 7.9284e-01, 0.0000e+00], [-9.9690e-05, -1.2975e-04, 1.0000e+00]], device='cuda:0') ### 0.0001射影,0.8仿射 0.2长宽畸变 原始矩阵: [[8.00e-01 2.00e-01 0.00e+00] [0.00e+00 1.25e+00 0.00e+00] [1.00e-04 1.00e-04 1.00e+00]] 选中的点: [1, 2, 0], [5, 1, 5], [4, 1, 5], [11, 4, 3], [2, 2, 0], [12, 4, 0], [3, 2, 4], [8, 1, 3], [6, 1, 5], 校正矩阵: tensor([[ 1.2606e+00, -1.9357e-01, 0.0000e+00], [-0.0000e+00, 7.9328e-01, 0.0000e+00], [-6.0840e-05, -9.0531e-05, 1.0000e+00]], device='cuda:0')