Подтвердить что ты не робот

Изменение размера изображения с билинейной интерполяцией без увеличения

Я нашел несколько методов для увеличения изображения, но нет решения для сжатия изображения. В настоящее время я использую метод ближайшего соседа. Как я могу это сделать с билинейной интерполяцией без использования функции imresize в MATLAB?

4b9b3361

Ответ 1

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

Прежде чем я начну с любого кода, я передам вам слайды обработки цифровых изображений Ричарда Алана Петерса II при интерполяции, в частности слайд # 59. Он имеет большую иллюстрацию, а также псевдокод о том, как сделать билинейную интерполяцию, дружественную MATLAB. Чтобы быть автономным, я собираюсь включить его слайд здесь, чтобы мы могли следовать и кодировать его:

enter image description here

Пусть напишет функцию, которая сделает это для нас. Эта функция примет изображение (которое читается через imread), который может быть как цветным, так и полутоновым, а также массив два элемента - изображение, которое вы хотите изменить, и размеры вывода в двухэлементном массиве конечного размера изображения, которое вы хотите. Первым элементом этого массива будут строки, а вторым элементом этого массива будут столбцы. Мы просто рассмотрим этот алгоритм и вычислим значения пикселей/оттенков серого выходного пикселя, используя этот псевдокод:

function [out] = bilinearInterpolation(im, out_dims)

    %// Get some necessary variables first
    in_rows = size(im,1);
    in_cols = size(im,2);
    out_rows = out_dims(1);
    out_cols = out_dims(2);

    %// Let S_R = R / R'        
    S_R = in_rows / out_rows;
    %// Let S_C = C / C'
    S_C = in_cols / out_cols;

    %// Define grid of co-ordinates in our image
    %// Generate (x,y) pairs for each point in our image
    [cf, rf] = meshgrid(1 : out_cols, 1 : out_rows);

    %// Let r_f = r'*S_R for r = 1,...,R'
    %// Let c_f = c'*S_C for c = 1,...,C'
    rf = rf * S_R;
    cf = cf * S_C;

    %// Let r = floor(rf) and c = floor(cf)
    r = floor(rf);
    c = floor(cf);

    %// Any values out of range, cap
    r(r < 1) = 1;
    c(c < 1) = 1;
    r(r > in_rows - 1) = in_rows - 1;
    c(c > in_cols - 1) = in_cols - 1;

    %// Let delta_R = rf - r and delta_C = cf - c
    delta_R = rf - r;
    delta_C = cf - c;

    %// Final line of algorithm
    %// Get column major indices for each point we wish
    %// to access
    in1_ind = sub2ind([in_rows, in_cols], r, c);
    in2_ind = sub2ind([in_rows, in_cols], r+1,c);
    in3_ind = sub2ind([in_rows, in_cols], r, c+1);
    in4_ind = sub2ind([in_rows, in_cols], r+1, c+1);       

    %// Now interpolate
    %// Go through each channel for the case of colour
    %// Create output image that is the same class as input
    out = zeros(out_rows, out_cols, size(im, 3));
    out = cast(out, class(im));

    for idx = 1 : size(im, 3)
        chan = double(im(:,:,idx)); %// Get i'th channel
        %// Interpolate the channel
        tmp = chan(in1_ind).*(1 - delta_R).*(1 - delta_C) + ...
                       chan(in2_ind).*(delta_R).*(1 - delta_C) + ...
                       chan(in3_ind).*(1 - delta_R).*(delta_C) + ...
                       chan(in4_ind).*(delta_R).*(delta_C);
        out(:,:,idx) = cast(tmp, class(im));
    end

Возьмите вышеуказанный код, скопируйте его и вставьте в файл с именем bilinearInterpolation.m и сохраните его. Убедитесь, что вы изменили рабочий каталог, в котором вы сохранили этот файл.


За исключением sub2ind и, возможно, meshgrid, все, кажется, соответствует алгоритму. meshgrid очень легко объяснить. Все, что вы делаете, это определение 2D-сетки координат (x,y), где каждое место на вашем изображении имеет пару координат (x,y) или столбца и строки. Создание сетки через meshgrid исключает любые циклы for, поскольку мы будем генерировать все нужные пиксельные местоположения из алгоритма, который нам нужен, прежде чем мы продолжим.

Как sub2ind работает в том, что он занимает место в строке и столбце в 2D-матрице (ну... это действительно может быть любое количество измерений, которое вы хотите), и выводит линейный индекс одиночный. Если вы не знаете, как индексы MATLAB в матрицах, есть два способа доступа к элементу в матрице. Вы можете использовать строку и столбец, чтобы получить то, что хотите, или использовать индекс column-major. Взгляните на приведенный ниже пример матрицы:

A = 

1  2  3  4  5
6  7  8  9  10
11 12 13 14 15

Если мы хотим получить доступ к номеру 9, мы можем сделать A(2,4), к чему большинство людей склонны по умолчанию. Существует еще один способ доступа к номеру 9 с использованием единственного числа, которое A(11)... теперь, как это происходит? MATLAB выделяет память своих матриц в формате столбца. Это означает, что если вы должны были взять эту матрицу и собрать все ее столбцы вместе в одном массиве, это будет выглядеть так:

A = 

1
6
11
2
7
12
3
8
13
4
9
14
5
10
15

Теперь, если вы хотите получить доступ к элементу номер 9, вам нужно будет получить доступ к 11-му элементу этого массива. Возвращаясь к биту интерполяции, sub2ind имеет решающее значение, если вы хотите сделать так, чтобы вы выделили доступ к элементам вашего изображения, чтобы сделать интерполяцию, не делая никаких циклов for. Таким образом, если вы посмотрите на последнюю строку псевдокода, мы хотим получить доступ к элементам в r, c, r+1 и c+1. Обратите внимание, что все это 2D-массивы, где каждый элемент в каждом из совпадающих местоположений во всех этих массивах сообщает нам четыре пикселя, которые нам нужно отбирать, чтобы получить конечный выходной пиксель. Вывод sub2ind будет также представлять собой 2D-массивы того же размера, что и выходные изображения. Ключ здесь состоит в том, что каждый элемент 2D-массивов r, c, r+1 и c+1 даст нам индексы столбца в изображение, которое мы хотим доступ, и, выбрасывая это как ввод в изображение для индексации, мы точно получим нужные пиксельные местоположения.


Есть несколько важных тонкостей, которые я хотел бы добавить при реализации алгоритма:

  • Вам нужно убедиться, что любые индексы для доступа к изображению при интерполяции вне изображения либо установлены на 1, либо количество строк или столбцов, чтобы гарантировать, что вы не выходите за пределы. На самом деле, если вы переходите вправо или под изображением, вам нужно установить его на один ниже максимум, поскольку для интерполяции требуется, чтобы вы обращались к пикселам в один справа или внизу. Это гарантирует, что вы все еще находитесь в пределах.

  • Вам также необходимо убедиться, что выходное изображение выполнено в том же классе, что и входное изображение.

  • Я пробежал цикл for, чтобы интерполировать каждый канал самостоятельно. Вы могли бы сделать это разумно, используя bsxfun, но я решил использовать цикл for для простоты и так, чтобы вы могли следовать наряду с алгоритмом.


В качестве примера, чтобы показать это, позвольте использовать образ onion.png, который является частью пути системы MATLAB. Исходными размерами этого изображения являются 135 x 198. Позвольте интерполировать это изображение, сделав его более крупным, идя в 270 x 396, который в два раза больше размера исходного изображения:

im = imread('onion.png');
out = bilinearInterpolation(im, [270 396]);
figure;
imshow(im);
figure;
imshow(out);

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

enter image description here

enter image description here


Аналогично, уменьшите изображение до половины:

im = imread('onion.png');
out = bilinearInterpolation(im, [68 99]);
figure;
imshow(im);
figure;
imshow(out);

Обратите внимание, что половина из 135 составляет 67,5 для строк, но я округлен до 68. Это то, что я получаю:

enter image description here

enter image description here


Одна вещь, которую я заметил на практике, это то, что upsampling с билинейным имеет приличную производительность по сравнению с другими схемами, такими как бикубический... или даже Lanczos. Однако, когда вы уменьшаете изображение, потому что вы удаляете детали, ближайшего соседа очень много. Я считаю, что билинейный или бикубический быть излишним. Я не уверен, что такое ваше приложение, но поиграйте с различными алгоритмами интерполяции и посмотрите, что вам нравится в результатах. Бикубич - это еще одна история, и я оставлю это вам как упражнение. Эти слайды, на которые я ссылался, действительно имеют материал о бикубической интерполяции, если вы заинтересованы.


Удачи!