Algorithme D'interpolation du plus proche voisin dans MATLAB

j'essaie d'écrire ma propre fonction pour mettre à l'échelle une image d'entrée en utilisant l'algorithme d'interpolation du plus proche voisin. La mauvaise partie est que je suis capable de voir comment cela fonctionne, mais impossible de trouver l'algorithme lui-même. Je serai reconnaissant pour toute aide.

voici ce que j'ai essayé pour augmenter l'image d'entrée par un facteur 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

Voici la sortie après marque 's suggestion alt text

20
demandé sur Community 2009-10-11 18:53:56

4 réponses

il y a quelque temps, j'ai parcouru le code de la fonction imresize dans la fonction MATLAB Image Processing Toolbox pour créer une version simplifiée pour l'interpolation des images par le plus proche voisin. Voici comment il serait appliqué à votre problème:

%# 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,:);

une autre option serait d'utiliser la fonction intégrée interp2 , bien que vous ayez mentionné ne pas vouloir utiliser la fonction intégrée fonctions de dans un de vos commentaires.

EDIT: EXPLICATION

au cas où quelqu'un serait intéressé, j'ai pensé vous expliquer comment la solution ci-dessus fonctionne...

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

tout d'abord, pour obtenir les nouvelles dimensions des rangées et des colonnes, les anciennes dimensions des rangées et des colonnes sont multipliées par le facteur d'échelle. Ce résultat est arrondi à l'entier le plus proche avec floor . Si le facteur d'échelle est moins de 1 vous pourriez finir avec un cas bizarre d'une des valeurs de taille étant 0, c'est pourquoi l'appel à max est là pour remplacer tout ce qui est moins de 1 par 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));

Ensuite, un nouvel ensemble d'indices est calculée pour les lignes et les colonnes. Tout d'abord, un ensemble d'indices pour l'image échantillonnée est calculé: 1:newSize(...) . Chaque pixel d'image est considéré comme ayant une largeur donnée, de sorte que le pixel 1 s'étend de 0 à 1, le pixel 2 s'étend de 1 à 2, etc.. Les "coordonnées" du pixel est donc traitée comme le centre, qui est pourquoi 0.5 est soustrait les indices. Ces coordonnées sont ensuite divisées par le facteur d'échelle pour donner un ensemble de coordonnées pixel-Centre pour l'image originale, qui ont alors 0.5 ajouté à eux et sont arrondis pour obtenir un ensemble d'indices entiers pour l'image originale. L'appel à min garantit qu'aucun de ces indices n'est plus grand que la taille de l'image originale oldSize(...) .

outputImage = inputImage(rowIndex,colIndex,:);

enfin, la nouvelle image upsampled est créée par simple indexation dans l'image originale.

19
répondu gnovice 2017-02-27 20:02:09

Cette réponse est plus explicatif que d'essayer d'être concis et efficace. Je pense que la solution de gnovice est la meilleure à cet égard. Au cas où vous essayez de comprendre comment cela fonctionne, continuez à lire...

maintenant le problème avec votre code est que vous êtes la cartographie des emplacements de l'image d'entrée à l'image de sortie, qui est pourquoi vous obtenez le spotty sortie. Prenons un exemple où l'image d'entrée est entièrement blanche. et sortie initialisée à noir, nous obtenons ce qui suit:

screenshot

ce que vous devriez faire est le contraire (de la sortie à l'entrée). À titre d'exemple, prenons la note suivante:

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'idée est que pour chaque emplacement (i,j) dans l'image de sortie, nous voulons l'associer à l'emplacement" le plus proche " dans les coordonnées de l'image d'entrée. Puisque c'est une simple cartographie, nous utilisons la formule qui correspond à un x donné à y (compte tenu de tous les autres paramètres):

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

dans notre cas, x est la coordonnée i / j et y est la coordonnée ii / jj . C'est pourquoi substituer à chacun nous donne:

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

en assemblant les morceaux, on obtient le code suivant:

% 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)
20
répondu Amro 2017-05-23 12:10:25

MATLAB l'a déjà fait pour vous. Use imresize :

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

ou si vous souhaitez mettre à l'échelle à la fois x et y de même,

output = imresize(input,2,'nearest');
2
répondu Jacob 2009-10-11 15:11:13

vous avez juste besoin d'une formule plus généralisée pour calculer xloc et yloc.

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

cela suppose que vos variables ont assez de portée pour les résultats de multiplication.

0
répondu Mark Ransom 2009-10-11 15:01:04