2

我是 Octave/MATLAB 的新手。我想为一个三角形矢量化一个简单的扫描线填充。这是我要消除的 while 循环:

 #Iterate over all the scan lines from bottom to top
 while(yCurr <= 200)

    #VARIABLES: 
    #  img - Zero matrix used as an image. Zero is black. Assume 320x200 pixels.
    #  leftIdx - Vector that contains the left-most pixel to fill in each
    #      scanline. Dim is 1x200. Each element represents x-coord of a pixel.
    #  rightIdx - Vector that contains the right-most pixel to fill in each
    #      scanline. Dim is also 1x200. Each element represents x-coord of a pixel.
    #  yCurr - The current row being scanned.    

    #Fill all the pixels in one scan line 
    img(leftIdx(yCurr) : rightIdx(yCurr), yCurr) = color;

    #Increment the row
    yCurr++;

 endwhile
4

3 回答 3

2

简单的解决方案 - 您可以将循环直接更改为一个 arrayfun 调用。arrayfun 是一种编写循环的奇特方式——它为所有提供的参数调用用户定义的函数。需要注意的是,通常与 arrayfun 一起使用的匿名函数不能分配变量。但是,您可以编写一个普通函数,将颜色分配给 img 并将其作为参数传递给 arrayfun:

 function doAllWork(img, rightIdx, leftIdx)

 arrayfun(@fill, 1:size(img, 1));

    function fill(i)
      img(leftIdx(i):rightIdx(i), i) = color;
    end
 end

我已经在 doAllWork 中将 fill 函数定义为本地函数,以便它可以访问 img、leftIdx、rightIdx。

复杂的解决方案通常在这种情况下,要一次性进行分配,您希望使用 sub2ind 来获得矩阵的线性索引(简而言之,在 C 中您会写 sth. like j*nx+i)。然后你写 img(ind) 而不是 img(indrow, indcol)。问题是每一行在不同的地方都有不同数量的非零。

(复杂的)想法是创建一个明确的列索引数组 Ii{row} = [leftIdx(row):rightIdx(row)] 和相应的行索引数组 Ij{row} = [row*ones(1, lenght(Ii{行}))] 为所有行。没有可以使用 arrayfun 完成的循环。一旦你有了这个,你可以在对应的 Ii/Ij 条目上使用 sub2ind 构造一个线性索引到你的 img 中,也称为使用 arrayfun。代码看起来像这样

nrows=1:size(img, 1);
Ii=arrayfun(@(i)(leftIdx(i):rightIdx(i)), nrows, 'UniformOutput', false);
Ij=arrayfun(@(i)(i*ones(1,length(Ii{i}))), nrows, 'UniformOutput', false);
lin=arrayfun(@(i)(sub2ind(size(A), Ij{i}, Ii{i})), nrows, 'UniformOutput', false);
img([lin{:}])=color;

这种方法在您的情况下没有多大用处 - 它太复杂了。但它对 arrayfun 可以做什么具有指导意义,并且 sub2ind 的技巧通常非常有用。

于 2012-09-18T19:45:05.693 回答
1

虽然不是 OP 的主要问题(即如何矢量化光栅扫描),但 MATLAB 中用于填充三角形值的干净外观解决方案可以来自使用poly2mask指定三角形内部的区域、使用三角形顶点和使用逻辑索引赋值。

% Example values
yCurr = 1:200;
img = zeros(320, 200);
leftIdx = ones(1,200);
rightIdx = 1:200;
color = 1;

% Define polygon vertices and get mask
x = [leftIdx(1) leftIdx(200) rightIdx(1) rightIdx(200)];
y = [1 1 200 200];
bw = poly2mask(x,y,320,200);
% Assign color values
img(bw) = color; 

由于poly2mask很可能使用了一些底层for,,因此它不是光栅化扫描的矢量化版本。但是,它提供了处理更复杂的多边形区域的好处。

于 2012-09-18T21:39:28.013 回答
1

我认为您最初的基于循环的解决方案是最好的解决方案。为什么?

  1. 因为在您没有完成分析之前,您无法知道矢量化解决方案是否实际上更快。
  2. 因为您使用 for 循环的代码对读者来说很清楚!它只包含 4 行代码,一看就知道它的用途。

我唯一要改变的是while->for

for yCurr = 1:200
    img(leftIdx(yCurr) : rightIdx(yCurr), yCurr) = color;
 end
于 2012-09-18T20:49:25.470 回答