绝对差值立体匹配算法的实现

4

你好!

我正在尝试学习手动实现立体匹配算法。我基本上从最基础的算法开始——绝对差异。

我在网上找到了一些幻灯片,描述了如何进行操作。从我的理解来看,我应该计算左图像中的像素与右图像中“移位”一定距离/视差的同一像素之间的差异。然后,在这些视差中,我选择最小值,这对我来说是有意义的,因为具有最低视差的像素意味着它很可能是左图像中相同的像素。

我已经在MATLAB中创建了原型。以下是代码:

im_left = imread('tsu_left.png');
im_right = imread('tsu_right.png');

height = size(im_left, 1);
width = size(im_left, 2);

disparity_max = 16;

ad_costs = zeros(height, width,disparity_max);

for disparity = 1:disparity_max
    for row = 1:height
        for col = 1:width
            %Left to right matching
            col_disp = col - disparity;
            if col_disp < 1
                ad_costs(row, col, disparity) = 0;
            else
                %Average RGB
                left_pixel = (im_left(row, col, 1) + im_left(row, col, 2) + im_left(row, col, 3))/3;
                right_pixel = (im_right(row, col_disp, 1) + im_right(row, col_disp, 2) + im_right(row, col_disp, 3))/3;

                %Subtract averages
                ad_costs(row, col, disparity) = abs(left_pixel - right_pixel);
            end
        end
    end
end

min_costs = zeros(height, width);

for disparity = 1:disparity_max
    for row = 1:height
        for col = 1:width
            %The minimum disparity is chosen
            min_costs(row, col) = min(ad_costs(row, col, :));
        end
    end
end

请注意,我还没有实现在某个窗口中求和差异,导致了绝对差值之和。我只是按每个像素、每个视差的差异取值。我在网上找到的讲义说应该像这样(最右边的图片):https://dl.dropboxusercontent.com/u/92715312/lec.PNG
然而,使用imshow(min_costs)生成的代码结果看起来像这样:https://dl.dropboxusercontent.com/u/92715312/res.PNG
我无法弄清楚为什么输出结果如此不同。是否有一些微不足道的步骤我漏掉了,或者我的算法理解有误?我也使用tsukuba图像。
2个回答

2
这很可能是一个imshow问题。如果它是uint8,则函数imshow期望图像在范围[0, 255]内,如果是浮点数,则期望在[0.0, 1.0]范围内。
请尝试:
imshow(min_cost, []);

注意,第二个参数传入空数组。这告诉Matlab自动计算缩放比例。

或者使用:

imagesc(min_cost); axis image off;

编辑:

使用一些像素差异度量的普通立体声是相当简单的。请参见下面的代码:

function [D, C_min, C] = stereo_sad(I1, I2, min_d, max_d, w_radius)
  % function [D, C_min, C] = stereo_sad(I1, I2, min_d, max_d, w_radius)
  %
  % INPUT
  %   I1 the left stereo image
  %   I2 the right stereo image
  %   min_d minimum disparity
  %   max_d maximum disparity
  %   w_radius the radius of the window to do the AD aggeration
  %
  % OUTPUT
  %   D disparity values
  %   C_min cost associated with the minimum disparity at pixel (i,j)
  %   C  the cost volume for AD
  %

  if nargin < 5, w_radius = 4; end % 9x9 window
  if nargin < 4, max_d = 64; end
  if nargin < 3, min_d = 0; end

  % aggregation filter (window size to aggerate the AD cost)
  kernel = ones(w_radius*2+1);
  kernel = kernel ./ numel(kernel); % normalize it

  % grayscale is sufficient for stereo matching
  % the green channel is actually a good approximation of the grayscale, we
  % could instad do I1 = I1(:,:,2);
  if size(I1,3) > 1, I1 = rgb2gray(I1); end
  if size(I2,3) > 1, I2 = rgb2gray(I2); end

  % conver to double/single
  I1 = double(I1);
  I2 = double(I2);

  % the range of disparity values from min_d to max_d inclusive
  d_vals = min_d : max_d;
  num_d = length(d_vals);
  C = NaN(size(I1,1), size(I1,2), num_d); % the cost volume

  % the main loop
  for i = 1 : length(d_vals);
    d = d_vals(i);
    I2_s = imtranslate(I2, [d 0]);
    C(:,:,i) = abs(I1 - I2_s); % you could also have SD here (I1-I2_s).^2
    C(:,:,i) = imfilter(C(:,:,i), kernel);

  end

  [C_min, D] = min(C, [], 3);
  D = D + min_d;

end

运行代码的步骤如下:

  1. 读取左右两张图片(分别为I1和I2)
  2. 在每个视差处平移右侧图像,计算平移后的图像与左侧图像之间的绝对差异(或其他度量,如SSD)
  3. 使用矩形窗口进行平均处理,得到一个"盒式"滤波器
  4. 将每个像素点的平均值存储在一个代价"体素"中
  5. 视差位于每个像素点的代价体素的极小值处。视差将在最小值的索引位置上被确定

可以使用Matlab内置工具来执行这些操作,以生成易于阅读的代码。

你将得到一个视差映射,类似于下面的图片:
SAD stereo

希望这有所帮助。


我尝试了第一和第二个建议,但仍然无法输出类似幻灯片的图像。我真的想不出来 :( - renzbagaporo
1
您的disparity_max为16。尝试将其更改为更高的值。我将在帖子中附上一些简单的代码来实现这个过程。使用Matlab进行基本立体视觉并不复杂。此外,disparity是成本体积中的索引。请查看我编辑过的帖子。 - bendervader
哇!非常感谢您提供的示例代码 :) 在研究了您的代码之后,我现在知道自己错在哪里了。基本上,我以为最低成本本身就形成了视差图。然而,应该做的是将最低成本映射到产生它的视差上。这就成为了视差图。这就是为什么我认为我缺少一个微不足道的步骤。 - renzbagaporo

0

我认为你应该在最小化步骤之后进行过滤

SAD

你好,你知道如何计算平滑度成本吗? - Raziel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接