如何在指定位置有效提取图像补丁?

时间:2015-01-01 18:32:59

标签: matlab image-processing

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

如果没有for循环,我怎样才能有效地做到这一点?我知道我可以在(x,y)位置提取一个补丁:

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

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

2 个答案:

答案 0 :(得分:6)

您可以使用图像处理工具箱中的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{:});

以上代码将创建im2col的3D版本,其中每个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);

答案 1 :(得分:1)

这看起来很意外,但对我来说,天真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);