2017-05-26 54 views
1

我試圖提取圖像的8個鄰居像素。不過,我想同時執行此操作的數百個位置(功能中的rowcolumn)。這意味着輸出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

您打算如何處理這些區塊?這聽起來很可疑,就像你試圖以艱難的方式進行卷積。 – beaker

+0

關於卷積的'硬'方式你是對的。由於我有數千個不同的內核,'convn'將會非常昂貴。我使用的方法只考慮塊而不是整個圖像。 'convn(image,kernels)'會很耗時。也許你有一個建議? –

+0

您應該首先使用'conv2'對基準解決方案進行基準測試。除非你的形象很大,而你只使用少量的社區,否則很難被打敗。 – beaker

回答

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的下端,否則一個行 - 列在嘗試撥打blocks = image(blockIdxs);時,在圖像邊緣會產生索引錯誤。您可以輕鬆地通過填充的圖像(nan的位置補齊)克服了這一點:如果您有圖像處理工具箱

% pad image edges with nans 
padded = padarray(image,[1 1],nan,'both'); 
sz = size(padded); 
% 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 (+1 because of the padding) 
idxs = permute(sub2ind(sz,row + 1,column + 1),[1 3 2]); 
% block indexes 
blockIdxs = bsxfun(@plus,idxs,hoodIdxs); 
% generate blocks 
blocks = padded(blockIdxs); 
+0

這太棒了!謝謝! –

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的第一列具有索引7img(2,2)的鄰域值。下一個是索引8img(3,2),依此類推。抵消是因爲im2col只給你有效的塊。如果這是你想要的,你只需要記住使用sub2indC找到列號之前減去行/列標1

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 

如果您又不是高興的街區是列向量,真的希望他們是3×3塊,你可以重塑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)

+0

非常感謝你的詳細解答!你的方法是更快的user2999345's,** IF **假設'image'對於幾個循環是相同的,因此只調用'im2col'一次,對我來說就是這樣!所以我正在實施你的方法! –