我试图提取图像的8个邻居像素。但是,我想同时对数百个位置(函数中的row
和column
)执行此操作。这意味着输出Block
是一个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);
答案 0 :(得分:1)
您可以在行列索引上使用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
,否则图像边缘上的行列会在尝试调用时抛出索引错误{ {1}}。您可以通过填充图像(此处填充blocks = image(blockIdxs);
)轻松克服此问题:
nan
答案 1 :(得分:1)
如果您有图像处理工具箱,一个选项是使用im2col将图像预处理为块,一次生成所有邻域。如果您需要多次访问块,这将特别有效。
给出一张图片:
>> 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
,然后使用sub2ind在C
中找到列号:
C_idx = sub2ind(size(img), 2-1, 2-1)
C_idx = 1
(如果填充图像,则索引和下标与原始图像中的相同。)
因此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
矩阵重塑为3D矩阵:
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)
相同的社区。 p>