Algoritmo de interpolación de vecino más cercano en MATLAB

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.

Esto es lo que intenté para ampliar la imagen de entrada 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á el resultado después de la sugerencia de Mark texto alternativo

Hace un tiempo imresize el código de la función de imresize en la Caja de herramientas de procesamiento de imágenes de MATLAB para crear una versión simplificada para 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 usar la función interp2 incorporada, aunque mencionaste que no deseas utilizar las funciones incorporadas en uno de tus comentarios.

EDITAR: EXPLICACIÓN

En caso de que alguien esté interesado, pensé en explicar cómo funciona la solución anterior …

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

Primero, para obtener los nuevos tamaños de fila y columna, los tamaños de fila y columna antiguos se multiplican por el factor de escala. Este resultado se redondea al entero más cercano con floor . Si el factor de escala es menor que 1, puede terminar con un caso raro de que uno de los valores de tamaño sea 0, por lo que la llamada a max está ahí para reemplazar cualquier cosa menor que 1 por 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 a min asegura que ninguno de estos índices sea más grande que el tamaño de imagen original oldSize(...) .

 outputImage = inputImage(rowIndex,colIndex,:); 

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

Esta respuesta es más explicativa que tratar de ser conciso y eficiente. Creo que la solución de Gnovice es la mejor en ese sentido. En caso de que intentes entender cómo funciona, sigue leyendo …

Ahora el problema con su código es que está mapeando las ubicaciones de la imagen de entrada a la imagen de salida, que es la razón por la que está obteniendo resultados irregulares . Considere un ejemplo donde la imagen de entrada es toda blanca y la salida inicializada en negro, obtenemos lo siguiente:

captura de pantalla

Lo que debería hacer es lo opuesto (de salida a entrada). Para ilustrar, considere 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 ubicación (i,j) en la imagen de salida, queremos asignarlo a la ubicación "más cercana" en las coordenadas de la imagen de entrada. Como se trata de un mapeo simple, usamos la fórmula que mapea una x dada a y (dados todos los otros parámetros):

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

en nuestro caso, x es la coordenada i / j e y es la coordenada ii / jj . Por lo tanto, sustituyendo cada uno nos da:

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

Juntando piezas, 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) 

MATLAB ya lo hizo por ti. Use imresize :

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

o si quieres escalar tanto xey como por igual,

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

Solo necesita una fórmula más general para calcular 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.