Matlab 一种同时提取数千个位置邻域像素的有效方法
我试图提取图像的8个像素。但是,我希望对数百个位置同时执行此操作(函数中的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(:)
行
和列
)。这意味着输出块
是一个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