如何在指定位置有效地提取映像补丁



我需要从图像(3 个通道)中提取指定 2D 位置周围大小s x s x 3的图像块。

如何在没有for循环的情况下有效地做到这一点? 我知道我可以在(x,y)位置周围提取一个补丁,如下所示:

apatch = I(y-s/2:y+s/2, x-s/2:x+s/2, :)

如何为许多补丁执行此操作? 我知道我可以blockproc使用 MATLAB 的函数,但我无法指定位置。

您可以使用

图像处理工具箱中的im2col将每个像素邻域转换为单个列。 选择像素邻域时,每个块都是按列选择的,这意味着块是通过先向下遍历行,然后继续到下一列并在那里获得邻域来构建的。

你这样称呼im2col

B = im2col(A, [M N]);

我假设您需要滑动/重叠的邻域,而不是不同的邻域,这是执行任何类型的图像过滤时通常使用的邻域。 A是您的图像,您希望查找转换为列M x N像素邻域。 B是输出,其中每个邻域都是一根列并水平平铺在一起。 但是,您可能希望处理要沿图像边界抓取像素邻域的情况。 在这种情况下,您需要先填充图像。 我们将假设MN是奇数,以使填充更容易。 具体来说,您希望确保在图像顶部和底部填充了floor(M/2)行,并在图像左侧和右侧填充了floor(N/2)列。 因此,我们应该首先使用 padarray 填充A。 假设边框像素将被复制,这意味着填充的行和列将只是从顶部或底部行或左右列抓取的行和列,具体取决于我们需要填充的位置。 因此:

Apad = padarray(A, floor([M N]/2), 'replicate');

对于下一部分,如果要选择指定邻域,可以使用sub2ind将 2D 坐标转换为线性索引,以便选择正确的列以获得正确的像素块。 但是,由于您有彩色图像,因此您需要在每个颜色通道上执行im2col。 不幸的是,im2col仅适用于灰度图像,因此您必须对图像中的每个通道重复此操作。

因此,要为补丁采样做好准备,请执行以下操作:

B = arrayfun(@(x) im2col(Apad(:,:,x), [M N]), 1:size(A,3), 'uni', 0);
B = cat(3, B{:});

上面的代码将创建一个 3D 版本的 im2col ,其中每个 3D 切片将是im2col为每个颜色通道生成的内容。 现在,我们可以使用sub2ind将您的(x,y)坐标转换为线性指数,以便我们可以选择所需的像素邻域。 因此,假设您的仓位存储在向量 xy 中,您将执行以下操作:

%// Generate linear indices
ind = sub2ind([size(A,1) size(A,2)], y, x);
%// Select neighbourhoods
%// Should be shaped as a MN x len(ind) x 3 matrix
neigh = B(:,ind,:);
%// Create cell arrays for each patch
patches = arrayfun(@(x) reshape(B(:,x,:), [M N 3]), 1:numel(ind), 'uni', 0);

patches将是一个单元数组,其中每个元素在您指定的(x,y)的每个位置都包含所需的修补程序。 因此,patches{1}是位于(x(1), y(1))的补丁,patches{2}是位于(x(2), y(2))等地的补丁。 为了您的复制和粘贴乐趣,这就是我们拥有的:

%// Define image, M and N here
%//...
%//...
Apad = padarray(A, floor([M N]/2), 'replicate');
B = arrayfun(@(x) im2col(Apad(:,:,x), [M N]), 1:size(A,3), 'uni', 0);
B = cat(3, B{:});
ind = sub2ind([size(A,1) size(A,2)], y, x);
neigh = B(:,ind,:);
patches = arrayfun(@(x) reshape(neigh(:,x,:), [M N 3]), 1:numel(ind), 'uni', 0);

尽管这看起来很出乎意料,但对我来说,天真的for循环实际上是最快的。这可能取决于您的 MATLAB 版本,因为对于较新版本,它们会不断改进 JIT 编译器。

常用数据:

A = rand(30, 30, 3); % Image
I = [5,2,3,21,24]; % I = y 
J = [3,7,5,20,22]; % J = x
s = 3; % Block size

幼稚的方法:(比im2colarrayfun更快!

Patches = cell(size(I));
steps = -(s-1)/2:(s-1)/2;
for k = 1:numel(Patches);
    Patches{k} = A(I(k)+steps, ...
                   J(k)+steps, ...
                   :);
end

使用arrayfun的方法:(比循环慢)

steps = -(s-1)/2:(s-1)/2;
Patches = arrayfun(@(ii,jj) A(ii+steps,jj+steps,:), I, J, 'UniformOutput', false);

最新更新