计算机视觉python--计算视差图

文章目录

  • 1. 立体视差
  • 2. 双目立体视觉
  • 3 归一化互相关(NCC)
  • 4. 计算视差图的步骤
  • 5 实验代码
  • 7 实验结果分析

1. 立体视差

立体视差 ,亦称立体视像、立体知觉。基于双眼视差所 获得的深度知觉。

立体视差的测量包括三个步骤:
(1)必须从一幅图像中选出位于场景中一个表面上的某一特定位置;
(2)必须在另一幅图像中鉴别出同一个位置;
(3)测出这两个对应像点之间的视差。

在一组重复摄影的两张照片上(立体模式),同一地物的影象,沿着摄影基线(摄影地点和下一个摄影地点之间的飞行方向线)方向位置变换,这个变化量叫“立体视差”。

立体视差在每张照片上,从那点到照片基线(临接摄影地点与照片的摄影地点的像连结的直线),下垂线的足和主点(相片中心)之间叫距离之和。这是把相对两个照片的基线方向,使其成为一直线,按摄影顺序排列时,和相应的同一地物影象间的两个照片主点之间的间隔差。

2. 双目立体视觉

双目立体视觉(Binocular Stereo Vision是机器视觉的一种重要形式,它是基于视差原理并利用成像设备从不同的位置获取被测物体的两幅图像,通过计算图像对应点间的位置偏差,来获取物体三维几何信息的方法。

为什么双目相机才能得到深度?
下图从物理原理上展示了为什么单目相机不能测量深度值而双目可以的原因。我们看到红色线条上三个不同远近的黑色的点在下方相机上投影在同一个位置,因此单目相机无法分辨成的像到底是远的那个点还是近的那个点,但是它们在上方相机的投影却位于三个不同位置,因此通过两个相机的观察可以确定到底是哪一个点。
计算机视觉python--计算视差图_第1张图片

提到双目视觉就不得不提视差图:双目立体视觉融合两只眼睛获得的图像并观察它们之间的差别,使我们可以获得明显的深度感,建立特征间的对应关系,将同一空间物理点在不同图像中的映像点对应起来,这个差别,我们称作视差(Disparity)图像。
(对于视差的理解自己可以体验一下:将手指头放在离眼睛不同距离的位置,并轮换睁、闭左右眼,可以发现手指在不同距离的位置,视觉差也不同,且距离越近,视差越大。)

这里再解释一下视差:视差是指在两个摄像机图像之间的像素位置的差异。假设立体视觉相机中的左图像在位置(1,30)具有像素,并且相同的像素在右图像中的位置(4,30)存在,视差值或差值为(4-1)=3。视差值与深度成反比。

深度图:深度图像也叫距离影像,是指将从图像采集器到场景中各点的距离(深度)值作为像素值的图像。获取方法有:激光雷达深度成像法、计算机立体视觉成像、坐标测量机法、莫尔条纹法、结构光法。

点云:当一束激光照射到物体表面时,所反射的激光会携带方位、距离等信息。若将激光束按照某种轨迹进行扫描,便会边扫描边记录到反射的激光点信息,由于扫描极为精细,则能够得到大量的激光点,因而就可形成激光点云。

深度图与点云的区别: 深度图像经过坐标转换可以计算为点云数据;有规则及必要信息的点云数据可以反算为深度图像。 两者在一定条件下是可以相互转化的,之前的博客里,有使用PCL库实现过点云提取深度图,当然给出相机参数也是可以由深度图转为点云的。截图一个深度图:
计算机视觉python--计算视差图_第2张图片

3 归一化互相关(NCC)

计算机视觉python--计算视差图_第3张图片

4. 计算视差图的步骤

计算机视觉python--计算视差图_第4张图片

5 实验代码

import stereo
import scipy.misc
from PIL import Image
from pylab import *
from scipy.ndimage import *


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(roll(norm_l, -displ - start) * norm_r, wid, s)  # 和归一化
        filters.uniform_filter(roll(norm_l, -displ - start) * 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 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(roll(norm_l, -displ - start) * norm_r, wid, 0, s)  # 和归一化

        filters.gaussian_filter(roll(norm_l, -displ - start) * roll(norm_l, -displ - start), wid, 0, s_l)
        filters.gaussian_filter(norm_r * norm_r, wid, 0, s_r)  # 和反归一化
    # 保存 ncc 的分数
    dmaps[:, :, displ] = s / sqrt(s_l * s_r)
    # 为每个像素选取最佳深度
    return argmax(dmaps, axis=2)


im_l = array(Image.open('d:/picture/008/im2.ppm').convert('L'), 'f')
im_r = array(Image.open('d:/picture/008/im6.ppm').convert('L'), 'f')
# 开始偏移,并设置步长
steps = 50
start = 4

# ncc 的宽度
wid = 13

res = plane_sweep_ncc(im_l, im_r, start, steps, wid)

imsave('d:/picture/008/depyh6.jpg', res)

7 实验结果分析

原图
计算机视觉python--计算视差图_第5张图片
计算机视觉python--计算视差图_第6张图片

wid=3
计算机视觉python--计算视差图_第7张图片

wid=5
计算机视觉python--计算视差图_第8张图片

wid=7
计算机视觉python--计算视差图_第9张图片

wid=9
计算机视觉python--计算视差图_第10张图片

wid=11
计算机视觉python--计算视差图_第11张图片

wid=13

计算机视觉python--计算视差图_第12张图片

wid=20
计算机视觉python--计算视差图_第13张图片

wid=30计算机视觉python--计算视差图_第14张图片

wid=50
计算机视觉python--计算视差图_第15张图片

wid=100
计算机视觉python--计算视差图_第16张图片

窗口代价计算视差的原理
如果是以单个特征点来计算视差的话容易出现较大的误差,比如相似的特征点很多或者因视觉问题出现的看得见看不见问题,所以就要用视窗来计算视差,原理是通过一个特征点为中心点设定一个固定长度的正方形,然后计算视差的时候就是由这个正方形和另一张图片特征点所形成的正方形进行对比计算,计算时用合适的窗口匹配算法也就是ncc来计算,从而得出视差

结果分析
通过前面不同wid的值跑出来的结果图片对比得出,当wid的值偏小时也就是窗口略小时,会存在比较多的噪声,可能是因为虽然已经由特征点变成窗口但是由于窗口太小和其他的窗口相似的可能性还是很大,所以会存在噪声。我们可以看到再接下来的图片中可以看出,当wid以一个不大的数值增大,图片并没有出现太多的变化。然后我就想试一下,当窗口的宽度大到一定程度的时候的出来的结果会是什么样子的。就计算了wid=30,50,100的实验结果.我们可以发现图片变得越来越光滑导致与原图片所搭配出来的完美图片的差距越来越来,可以分析得出,当窗口越来越大时和小窗口相通,与他相似的特征点也会越来越多在步长不变的情况下,导致计算出来的视差没有明显的跨度,导致图片的颜色层次越来越少。

你可能感兴趣的:(计算机视觉python--计算视差图)