Matlab 如何在指定位置有效地提取图像修补程序?

Matlab 如何在指定位置有效地提取图像修补程序?,matlab,image-processing,Matlab,Image Processing,我需要从图像(3个通道)的指定2D位置周围提取大小为sxsx3的图像块 如果没有for循环,如何有效地执行此操作?我知道我可以在(x,y)位置提取一个补丁,如下所示: apatch = I(y-s/2:y+s/2, x-s/2:x+s/2, :) 如何为许多修补程序执行此操作?我知道我可以使用MATLAB的函数blockproc,但我不能指定位置。这似乎出乎意料,但对我来说,天真的for-循环实际上是最快的。不过,这可能取决于您的MATLAB版本,因为较新的版本会不断改进JIT编译器 常用数据

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

如果没有
for
循环,如何有效地执行此操作?我知道我可以在
(x,y)
位置提取一个补丁,如下所示:

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

如何为许多修补程序执行此操作?我知道我可以使用MATLAB的函数
blockproc
,但我不能指定位置。

这似乎出乎意料,但对我来说,天真的
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
天真的方法:(比
im2col
arrayfun
更快) 使用
arrayfun
进近:(比循环慢) 您可以使用图像处理工具箱将每个像素邻域转换为一列。像素邻域的选择使得每个块在列的基础上进行选择,这意味着通过首先向下遍历行,然后继续到下一列并在那里获得邻域来构建块

你这样称呼:

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

Apad = padarray(A, floor([M N]/2), 'replicate');
对于下一部分,如果要选择“指定邻域”,可以使用将二维坐标转换为线性索引,以便选择正确的列以获得正确的像素块。但是,由于您有彩色图像,因此需要在每个彩色通道上执行
im2col
。不幸的是,
im2col
仅适用于灰度图像,因此您必须对图像中的每个通道重复此操作

因此,要准备进行修补程序采样,请执行以下操作:

B = arrayfun(@(x) im2col(Apad(:,:,x), [M N]), 1:size(A,3), 'uni', 0);
B = cat(3, B{:});
%// 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);
上述代码将创建一个3D版本的
im2col
,其中每个3D切片将是
im2col
为每个颜色通道生成的。现在,我们可以使用
sub2ind
(x,y)
坐标转换为线性索引,以便选择所需的像素邻域。因此,假设您的位置存储在向量
x
y
中,您将执行以下操作:

B = arrayfun(@(x) im2col(Apad(:,:,x), [M N]), 1:size(A,3), 'uni', 0);
B = cat(3, B{:});
%// 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);

(x,y)位置是否存储在向量中?是的。我把(x,y)作为向量,因为我喜欢你的方法,所以我做了一些测试。似乎对-循环使用
的天真方法在某种程度上击败了我们的两种解决方案!?(使用
2000-by-2000-by-3
图像并提取越来越多的
3-by-3-by-3
块。)@knedlsepp使用循环会加快某些操作。。。。我猜这次是JIT踢进来打败我们了@knedlsepp顺便说一句,谢谢:)也喜欢你的方法,
bsxfun
。我必须承认,我在几个小时前意识到,
bsxfun
部分实际上在这里没有任何作用。;-)我想我应该删除它或者以某种方式使用它…@user570593:我很想知道你的机器上是否有类似的性能结果。