在MATLAB / Octave中矢量化三角形扫描线

时间:2012-09-18 19:16:45

标签: matlab graphics octave vectorization rasterizing

我是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

3 个答案:

答案 0 :(得分: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

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

复杂的解决方案通常在这种情况下,要一次性完成一项任务,你想使用sub2ind来获得矩阵的线性索引(简而言之,在C中,你会写出......就像j一样* NX + i)中。然后你写img(ind)而不是img(indrow,indcol)。问题是每一行在不同的地方都有不同数量的非零。

(复杂)的想法是创建一个显式列索引数组Ii {row} = [leftIdx(row):rightIdx(row)]和相应的行索引数组Ij {row} = [row * ones(1,lenght) (Ii {row}))]用于所有行。没有可以使用arrayfun完成的循环。一旦你有了这个,你可以使用sub2ind在相应的Ii / Ij条目上构建一个线性索引到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的技巧通常非常有用。

答案 1 :(得分:1)

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

  1. 因为在您没有进行分析之前,您无法知道矢量化解决方案是否实际上更快。
  2. 因为您使用for循环的代码对于读者来说是清楚的!它只包含4行代码,只有通过一看才能理解其目的。
  3. 我唯一要改变的是while - &gt; for

    for yCurr = 1:200
        img(leftIdx(yCurr) : rightIdx(yCurr), yCurr) = color;
     end
    

答案 2 :(得分: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,,因此它不是光栅化扫描的矢量化版本。但是,它提供了处理更复杂的多边形区域的好处。