【python计算机视觉】计算视差图
一. 计算视差原理
1.1 立体图像
一个多视图成像的特殊例子是立体视觉(或者立体成像),即使用两台只有水平(向 一侧)偏移的照相机观测同一场景。当照相机的位置如上设置,两幅图像具有相同 的图像平面,图像的行是垂直对齐的,那么称图像对是经过矫正的。该设置在机器 人学中很常见,常被称为立体平台。
假设两幅图像经过了矫正,那么对应点的寻找限制在图像的同一行上。一旦找到 对应点,由于深度是和偏移成正比的,那么深度(Z 坐标)可以直接由水平偏移来 计算

其中,f 是经过矫正图像的焦距,b 是两个照相机中心之间的距离,xl 和 xr 是左右两 幅图像中对应点的 x 坐标。分开照相机中心的距离称为基线。矫正后的立体照相机:

立体重建(有时称为致密深度重建)就是恢复深度图(或者相反,视差图),图像中 每个像素的深度(或者视差)都需要计算出来。
1.2 计算视差图
在该立体重建算法中,我们将对于每个像素尝试不同的偏移,并按照局部图像周围 归一化的互相关值,选择具有最好分数的偏移,然后记录下该最佳偏移。因为每个偏移在某种程度上对应于一个平面,所以该过程有时称为扫平面法。
1.3 NCC视差匹配方法
当密集地应用在图像中时,归一化的互相关值可以很快地计算出来。这和我们在第 2 章中应用于稀疏点对应的不同。我们使用每个像素周围的图像块(根本上说,是 局部周边图像)来计算归一化的互相关。对于这里的情形,我们可以在像素周围重 新写出公式(2.3)中的== NCC==

1.4 双目立体匹配的步骤
-
采集图像:通过标定好的双目相机采集图像,当然也可以用两个单目相机来组合成双目相机。
-
极线校正:校正的目的是使两帧图像极线处于水平方向,或者说是使两帧图像的光心处于同一水平线上。
2.1 由标定得到的内参中畸变信息中可以对图像去除畸变
2.2 通过校正函数校正以后得到相机的矫正变换R和新的投影矩阵P,接下来是要对左右视图进行去畸变,并得到重映射矩阵。
2.3 根据上述得到的重映射参数map1,map2,我们需要进一步对原始图像进行重映射到新的平面中才能去除图像畸变。
2.4 通过上述两步操作,我们成功地对图像去除了畸变,并且校正了图像极线。 -
特征匹配:这里便是我们利用NCC做匹配的步骤啦,匹配方法如上所述,右视图中与左视图待测像素同一水平线上相关性最高的即为最优匹配。完成匹配后,我们需要记录其视差d,即待测像素水平方向xl与匹配像素水平方向xr之间的差值d = xr - xl,最终我们可以得到一个与原始图像尺寸相同的视差图D。
-
深度恢复:通过上述匹配结果得到的视差图D,我们可以很简单的利用相似三角形反推出以左视图为参考系的深度图。计算原理如下图所示:

二. 代码实现
2.1 图片集
左相机:

右相机:



2.2 代码实现
# -*- coding: utf-8 -*-
from PIL import Image
from pylab import *
import cv2
from numpy import *
from numpy.ma import array
from scipy.ndimage import filters
def plane_sweep_ncc(im_l,im_r,start,steps,wid):
""" 使用归一化的互相关计算视差图像 """
m,n = im_l.shape
# 保存不同求和值的数组
mean_l = zeros((m,n))
mean_r = zeros((m,n))
s = zeros((m,n))
s_l = zeros((m,n))
s_r = zeros((m,n))
# 保存深度平面的数组
dmaps = zeros((m,n,steps))
# 计算图像块的平均值
filters.uniform_filter(im_l,wid,mean_l)
filters.uniform_filter(im_r,wid,mean_r)
# 归一化图像
norm_l = im_l - mean_l
norm_r = im_r - mean_r
# 尝试不同的视差
for displ in range(steps):
# 将左边图像移动到右边,计算加和
filters.uniform_filter(np.roll(norm_l, -displ - start) * norm_r, wid, s) # 和归一化
filters.uniform_filter(np.roll(norm_l, -displ - start) * np.roll(norm_l, -displ - start), wid, s_l)
filters.uniform_filter(norm_r*norm_r,wid,s_r) # 和反归一化
# 保存 ncc 的分数
dmaps[:,:,displ] = s / sqrt(s_l * s_r)
# 为每个像素选取最佳深度
return np.argmax(dmaps, axis=2)
def plane_sweep_gauss(im_l,im_r,start,steps,wid):
""" 使用带有高斯加权周边的归一化互相关计算视差图像 """
m,n = im_l.shape
# 保存不同加和的数组
mean_l = zeros((m,n))
mean_r = zeros((m,n))
s = zeros((m,n))
s_l = zeros((m,n))
s_r = zeros((m,n))
# 保存深度平面的数组
dmaps = zeros((m,n,steps))
# 计算平均值
filters.gaussian_filter(im_l,wid,0,mean_l)
filters.gaussian_filter(im_r,wid,0,mean_r)
# 归一化图像
norm_l = im_l - mean_l
norm_r = im_r - mean_r
# 尝试不同的视差
for displ in range(steps):
# 将左边图像移动到右边,计算加和
filters.gaussian_filter(np.roll(norm_l, -displ - start) * norm_r, wid, 0, s) # 和归一化
filters.gaussian_filter(np.roll(norm_l, -displ - start) * np.roll(norm_l, -displ - start), wid, 0, s_l)
filters.gaussian_filter(norm_r*norm_r,wid,0,s_r) # 和反归一化
# 保存 ncc 的分数
dmaps[:,:,displ] = s / np.sqrt(s_l * s_r)
# 为每个像素选取最佳深度
return np.argmax(dmaps, axis=2)
im_l = array(Image.open('11.png').convert('L'), 'f')
im_r = array(Image.open('12.png').convert('L'),'f')
# 开始偏移,并设置步长
steps = 12
start = 4
# ncc 的宽度
wid = 9
res = plane_sweep_ncc(im_l,im_r,start,steps,wid)
import scipy.misc
scipy.misc.imsave('depth.png',res)
show()
2.3 运行结果及分析
窗口值wid = 15 时

窗口值wid = 9 时

窗口值wid = 5 时

窗口值wid = 3 时

图片集2:

窗口值wid = 15 时:

窗口值wid = 9 时:

窗口值wid = 3时:

三. 实验结果及小结
- 从实验结果可以看出,窗口值的大小改变对结果影响较大,wid值越小,匹配结果的区分度越低,并且成散粉分裂状;随着窗口值增大,匹配区分度逐渐清晰,匹配精度变高。
- 当窗口值过大时,效果也并没有更好,暗区会越来越黑,导致匹配效果也不太好。
- 实验遇到的错误: numpy版本问题,依旧需要卸载重装方可解决;使用numpy里的函数需要在函数名前面加np.前缀方可。
智能推荐
计算机视觉实验五 双目立体匹配获得视差图,深度图
完整源码链接 https://github.com/LamyaLi/cvLab 文章目录 一、 立体匹配的研究背景及意义 二、 立体匹配算法的基本实现思想 1、误差能量函数 2、基于最小平均误差能量的视差图 3、计算可靠度,生成具有可靠视差的视差图 4、由视差图生成深度图 三、 实现步骤与结果展示 1、计算误差能量,生成具有最小平均误差能量的视差图 2、计算可靠度,生成可靠视差的视差图 3、计算深...
计算机视觉---NCC视差匹配方法
文章目录 1. NCC原理 2. 运算流程 3. 实验内容 4.总结 1. NCC原理 NCC,normalization cross-correlation(归一化相关性),用于归一化待匹配目标之间的相关程度。 对于原始的图像内任意一个像素点(px,py)(px,py)(px,py)构建一个n×nn×nn×n 的邻域作为匹配窗口。然后对于目标相素位置(px+d...
计算机视觉——双目视觉匹配计算视差深度
源码地址:https://github.com/AOYLAOTANG/Computer-Vision/tree/main/stereo%E5%8F%8C%E7%9B%AE%E5%8C%B9%E9%85%8D 一、基本原理 Stereo双目立体匹配有很多算法, 比如SAD、BM、SGBM、GC,差别在于匹配时候的策略不同,我们这次要用到的NCC度量就是一种不错的方法。 其中I为目标图像,T为模板图像...
冒泡排序,及改进方式,性能优化400%>>>附图解加源码
首先源码附上,源码中带有注释,看不懂没关系,源码后面附带图解,最后附上代码效率提升图 源码如下: 方案一:其实实现很简单,两层循环,每次内层迭代出最大的一个值,将其放入数组最后一个位置,外层循环的末端便往前移一位。其原理如下图 方案一代码块: 方案二:优化改进 仔细观察上面的图,我们不难发现当迭代到图下这样的情况时,其实已经全排序好了,但是我们还是需要对它进行1,2,3,4,5,6的迭代,这些情况...
css3常用选择器
先介绍一下基本选择器,如下几种 *:通配符。选择页面的所有元素 E:元素选择器。对页面的一些元素进行选择,如p,div,li等 .class:类选择器 #id:id选择器。一个Id在一个页面中只能选择,这是和类选择器的区别 E F:后代选择器。如ul li。选中ul下的li E>F:子元素选择器。如下,可以用 h1 > strong {color:red;}使h1的子元素strong变...
猜你喜欢
python is not set from command line or npm configuration
问题 猜测原因 python版本冲突 解决方案 去官网找到最新版本python 点击下载,注意记住你下载的目录,下载好以后,打开这个目录下的文件夹,Python310, 整个文件夹复制一下 在项目里运行npm config list --json 找到python的路径 我的是 C:\\Python27\\python.exe 说明项目里用的还是py...
Java8 Stream流操作
前言 我们常常需要将一个容器转化成另一个容器,或是对这个容器中的数据进行批量处理,这时使用Stream流可以大大减少我们的工作量。 1 Stream概述 Java 8 是一个非常成功的版本,这个版本新增的Stream,配合同版本出现的 Lambda ,给我们操作集合(Collection)提供了极大的便利。 那么什么是Stream? Stream将要处理的元素集合看作一种流,在流的过程中,借助St...
带你玩转Visual Studio——带你跳出坑爹的Runtime Library坑
在Windows下进行C++的开发,不可避免的要与Windows的底层库进行交互,然而VS下的一项设置MT、MTd、MD和MDd却经常让人搞迷糊,相信不少人都被他坑过,特别是你工程使用了很多第三库的时候,及容易出现各种链接问题。看一下下面这个错误提示: LIBCMT.lib(_file.obj) : error LNK2005: ___initstdio already defined...
git 设置 gitignore 忽略 __pycache__
清除git缓存中的pycache 直接删掉硬盘上的文件 如果我想保留硬盘上的这个文件,而只删除版本管理中的文件,就需要加入--cached参数。 切换分支出现问题 尽管我已经删除了__pycache__,硬盘也没有了,但是切换分支的时候依然是会提示本地重写的情况。 提示:需要我在切换分支之前,提交一次更新。 提交了更新之后,再来尝试切换分支,如下: 成功了,说明当做了任何变更之后,切换分支前需要执...
人生苦短,我用Python(二)— 爬取会议网站 EasyChair Smart CFP
寒假留校帮学长写了个爬虫,抓取会议网站上一些CFP信息。想着把一些知识点、坑点记下来,一来做个小总结给工作收收尾,二是以后再遇到好从容应对。 这是我写的第二个比较完善的爬虫了,比第一个要简单许多,完全过程化的代码,而且easychair这个网站页面布局比较友好,适合python新手、前端小白入门练习。但这个网站反爬比较厉害,写爬虫的过程中就被ban了好几次…… 制定抓取...
