问题描述
我想知道在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数组A
和B
,因此我们应用repmat
沿第3维复制它(这里的3是重复次数,我们假设A
和B
是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...
矩阵包含0
和1
,因此我们可以将它们逐元素地乘以A
和B
以过滤出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