20

Estoy intentando escribir mi propia función para escalar una imagen de entrada utilizando el algoritmo de interpolación Nearest-neighbor. La parte mala es que puedo ver cómo funciona, pero no puedo encontrar el algoritmo en sí. Estaré agradecido por cualquier ayuda.Algoritmo de interpolación de vecino más cercano en MATLAB

Aquí es lo que traté de la imagen de entrada ampliación por un factor de 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 

Aquí está la salida después de la sugerencia Mark 's alt text

+0

Lo sentimos, no sé lo que estaba pensando - que necesita para repetir la salida, no se la entrada, ya que la salida es más grande. Y en ese caso mis fórmulas necesitarían ser revertidas. –

Respuesta

19

un tiempo me pasó por el código de la función imresize en el MATLAB Image Processing Toolbox para crear una versión simplificada de la interpolación de imágenes del vecino más cercano. Así es como se aplicaría a su 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,:); 

Otra opción sería utilizar el incorporado en interp2 función, aunque no se menciona que deseen utilizar las funciones incorporadas en uno de sus comentarios.

EDIT: EXPLICACIÓN

En caso de que a alguien le interesa, que pensé en explicar cómo la solución anterior funciona ...

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

En primer lugar, para obtener los nuevos tamaños de fila y columna los viejos tamaños de fila y columna se multiplican por el factor de escala. Este resultado se redondea al número entero más cercano con floor. Si el factor de escala es menor que 1 usted podría terminar con un caso raro de uno de los valores de tamaño que son 0, que es la razón por la llamada a max está ahí para reemplazar nada menos que 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)); 

A continuación, se calcula un nuevo conjunto de índices tanto para las filas como para las columnas. Primero, se calcula un conjunto de índices para la imagen muestreada: 1:newSize(...). Cada píxel de imagen se considera que tiene un ancho dado, de modo que el píxel 1 se extiende de 0 a 1, el píxel 2 se extiende de 1 a 2, etc. La "coordenada" del píxel se trata así como el centro, razón por la cual 0.5 se resta de los índices. Luego, estas coordenadas se dividen por el factor de escala para dar un conjunto de coordenadas de píxel-centro para la imagen original, que luego tienen 0.5 añadidas a ellas y se redondean para obtener un conjunto de índices enteros para la imagen original. La llamada al min garantiza que ninguno de estos índices sea más grande que el tamaño de la imagen original oldSize(...).

outputImage = inputImage(rowIndex,colIndex,:); 

Finalmente, la nueva imagen muestreada se crea simplemente indexando en la imagen original.

+0

funciona muy bien, gracias! – Hellnar

+0

@Hellnar: ¡Me alegra ayudar! También acabo de actualizar el código, por lo que debería funcionar para factores de escala no enteros, así como para escala de grises o imágenes RGB. – gnovice

0

Sólo se necesita una fórmula más general para el cálculo de xloc y yloc.

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

Esto supone que sus variables tienen suficiente rango para los resultados de la multiplicación.

2

MATLAB ya lo hizo por usted. Utilice imresize:

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

o si desea escalar tanto x & y por igual,

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

Ya conozco la función de compilación, pero necesito lograr esto con mi propio código. gracias – Hellnar

+1

Lo siento, no lo sabía! Es bueno ver que encontraste tu respuesta. – Jacob

20

Esta respuesta es más explicativa que tratar de ser conciso y eficiente. Creo que la solución de gnovice es la mejor al respecto. En caso de que intente comprender cómo funciona, siga leyendo ...

Ahora el problema con su código es que está mapeando ubicaciones desde la imagen de entrada a la imagen de salida, razón por la cual está obteniendo el irregular salida. Consideremos un ejemplo donde la imagen de entrada es todo blanco y negro de salida inicializado a, obtenemos lo siguiente:

screenshot

Lo que usted debe hacer es lo contrario (de salida a entrada). Como ejemplo, consideremos la siguiente notación:

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] 

La idea es que para cada lugar (i,j) la imagen de salida, queremos hacer un mapa de la ubicación "más cercano" en las coordenadas de imagen de entrada. Dado que este es un mapeo sencillo que usamos la fórmula que se asigna un determinado x a y (dados todos los otros parametros):

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

en nuestro caso, x es el i/j coordenada y y es el ii/jj coordinar. Por lo tanto, la sustitución para cada uno nos da:

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

poner las piezas juntas, obtenemos el siguiente código:

% 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 solución de gnovice es aproximadamente 10 veces más rápida. Sin embargo, gracias por la explicación! – Wok

+0

Cuando una imagen I se escala usando el vecino más cercano a Izoom, y luego Izoom se reduce por el mismo factor, recuperamos la imagen original I. Ahora, intuitivamente, entiendo que, dado que estamos haciendo solo la replicación de píxeles y ningún promedio, esto es bastante natural, pero no puedo encontrar una prueba más rigurosa. Esperaba que alguien aquí pudiera darme algunos consejos con respecto a esto. – idexi

Cuestiones relacionadas