【问题标题】:How do I efficiently extract image patches at specified locations?如何有效地提取指定位置的图像补丁?
【发布时间】:2015-01-04 06:06:03
【问题描述】:

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

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

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

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

【问题讨论】:

  • 您是否将 (x,y) 位置存储在向量中?
  • 是的。我有 (x,y) 作为向量。

标签: matlab image-processing


【解决方案1】:

您可以使用图像处理工具箱中的im2col 将每个像素邻域转换为单列。像素邻域的选择使得每个块都是在column-basis上选择的,这意味着块是通过首先遍历行来构造的,然后继续到下一列并在那里得到邻域。

你这样打电话给im2col:

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

我假设您需要滑动/重叠邻域,而不是不同的邻域,这是执行任何类型的图像过滤时通常使用的。 A 是您的图像,您希望找到转换为列的 M x N 像素邻域。 B 将是每个邻域是单个列并且水平平铺在一起的输出。但是,您可能需要处理想要沿图像边界抓取像素邻域的情况。在这种情况下,您需要先填充图像。我们将假设M 和N 是奇怪的,以使填充更容易。具体来说,您要确保在图像顶部和底部填充有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) 坐标转换为线性索引,以便我们可以选择我们想要的像素邻域。因此,假设您的位置存储在向量x 和y 中,您将执行以下操作:

%// 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-loops 的天真方法在某种程度上击败了我们的解决方案!? (使用2000-by-2000-by-3 图像并提取越来越多的3-by-3-by-3 块。)
  • @knedlsepp 某些操作使用循环会更快......我的猜测是 JIT 踢了这次并击败了我们!
  • @knedlsepp 顺便说一句,谢谢 :) 也很喜欢你的方法,bsxfun。
  • 我不得不承认,我在几个小时前就意识到,bsxfun 部分在这里实际上并没有做任何事情。 ;-) 我想我应该删除它或以某种方式实际使用它...
【解决方案2】:

这可能看起来很意外,但对我来说,天真的for-loop 实际上是最快的。不过,这可能取决于您的 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

幼稚的方法:(比im2col 和arrayfun 更快!)

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);

【讨论】:

  • @user570593:我很想知道在你的机器上你是否能得到类似的性能结果。
猜你喜欢
  • 2018-10-06
  • 1970-01-01
  • 1970-01-01
  • 2020-08-22
  • 2019-10-22
  • 2017-07-09
  • 2021-01-20
  • 2018-01-31
  • 2019-06-17
相关资源
最近更新 更多