立体匹配-----NCC视差匹配
目录
一、立体匹配算法
1.立体匹配算法分类
二、NCC 视差匹配方法
1.原理
2.NCC计算公式
3.算法流程
4.代码实现
5.不同场景运行
三、结论
四、遇到的问题及解决方法
一、立体匹配算法
1.立体匹配算法分类
在立体匹配中,匹配问题可以看成是寻找两组数据相关程度的过程。根据采用图像表示的基元不同,立体匹配算法有多种分类。
①根据算法运行时约束的作用范围:分为局部匹配算法和全局匹配算法。
②基于生成的视差图:可分为稠密匹配和稀疏匹配。稠密匹配:是基于生成的视差图,对于所有像素都能生成确定视差值,称为稠密匹配。稀疏匹配:只选择关键像素点[通常为角点或者边缘点]计算视差值的方法称为稀疏匹配,该算法计算速度较快,但后续还需要通过插值算法计算缺失像素点的视差值,因此应用场景上有很大限制。
1.1全局匹配算法
全局(半全局)立体匹配算法主要是采用了全局的优化理论方法估计视差,建立一个全局能量函数,其包含一个数据项和平滑项,通过最小化全局能量函数得到最优的视差值。其中,图割、置信传播、动态规划,粒子群算法、遗传算法等优化算法都是常用的求解能量最小化的方法。(以后作补充,也可参考我之前的粒子群算法、遗传算法文章)
1.2局部匹配算法
(1)算法介绍:局部立体匹配算法又称基于窗口的方法或基于支持区域的方法。算法对参考图像中的每个像素计算一个合适大小、形状和权重的窗口,然后对这个窗口内的视差值进行加权平均。理想的支持窗口应该完全覆盖弱纹理区域,并在窗口内深度连续。与全局立体匹配算法相似,通过优化一个代价函数的方法计算最佳视差。但是,在局部立体匹配算法的能量函数中,只有基于局部区域的约束数据项,没有平滑项。局部匹配算法仅利用某一点邻域的灰度、颜色、梯度等信息进行计算匹配代价,计算复杂度较低,大多实时的立体匹配算法都属于局部立体匹配的范畴,但局部立体匹配算法对低纹理区域、重复纹理区域、视差不连续和遮挡区域匹配效果不理想。
(2)基本原理:在参考图像中选择一个点,选择该点邻域内一个支持窗口,然后依据一定的相似性判断准则,在待匹配图像中寻找与支持窗口最相似的子窗口,该子窗口所对应的像素点即为对应的匹配点。
(3)不同场景运用:固定窗口代价聚合使用固定大小和形状的窗口作为代价聚合的基元,通常是一个矩形,并假设支持窗口内的其它像素点与待匹配点具有相同的视差。固定窗口法精度不高,但易实现、耗时短,在一些对实时性要求极高的场合得到了应用。
基于双边滤波的代价聚合算法仍然使用固定大小和形状的窗口,但窗口内的元素权重不同,权重由目标图像在该窗口内像素与窗口中心的灰度差和距离计算。基于双边滤波的代价聚合算法精度高,但计算复杂,实时性差,算法性能随窗口尺寸指数增加。
基于分割的代价聚合算法的主要思想是:预先将作为参考图像的左图进行分割,对于支持窗口内与窗口中心处于同一分割的像素,对应的权值取1,否则为一个远小于1的正数。但是图像分割是一个非常耗时的操作,同样无法在实时性要求较高的场合使用。
基于十字的代价聚合算法(Cross-based Cost Aggregation,CBCA)的支持窗口形状并不确定,会根据匹配点邻域的灰度值而改变,具体实现后面的更新中会介绍。该方法可以使用GPU并行计算,具有较好的实时性,现广泛应用于各种算法的代价聚合步骤。
(4)优点:算法成熟、计算简单、速度快,能进行图像实时处理,匹配精度较高,计算量比全局匹配算法更小。
(5)缺点:对噪声敏感,弱纹理区易造成误匹配
二、NCC 视差匹配方法
1.原理:对于原始的图像内任意一个像素 点(px, py )构建一个n x n的邻域作为匹配窗口。然后对于目标相素位置(px + d, py )同样构建一个n x n大小的匹配窗口,对两个窗口进行相似度度量,注意这里的有一个取值范围。对于两幅图像来说,在进行NCC计算之前要对图像处理,也就是将两帧图像校正到水平位置,即光心处于同一 水平线上,此时极线是水平的,否则匹配过程只能在倾斜的极线方向上完成,这将消耗更多的计算资源。
2.NCC计算公式:
求出的NCC(p,d)值在[−1,1]之间
3.算法流程:
①采集图像:通过标定好的双目相机采集图像,当然也可以用两个单目相机来组合成双目相机。
②极线校正:校正的目的是使两帧图像极线处于水平方向,或者说是使两帧图像的光心处于同一水平线上。通过校正极线可以方便后续的NCC操作。
③特征匹配:这里便是我们利用NCC做匹配的步骤,匹配方法如上所述,右视图中与左视图待测像素同一水平线上相关性最高的即为最优匹配。完成匹配后,需要记录其视差d,即待测像素水平方向xl与匹配像素水平方向xr之间的差值d=xr−xl,最终可以得到一个与原始图像尺寸相同的视差图D。
④深度恢复:通过上述匹配结果得到的视差图D,我们可以很简单的利用相似三角形反推出以左视图为参考系的深度图。计算原理如下图所示:
如图,Tx为双目相机基线,f为相机焦距,这些可以通过相机标定步骤得到。而xr - xl就是视差D。
通过公式 z = f * Tx / d可以很简单地得到以左视图为参考系的深度图了。
4.代码实现:
(1)源代码

# -*- 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(r'C:/Users/LE/PycharmProjects/untitled/NCC/3.jpg').convert('L'), 'f')
im_r = array(Image.open(r'C:/Users/LE/PycharmProjects/untitled/NCC/4.jpg').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()





②.窗口值=11
③.窗口值=15
5.不同场景运行(手机拍摄)


②.窗口值=5
③.窗口值=7
④.窗口值=9
2.原图:
窗口值=3
窗口值=5
窗口值=7
窗口值=11
三、结论
通过对上面三组图片进行实验对比可知:
1.需要注意每组实验中的两张图像要校正到水平位置,即光心处于同一 水平线上,此时极线是水平的,否则匹配过程只能在倾斜的极线方向上完成,这将消耗更多的计算资源,如我上述用手机拍摄的两组实验,结果无法看出匹配图像轮廓,匹配精度都不高。
2.当窗口值过小,匹配代价过低,在弱纹理区域容易出现错误匹配,匹配精度也越低
3.当窗口值过大,匹配代价过高,在复杂的纹理区域容易出现错误匹配,匹配精度也会降低
4.窗口值与匹配精度呈开口向下的抛物线关系,窗口值过高过低都会降低匹配精度,所以窗口值应该取合适的值以达到匹配精度最高
5.NCC算法的优点是抗白噪声干扰能力强,且在灰度变化及几何畸变不大的情况下匹配精度很高,它的这种优点非常突出,但该方法受局部光照变化的影响,且匹配速度较慢。
四、遇到的问题及解决方法
1.运行代码时出现
解决方法
在代码中添
2.图片的像素过高,算法效率降低,图片取合适的像素值即可
参考:https://www.cnblogs.com/yepeichu/p/7354083.html
立体匹配-----NCC视差匹配的更多相关文章
- 图像的视差匹配(Stereo Matching)
这里要求用我们自己计算得到的视差图和给的视差图作比較来比較我们得到的视差图的好坏程度,我视差图返回的值是计算得到的视差乘以3之后的图,所以在计算时我不是两个值相差大于1,而是大于3.由于两个图像都乘3 ...
- 双目立体匹配——归一化互相关(NCC)
归一化相关性,normalization cross-correlation,因此简称NCC,下文中笔者将用NCC来代替这冗长的名称. NCC,顾名思义,就是用于归一化待匹配目标之间的相关程度,注意这 ...
- halcon之NCC匹配
NCC匹配 基于Normalized cross correlation(NCC)用来比较两幅图像的相似程度已经是一个常见的图像处理手段.在工业生产环节检测.监控领域对对象检测与识别均有应用.NCC算 ...
- 立体视觉-opencv中立体匹配相关代码
三种匹配算法比较 BM算法: 该算法代码: view plaincopy to clipboardprint? CvStereoBMState *BMState = cvCreateStereoBMS ...
- OpenCV stereo matching 代码 matlab实现视差显示
转载请注明出处:http://blog.csdn.net/wangyaninglm/article/details/44151213, 来自:shiter编写程序的艺术 基础知识 计算机视觉是一门研究 ...
- Stereo Matching 立体匹配学习资料
Middlebury Stereo Evaluation Camera Calibration and 3D Reconstruction OpenCV学习笔记(18)双目测距与三维重建的OpenCV ...
- [收藏夹整理]OpenCV部分
OpenCV中文论坛 OpenCV论坛 opencv视频教程目录(初级) OpenCV 教程 Opencv感想和一些分享 tornadomeet 超牛的大神 [数字图像处理]C++读取.旋转和保存bm ...
- 利用光场进行深度图估计(Depth Estimation)算法之二——匹配算法
光场相机由于能够捕获相机内部光线的强度和方向而得到整个光场,可以实现重聚焦(refocus)和视角变换等功能.进而可以进行深度估计获取深度图,前面说过利用重聚焦的图像进行深度估计,今天说一下利用不同视 ...
- [收藏转载链接]Opencv部分
转载自-柳如风-http://www.cnblogs.com/rongfangliu/p/opencvlink.html [收藏夹整理]OpenCV部分 OpenCV中文论坛 OpenCV论坛 o ...
随机推荐
- SVM | 支持向量机原理讲解(二)
一.线性可分的支持向量机存在的问题 在支持向量机一中,我们介绍了当数据集是线性可分的时候,我们可以使用线性可分的支持向量机将数据进行分类(由于隔了很长时间才更新,因此忘记了支持向量机一的读者可以回看支 ...
- postman设置全局变量及参数化
笔者第一次记录使用过程,仅供参考 测试过程中接口的前缀都是一样的,所以我们可以将这个前缀作为全局变量来使用 首先,打开postman点击这里的小齿轮设置 在这里就可以进行变量的一个添加,添加好之后记住 ...
- 150+行Python代码实现带界面的数独游戏
150行代码实现图形化数独游戏 Github地址,欢迎各位大佬们fork.star啥的,感谢: 今天闲着没事干,以前做过html+js版的数独,这次做个python版本的,界面由pygame完成,数独 ...
- SQL server 2008 简介
一.简介 网状模型 关系模型(独立表) 拆分成有主键的表.连接表即可. 工资与奖金有了依赖关系.所以可以不保存奖金,计算得出结果. 二. 1. 2.环境配置 安装iis服务 https://jingy ...
- MATLAB——nctoolbox安装及使用
1.nctoolbox安装 nctoolbox是一个Matlab工具箱,它提供对通用数据模型数据集的只读访问. (1)下载nctoolbox安装包. 地址:https://code.google.co ...
- Bootstrap Blazor 组件库
项目介绍 Blazor 是一个使用 .NET 生成交互式客户端 Web UI 的框架: 使用 C# 代替 JavaScript 来创建丰富的交互式 UI. 共享使用 .NET 编写的服务器端和客户端应 ...
- IBN-Net: 提升模型的域自适应性
本文解读内容是IBN-Net, 笔者最初是在很多行人重识别的库中频繁遇到比如ResNet-ibn这样的模型,所以产生了阅读并研究这篇文章的兴趣,文章全称是: <Two at Once: Enha ...
- 别人家的 InfluxDB 实战 + 源码剖析
1. 前几次的分享,我们多次提到了下图中 Metrics 指标监控的 Prometheus.Grafana,而且 get 到了 influxdata 旗下的 InfluxDB 的入门技能. 本次,我们 ...
- DOM--选取文档元素
大多数的客户端JavaScript程序在运行时都是在操作一个或者多个文档元素,而为了操作文档中的元素我们就必须要通过某种途径或者方法获得或者选取这些引用文档元素的Element对象.DOM定义了许多种 ...
- 多线程学习笔记(四)---- Thread类的其他方法介绍
一.wait和 sleep的区别 wait可以指定时间也可以不指定时间,而sleep必须指定时间: 在同步中时,对cpu的执行权和锁的处理不同: wait:释放执行权,释放锁:释放锁是为了别人noti ...