Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/matlab/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Matlab 一种同时提取数千个位置邻域像素的有效方法_Matlab_Loops_For Loop_Image Processing_Matrix - Fatal编程技术网

Matlab 一种同时提取数千个位置邻域像素的有效方法

Matlab 一种同时提取数千个位置邻域像素的有效方法,matlab,loops,for-loop,image-processing,matrix,Matlab,Loops,For Loop,Image Processing,Matrix,我试图提取图像的8个像素。但是,我希望对数百个位置同时执行此操作(函数中的行和列)。这意味着输出块是一个3D矩阵,3D矩阵的每个切片对应于单个位置 function Block = getNeighbours(image, row, column) % Create a 3x3 matrix that contains the neighbors of the point (row,column) row=round(row(:)); column=round(column(:)

我试图提取图像的8个像素。但是,我希望对数百个位置同时执行此操作(函数中的
)。这意味着输出
是一个3D矩阵,3D矩阵的每个切片对应于单个位置

function Block = getNeighbours(image, row, column)
% Create a 3x3 matrix that contains the neighbors of the point (row,column)
    row=round(row(:));
    column=round(column(:));
    neighbors_x = [row(:,1)-1 row(:,1) row(:,1)+1];
    neighbors_y = [column(:,1)-1 column(:,1) column(:,1)+1];
    Block = zeros(3,3,size(row,1));
    for i=1:size(row,1)
    Block(:,:,i) = image(neighbors_x(i,:), neighbors_y(i,:)); %can I avoid this loop?
    end
end
根据上面的代码,我需要循环来完成这项工作。这似乎是这一功能的瓶颈,对于数千个地点来说,这绝对是没有效率的。有没有办法避免这种情况

您可以通过以下方式尝试此功能:

image=randi([1 255], [300 300]);
row=randi([1 200], [1 1000]);
column=randi([1 200], [1 1000]);

block=getNeighbours(image, row, column);

您可以对行-列索引使用
sub2ind
,然后添加常规9邻域索引以形成块索引。对于大量的行-列对,其速度大约是使用循环的10倍:

image=randi([1 255], [300 300]);
row=randi([2 200], [1 10000]);
column=randi([2 200], [1 10000]);
tic;
sz = size(image);
% general 9-neighberhood indexes
hoodIdxs = [-sz(2)-1,-1,sz(2)-1;-sz(2),0,sz(2);-sz(2)+1,1,sz(2)+1];
% linear indexes of requested pixels
idxs = permute(sub2ind(sz,row,column),[1 3 2]);
% block indexes
blockIdxs = bsxfun(@plus,idxs,hoodIdxs);
% generate blocks
blocks = image(blockIdxs);
toc;
% OP's function
tic;
blocks_loop = getNeighbours(image, row, column); % ~10 times slower
toc
% check
isequal(blocks, blocks_loop) % yes
请注意,在生成随机行和列时,我将
randi
间隔的下端设置为
2
,否则图像边缘上的行列在尝试调用
blocks=image(blockIdxs)时将抛出索引错误。您可以通过填充图像(此处填充了
nan
)轻松克服此问题:


如果您有图像处理工具箱,一个选项是将图像预处理为块,一次生成所有邻域。如果需要多次访问块,这将特别有效

给出一个图像:

>> img = reshape(1:25,5,5)

img =

    1    6   11   16   21
    2    7   12   17   22
    3    8   13   18   23
    4    9   14   19   24
    5   10   15   20   25
im2col
将每个有效块(这很重要…)转换为矩阵的一列:

C = im2col(img,[3,3])

C =

    1    2    3    6    7    8   11   12   13
    2    3    4    7    8    9   12   13   14
    3    4    5    8    9   10   13   14   15
    6    7    8   11   12   13   16   17   18
    7    8    9   12   13   14   17   18   19
    8    9   10   13   14   15   18   19   20
   11   12   13   16   17   18   21   22   23
   12   13   14   17   18   19   22   23   24
   13   14   15   18   19   20   23   24   25
如您所见,
C
的第一列具有索引
7
img(2,2)
的邻域值。下一个是索引
8
,或
img(3,2)
,依此类推。偏移是因为
im2col
仅提供有效块。如果这是您想要的,您只需记住从行/列下标中减去
1
,然后使用以下方法在
C
中查找列号:

(如果填充图像,索引和下标与原始图像中的索引和下标相同。)

因此,
img(2,2)
的邻域的列索引是
1

你可以停在这里。如果要将同一内核应用于所有查询的邻域,只需将内核生成行向量并进行乘法,选择要考虑的
C
列:

kernel = ones(3)/9
kernel =

   0.11111   0.11111   0.11111
   0.11111   0.11111   0.11111
   0.11111   0.11111   0.11111

kernel(:).' * C
ans =

    7.0000    8.0000    9.0000   12.0000   13.0000   14.0000   17.0000   18.0000   19.0000

C_idx = [1:9];   % or randi(9, 1, 4), or any valid list of column numbers
k_vec = kernel(:).';   % turn kernel into a row vector
result = k_vec * C(:, C_idx);

result =

    7.0000    8.0000    9.0000   12.0000   13.0000   14.0000   17.0000   18.0000   19.0000

如果您不满意邻域是列向量,并且确实希望它们是3x3块,则可以将
C
矩阵重塑为三维矩阵:

D = reshape(C, 3, 3, []);

D =

ans(:,:,1) =

    1    6   11
    2    7   12
    3    8   13

ans(:,:,2) =

    2    7   12
    3    8   13
    4    9   14

ans(:,:,3) =

    3    8   13
    4    9   14
    5   10   15

ans(:,:,4) =

    6   11   16
    7   12   17
    8   13   18

ans(:,:,5) =

    7   12   17
    8   13   18
    9   14   19

ans(:,:,6) =

    8   13   18
    9   14   19
   10   15   20

ans(:,:,7) =

   11   16   21
   12   17   22
   13   18   23

ans(:,:,8) =

   12   17   22
   13   18   23
   14   19   24

ans(:,:,9) =

   13   18   23
   14   19   24
   15   20   25
从这里开始,您对列使用与以前相同的索引,但现在它们是第三维的索引,例如:

>> D(:, :, 1)
ans =

    1    6   11
    2    7   12
    3    8   13

为您提供与
C(:,1)

相同的邻域,您打算如何处理这些块?听起来很可疑,你是想用艰难的方式进行卷积。你说的“艰难的”卷积方式是对的。由于我有数千种不同的内核,
convn
将非常昂贵。我使用的方法只考虑块而不是整个图像。代码>convn(图像、内核)
将非常耗时。也许您有一个建议?您应该首先使用
conv2
对解决方案进行基准测试。除非你的形象是巨大的,而且你只使用了一小部分社区,否则很难打败它。这太棒了!谢谢非常感谢您的详细回答!如果假定多个循环的
图像
相同,因此只调用
im2col
一次,那么您的方法比user2999345更快,这对我来说就是如此!所以我在实施你的方法!
D = reshape(C, 3, 3, []);

D =

ans(:,:,1) =

    1    6   11
    2    7   12
    3    8   13

ans(:,:,2) =

    2    7   12
    3    8   13
    4    9   14

ans(:,:,3) =

    3    8   13
    4    9   14
    5   10   15

ans(:,:,4) =

    6   11   16
    7   12   17
    8   13   18

ans(:,:,5) =

    7   12   17
    8   13   18
    9   14   19

ans(:,:,6) =

    8   13   18
    9   14   19
   10   15   20

ans(:,:,7) =

   11   16   21
   12   17   22
   13   18   23

ans(:,:,8) =

   12   17   22
   13   18   23
   14   19   24

ans(:,:,9) =

   13   18   23
   14   19   24
   15   20   25
>> D(:, :, 1)
ans =

    1    6   11
    2    7   12
    3    8   13