使用双线性插值调整图像的大小,而不是imresize

我发现了一些放大图像的方法,但没有办法缩小图像。 我目前正在使用最近邻的方法。 我怎样才能做到这一点与双线性插值,而不使用MATLAB中的imresize函数?

在你的评论中,你提到你想用双线性插值来调整图像的大小。 请记住,双线性插值algorithm与尺寸无关。 您可以很好地使用相同的algorithm来放大图像以及缩小图像。 采样像素位置的正确比例因子取决于您指定的输出尺寸。 这不会改变核心algorithm。

在我开始使用任何代码之前,我会把你推荐给理查德·艾伦·彼得斯(Richard Alan Peters)的II插值数字image processing幻灯片 ,特别是幻灯片#59。 对于如何进行MATLAB友好的双线性插值,它有很好的说明和伪代码。 为了自成一体,我将在这里包括他的幻灯片,以便我们可以跟随并编码:

在这里输入图像描述

我们来写一个函数来为我们做这个。 这个函数将获取一个图像(通过imreadimread ),可以是彩色或灰度图像,也可以是一个由两个元素组成的数组: – 要调整图像的大小,以及两个元素数组中的输出大小最终resize的图像你想要的。 这个数组的第一个元素是行,这个数组的第二个元素是列。 我们将简单地通过这个algorithm,并使用这个伪代码计算输出像素颜色/灰度值:

 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的文件中并保存。 确保你改变了你保存这个文件的工作目录。


除了sub2indmeshgrid ,一切似乎都与algorithm一致。 meshgrid很容易解释。 你所做的只是指定一个(x,y)坐标的二维网格,其中图像中的每个位置都有一对(x,y)或列和行坐标。 通过meshgrid创build一个网格避免了任何for循环,因为我们将在继续之前从algorithm中生成所有正确的像素位置。

sub2ind是如何工作的,它在一个二维matrix中取得一个行和一列的位置(好吧,它可以是任意数量的维度),并输出一个单一的线性索引。 如果您不知道MATLAB如何将matrix索引到matrix中,则有两种方法可以访问matrix中的元素。 你可以使用行和列来得到你想要的,或者你可以使用列主要索引。 看看下面这个matrix例子:

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

如果我们想访问数字9,我们可以做A(2,4)这是大多数人倾向于默认的。 还有另外一种方法可以用一个单一的号码访问数字9,这就是A(11) …现在情况怎么样? MATLAB列出主要格式的matrix内存。 这意味着如果你要采用这个matrix并把它的所有一起堆放在一个数组中,它看起来像这样:

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

现在,如果要访问元素编号9,则需要访问此数组的第11个元素。 回到插值位,如果你想vector化访问图像中的元素来进行插值而不做任何for循环, sub2ind是至关重要的。 因此,如果您查看伪代码的最后一行,我们要访问rcr+1c+1元素。 请注意,所有这些都是二维数组 ,其中所有这些数组中的每个匹配位置中的每个元素都告诉我们需要从中抽样的四个像素,以便生成最终的输出像素。 sub2ind的输出将是与输出图像大小相同的二维数组。 这里的关键是, rcr+1c+1的二维数组中的每个元素都会给我们列出想要访问的图像的列主索引,并将其作为input投影到图像中对于索引,我们将精确地获取我们想要的像素位置。


在实现algorithm时,我想添加一些重要的细节:

  1. 您需要确保在插入图像外部时访问图像的索引要么设置为1,要么确保行数或列数不超出边界。 实际上,如果扩展到图像的右下方,则需要将其设置为低于最大值,因为插值要求您正在访问像素的右侧或下侧。 这将确保你仍然在界限内。

  2. 您还需要确保将输出图像转换为与input图像相同的类别。

  3. 我跑了一个for循环来自己插入每个通道。 您可以使用bsxfun智能地做到这bsxfun ,但为了简单起见,我决定使用for循环,以便您能够跟随algorithm。


作为一个例子来说明这个工作,让我们使用MATLAB的系统path的一部分onion.png图像。 这张图片的原始尺寸是135 x 198 。 让我们把这个图像加大来插入,这个图像的大小是原始图像大小的两倍: 270 x 396

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

上面的代码将通过增加每个维度两倍来插入图像,然后用原始图像和另一个图像与放大的图像一起显示graphics。 这是我得到的两个:

在这里输入图像描述

在这里输入图像描述


同样,让我们​​缩小一半的图像:

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

请注意,行的一半是67.5,但我四舍五入到68.这就是我得到的:

在这里输入图像描述

在这里输入图像描述


在实践中我注意到的一件事情是,与双三次…甚至Lanczos等其他scheme相比,使用双线性上采样具有不俗的performance。 然而,当你缩小图像时,因为你正在删除细节,所以最近的邻居就足够了。 我发现双线性或双三次是过度的。 我不确定你的应用程序是什么,但玩弄不同的插值algorithm,看看你喜欢的结果。 Bicubic是另外一个故事,我会把它作为一个练习。 如果您有兴趣,那么我介绍给您的那些幻灯片确实有关于双三次插值的材料。


祝你好运!