【问题标题】:How to optimize conditional statement in for loop over image?如何优化图像循环中的条件语句?
【发布时间】:2021-01-10 00:13:14
【问题描述】:

我想知道是否有一种可索引的方式在 Octave 上执行以下代码,因为它是迭代的,因此与使用索引相比真的很慢。

for i = [1:size(A, 1)]
  for j = [1:size(A, 2)]
    if (max(A(i, j, :)) == 0)
      A(i, j, :) = B(i, j, :);
    endif
  endfor
endfor

A 和 B 是两个重叠的 RGB 图像,如果 A(i,j) 在所有三个通道上均为 0,我希望 A(i,j) 具有 B(i,j) 值。这种形式很慢,但我没有对这种语言进行足够的实验来对其进行矢量化。

【问题讨论】:

    标签: arrays loops image-processing vectorization octave


    【解决方案1】:

    这里没有添加太多,但也许这会让您更好地理解,因此值得添加另一个解决方案。

    % example data
      A = randi( 255, [2,4,3] ); A(2,2,:) = [0,0,0];
      B = randi( 255, [2,4,3] );
    
    % Logical array with size [Dim1, Dim2], such that Dim3 is 'squashed' into a 
    % single logical value at each position, indicating whether the third dimension
    % at that position does 'not' have 'any' true (i.e. nonzero) values.
      I = ~any(A, 3);
    
    % Use this to index A and B for assignment.
      A([I,I,I]) = B([I,I,I])
    

    这种方法可能比 repmat 更有效,repmat 是一种稍微昂贵的操作,但可能不太明显理解它的工作原理。 但是。了解它的工作原理会教你一些关于 matlab/octave 的知识,所以这是一个很好的学习点。

    Matlab 和 Octave 将数组存储在 column major order 中(与 Python 相对)。这也是执行A(:) 将返回A 作为向量的原因,该向量逐列构造。这也是您可以使用单个索引(称为“线性索引”)对 3 维数组进行索引的原因,该索引将对应于您在计算沿列的元素数量时到达的元素。

    执行逻辑索引时,matlab/octave 有效地获取一个逻辑向量,将该向量的每个线性索引与A 的等效线性索引匹配,并根据是否返回它的布尔值来决定是否返回它。该线性索引处的逻辑索引是真还是假。如果您提供的逻辑数组I 的大小小于A,则索引将简单地停止在I 的最后一个线性索引处。具体来说,请注意Ishape 无关紧要,因为无论如何它都会以线性索引方式进行解释。

    换句话说,使用I 的逻辑索引与使用I(:) 的逻辑索引相同,使用[I,I,I] 的逻辑索引与使用[ I(:); I(:); I(:) ] 的逻辑索引相同。

    如果I 的大小为A(:,:,1),则[I,I,I] 的大小为A(:,:,:),因此在线性索引意义上,它可以用作匹配I 的每个线性索引的有效逻辑索引A 的等效线性索引。

    【讨论】:

      【解决方案2】:

      你的代码可以被向量化如下:

      I = max(A,[],3) == 0;
      I = repmat(I,1,1,3);
      A(I) = B(I);
      

      第一行是循环中max 条件语句的直接副本,但在整个A 中进行了向量化。这将返回一个 2D 数组,我们不能直接使用它来索引 3D 数组 AB,因此我们应用 repmat 沿第 3 维复制它(这里的 3 是重复次数,我们重新假设 AB 是沿第三维具有 3 个元素的 RGB 图像)。最后,索引赋值将相关值从B 复制到A

      要将其推广到任何数组大小,请将repmat 语句中的“3”替换为size(A,3)

      【讨论】:

        【解决方案3】:

        max() function 可以采用单个矩阵并返回沿某个维度的最大值

        还有all() function 告诉您维度上的所有 值是否非零,any() function 告诉您维度上的任何 值是否维度不为零

        A = reshape(1:75, 5, 5, 3)
        A(2, 3, :) = 0;
        B = ones(size(A)) * 1000
        
        use_pixel_from_A = any(A, 3)
        use_pixel_from_B = ~use_pixel_from_A
        

        现在对于第 3 轴的每个元素,您知道从 A 获取哪些像素,从 B 获取哪些像素。由于我们的use_pixel... 矩阵包含01,我们可以将它们逐元素乘以AB,以根据需要过滤掉AB 的元素。

        C = zeros(size(A));
        for kk = 1:size(A, 3)
            C(:, :, kk) = A(:, :, kk) .* use_pixel_from_A + B(:, :, kk) .* use_pixel_from_B
        end
        

        【讨论】:

          猜你喜欢
          • 2017-07-19
          • 1970-01-01
          • 1970-01-01
          • 2017-03-10
          • 2010-09-07
          • 2011-10-23
          • 2015-02-10
          • 2019-03-25
          • 1970-01-01
          相关资源
          最近更新 更多