如何优化循环图像中的条件语句?

问题描述

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

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

A和B是重叠的两个RGB图像,并且如果三个通道上所有A(i,j)都为0,我希望B(i,j)的值为A(i,j)。这种形式的速度非常慢,但是我还没有对这种语言进行矢量化实验。

解决方法

您的代码可以如下矢量化:

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

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

要将其概括为任意大小的数组,请将repmat语句中的“ 3”替换为size(A,3)

,

在这里没有添加太多内容,但是也许这会使您更好地理解,因此值得添加另一种解决方案。

% example data
  A = randi( 255,[2,4,3] ); A(2,2,:) = [0,0];
  B = randi( 255,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])

这种方法可能比repmat方法更有效,后者是一种稍贵的操作,但要了解其工作原理可能不太明显。 但是。了解它的工作原理会教给您一些关于matlab / octave的知识,所以这是一个不错的学习要点。

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

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

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

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

,

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

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

A = reshape(1:75,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以过滤出A的元素和B(根据需要)。

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