20

Я пытаюсь написать свою собственную функцию для увеличения входного изображения с помощью алгоритма интерполяции ближайшего соседа. Плохая часть - я могу видеть, как она работает, но не может найти сам алгоритм. Буду благодарен за любую помощь.Алгоритм интерполяции ближайших соседей в MATLAB

Вот что я пытался для расширения входного изображения с коэффициентом 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 

Вот результат после того, как предложение Mark «S alt text

+0

К сожалению, не знаю, что я имел в виду - вам нужно пройти по выходу, не вход, поскольку выход больше. И в этом случае мои формулы должны быть отменены. –

ответ

19

Некоторое время назад я прошел через код функции imresize в MATLAB Image Processing Toolbox создать упрощенную версию для только ближайшая соседняя интерполяция изображений. Вот как это будет применяться к вашей проблеме:

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

Другим вариантом было бы использовать встроенный в interp2 функции, хотя вы упомянули, не желая использовать встроенные функции в одном из ваших комментариев.

EDIT: ОБЪЯСНЕНИЕ

В случае, если кто-то интересно, я думал, что объяснить, как выше работает решение ...

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

Во-первых, чтобы получить новые строки и столбца размеров размеры старых строк и столбцов умножаются на коэффициент масштабирования. Этот результат округляется до ближайшего целого числа с floor. Если масштабный коэффициент меньше 1 вы могли бы в конечном итоге с странным случаем одно из значений размера равно 0, поэтому вызов max находится там, чтобы заменить что-либо меньшее, чем 1 с 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)); 

Затем вычисляется новый набор индексов для строк и столбцов. Сначала вычисляется набор индексов для изображения с повышенной дискретизацией: 1:newSize(...). Каждый пиксель изображения считается имеющим заданную ширину, так что пиксель 1 охватывает от 0 до 1, пиксель 2 охватывает от 1 до 2 и т. Д. Таким образом, «координата» пикселя обрабатывается как центр, поэтому 0,5 вычитается из индексов. Затем эти координаты делятся на коэффициент масштабирования, чтобы получить набор координат пиксельных центров для исходного изображения, которые затем добавляются к ним 0,5 и округляются, чтобы получить набор целочисленных индексов для исходного изображения. Вызов min гарантирует, что ни один из этих индексов не будет больше исходного размера изображения oldSize(...).

outputImage = inputImage(rowIndex,colIndex,:); 

И, наконец, новое изображение с улучшенной дискретизацией создается путем простого индексирования в исходное изображение.

+0

отлично работает, спасибо! – Hellnar

+0

@ Хеллнар: Рад помочь! Я также просто обновил код, поэтому он должен работать для нецелочисленных масштабных коэффициентов, а также для изображений в оттенках серого или RGB. – gnovice

0

Вам просто нужно более обобщенную формулу для расчета xloc и yloc.

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

Это предполагает, что ваши переменные имеют достаточный диапазон для результатов умножения.

2

MATLAB уже сделал это за вас. Используйте imresize:

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

или если вы хотите масштабировать как х & у одинаково,

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

Я уже знаю встроенную функцию, но мне нужно добиться этого с помощью собственного кода. спасибо – Hellnar

+1

Извините, не знал! Рад видеть, что вы нашли свой ответ. – Jacob

20

Этот ответ более пояснительный, чем попытка быть кратким и эффективным. Я думаю, что решение gnovice является лучшим в этом отношении. Если вы пытаетесь понять, как это работает, продолжайте читать ...

Теперь проблема с вашим кодом заключается в том, что вы сопоставляете местоположения с входным изображением на выходное изображение, поэтому вы получаете пятно мощность. Рассмотрим пример, когда входное изображение является полностью белый и выход инициализируется черный, мы получаем следующее:

screenshot

То, что вы должны делать обратное (от выхода к входу). В качестве примера рассмотрим следующие обозначения:

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] 

Идея заключается в том, что для каждого места (i,j) в выходном изображении, мы хотим, чтобы отобразить его в «ближайшее» место в координатах входного изображения. Поскольку это простое отображение мы используем формулу, которая отображает данную x к y (учитывая все другие Params):

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

в нашем случае, x является i/j координат и y является ii/jj координат. Поэтому подставляя каждый дает нам:

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

Ввод куски вместе, мы получаем следующий код:

% 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

Решение gnovice примерно в 10 раз быстрее. Однако, спасибо за объяснение! – Wok

+0

Когда изображение I масштабируется с использованием ближайшего соседа к Izoom, а затем Izoom сокращается на тот же коэффициент, мы возвращаем исходное изображение I. Теперь, интуитивно, я понимаю, что, поскольку мы делаем только репликацию пикселей, а не какое-либо усреднение, это вполне естественно, но я не могу найти более строгого доказательства. Я надеялся, что кто-то здесь может дать мне несколько указаний относительно этого. – idexi