20

Sto tentando di scrivere la mia funzione per ridimensionare un'immagine di input utilizzando l'algoritmo di interpolazione Nearest-neighbor. La parte cattiva è che sono in grado di vedere come funziona ma non riesco a trovare l'algoritmo stesso. Sarò grato per qualsiasi aiuto.Algoritmo di interpolazione vicino più vicino in MATLAB

Ecco quello che ho provato per scalare l'immagine in ingresso di un fattore di 2:

function output = nearest(input) 
[x,y]=size(input); 
output = repmat(uint8(0),x*2,y*2); 
[newwidth,newheight]=size(output); 
for i=1:y 
    for j=1:x 
     xloc = round ((j * (newwidth+1))/(x+1)); 
     yloc = round ((i * (newheight+1))/(y+1)); 
     output(xloc,yloc) = input(j,i); 
    end 
end 

Qui è l'uscita dopo il suggerimento Mark s' alt text

+0

Spiacente, non so cosa stavo pensando - è necessario iterare l'uscita, non l'input, poiché l'output è più grande. E in quel caso le mie formule avrebbero bisogno di essere invertite. –

risposta

19

Qualche tempo fa ho passato attraverso il codice della funzione imresize nella MATLAB Image Processing Toolbox per creare una versione semplificata per solo l'interpolazione delle immagini vicina più vicina. Ecco come sarebbe stato applicato al tuo problema:

%# Initializations: 

scale = [2 2];    %# The resolution scale factors: [rows columns] 
oldSize = size(inputImage);     %# Get the size of your image 
newSize = max(floor(scale.*oldSize(1:2)),1); %# Compute the new image size 

%# Compute an upsampled set of indices: 

rowIndex = min(round(((1:newSize(1))-0.5)./scale(1)+0.5),oldSize(1)); 
colIndex = min(round(((1:newSize(2))-0.5)./scale(2)+0.5),oldSize(2)); 

%# Index old image to get new image: 

outputImage = inputImage(rowIndex,colIndex,:); 

Un'altra opzione sarebbe quella di utilizzare il built-in interp2 funzione, anche se non menzionati che vogliono utilizzare le funzioni incorporate in uno dei tuoi commenti.

EDIT: SPIEGAZIONE

Nel caso in cui qualcuno è interessato, ho pensato di spiegare come la soluzione di cui sopra funziona ...

newSize = max(floor(scale.*oldSize(1:2)),1); 

In primo luogo, per ottenere le nuove dimensioni di righe e colonne le vecchie dimensioni di righe e colonne sono moltiplicate per il fattore di scala. Questo risultato viene arrotondato all'intero più vicino con floor. Se il fattore di scala è inferiore a 1 si potrebbe finire con un caso strano di uno dei valori di dimensione che sono 0, che è il motivo per cui la chiamata a max c'è da sostituire niente di meno di 1 con 1.

rowIndex = min(round(((1:newSize(1))-0.5)./scale(1)+0.5),oldSize(1)); 
colIndex = min(round(((1:newSize(2))-0.5)./scale(2)+0.5),oldSize(2)); 

Successivamente, viene calcolata una nuova serie di indici sia per le righe che per le colonne. Innanzitutto, viene calcolato un insieme di indici per l'immagine sovrastampata: 1:newSize(...). Si considera che ogni pixel dell'immagine abbia una larghezza determinata, tale che il pixel 1 si estenda da 0 a 1, il pixel 2 si estende da 1 a 2, ecc. La "coordinata" del pixel viene quindi considerata come il centro, motivo per cui 0.5 viene sottratto dagli indici. Queste coordinate vengono quindi divise per il fattore di scala per fornire un insieme di coordinate del centro dei pixel per l'immagine originale, che poi hanno aggiunto 0,5 e sono arrotondate per ottenere un insieme di indici interi per l'immagine originale. La chiamata a min assicura che nessuno di questi indici sia più grande della dimensione dell'immagine originale oldSize(...).

outputImage = inputImage(rowIndex,colIndex,:); 

Infine, la nuova immagine sovrastampata viene creata semplicemente indicizzando nell'immagine originale.

+0

funziona alla grande, grazie! – Hellnar

+0

@Hellnar: Felice di aiutare! Ho anche appena aggiornato il codice in modo che possa funzionare per fattori di scala non interi come pure per immagini in scala di grigi o RGB. – gnovice

0

Hai solo bisogno di una formula più generalizzato per il calcolo xloc e yloc.

xloc = (j * (newwidth+1))/(x+1); 
yloc = (i * (newheight+1))/(y+1); 

Questo presuppone che le variabili abbiano un intervallo sufficiente per i risultati di moltiplicazione.

2

MATLAB lo ha già fatto per voi. Utilizzare imresize:

output = imresize(input,size(input)*2,'nearest'); 

o se si vuole scalare sia x & y ugualmente,

output = imresize(input,2,'nearest'); 
+2

Sono già a conoscenza della funzione build-in, ma ho bisogno di farlo con il mio codice. grazie – Hellnar

+1

Siamo spiacenti, non lo so! È bello vedere che hai trovato la tua risposta. – Jacob

20

Questa risposta è più esplicativa che cercare di essere concisi ed efficienti. Penso che la soluzione di gnovice sia la migliore al riguardo. Se stai cercando di capire come funziona, continua a leggere ...

Ora il problema con il tuo codice è che stai mappando le posizioni dall'immagine di input all'immagine di output, motivo per cui stai ricevendo lo spot Uscita. Si consideri un esempio in cui l'immagine di ingresso è tutto bianco e uscita inizializzata al nero, otteniamo la seguente:

screenshot

Cosa si dovrebbe fare è l'opposto (da uscita e ingresso). Per illustrare, si consideri la seguente notazione:

1   c   1     scaleC*c 
+-----------+ 1  +----------------------+ 1 
| |  |   |  |    | 
|----o  | <=== |  |    | 
| (ii,jj) |   |--------o    | 
+-----------+ r  |  (i,j)   | 
    inputImage   |      | 
         |      | 
         +----------------------+ scaleR*r 
          ouputImage 

Note: I am using matrix notation (row/col), so: 
    i ranges on [1,scaleR*r] , and j on [1,scaleC*c] 
    and ii on [1,r], jj on [1,c] 

L'idea è che per ogni posizione (i,j) l'immagine di output in, vogliamo mappare nella posizione "più vicino" le coordinate di immagine di ingresso. Dal momento che si tratta di una semplice mappatura usiamo la formula che associa un dato x a y (dato tutti gli altri params):

x-minX  y-minY 
--------- = --------- 
maxX-minX maxY-minY 

nel nostro caso, x è il i/j coordinata e y è la ii/jj coordinata. Quindi sostituendo ciascun ci dà:

jj = (j-1)*(c-1)/(scaleC*c-1) + 1 
ii = (i-1)*(r-1)/(scaleR*r-1) + 1 

Mettendo insieme i pezzi, si ottiene il seguente codice:

% read a sample image 
inputI = imread('coins.png'); 
[r,c] = size(inputI); 
scale = [2 2];  % you could scale each dimension differently 

outputI = zeros(scale(1)*r,scale(2)*c, class(inputI)); 

for i=1:scale(1)*r 
    for j=1:scale(2)*c 
     % map from output image location to input image location 
     ii = round((i-1)*(r-1)/(scale(1)*r-1)+1); 
     jj = round((j-1)*(c-1)/(scale(2)*c-1)+1); 

     % assign value 
     outputI(i,j) = inputI(ii,jj); 
    end 
end 

figure(1), imshow(inputI) 
figure(2), imshow(outputI) 
+0

La soluzione di gnovice è circa 10 volte più veloce. Eppure, grazie per la spiegazione! – Wok

+0

Quando un'immagine I viene ridimensionata usando il vicino più prossimo a Izoom, e quindi Izoom viene ridotto dello stesso fattore, si ottiene di nuovo l'immagine originale I. Ora, intuitivamente, capisco che dal momento che stiamo facendo solo la replicazione dei pixel e non una media, questo è abbastanza naturale, ma non riesco a trovare una prova più rigorosa. Speravo che qualcuno qui potesse darmi qualche suggerimento su questo. – idexi