image - 使用双线性插值调整图像大小而不使用 imresize

标签 image matlab image-processing interpolation

我找到了一些放大图像的方法,但没有缩小图像的解决方案。我目前正在使用最近邻法。在不使用 imresize 的情况下,我怎么能用双线性插值来做到这一点? MATLAB 中的函数?

最佳答案

在您的评论中,您提到您想使用双线性插值调整图像大小。请记住,双线性插值算法与大小无关。您可以很好地使用相同的算法来放大和缩小图像。对像素位置进行采样的正确比例因子取决于您指定的输出尺寸。此 没有 顺便改一下核心算法。
在我开始任何代码之前,我将向您推荐 Richard Alan Peters' II digital image processing slides on interpolation ,特别是幻灯片 #59。它有一个很好的说明以及关于如何进行 MATLAB 友好的双线性插值的伪代码。为了自成一体,我将在此处包含他的幻灯片,以便我们可以继续进行并对其进行编码:
enter image description here
请注意,这只会重新采样图像。如果你真的想匹配MATLAB的输出,你需要禁用抗锯齿 .
MATLAB by default will perform anti-aliasing以确保输出在视觉上令人愉悦。如果您想将苹果与苹果进行比较,请确保在将此实现与 MATLAB 的 imresize 进行比较时禁用抗锯齿功能。功能。
让我们编写一个函数来为我们做这件事。此函数将接收一个图像(通过 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 很容易解释。你所做的只是指定一个 (x,y) 的二维网格坐标,图像中的每个位置都有一对 (x,y)或列和行坐标。通过 meshgrid 创建网格避免任何 for循环,因为我们将在继续之前从我们需要的算法中生成所有正确的像素位置。
如何 sub2ind 有效的是它接受二维矩阵中的行和列位置(嗯......它真的可以是 任何 你想要的维度),并输出一个 单例线性指数。如果您不知道 MATLAB 如何索引到矩阵中,有两种方法可以访问矩阵中的元素。您可以使用行和列来获取您想要的内容,或者您​​可以使用 专栏指数。看看我下面的这个矩阵示例:
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+1c+1 .请注意,所有这些都是 二维数组 ,其中所有这些数组中每个匹配位置中的每个元素告诉我们需要从中采样的四个像素,以生成最终输出像素。 sub2ind的输出将 还有是与输出图像大小相同的二维数组。这里的关键是 r 的二维数组的每个元素, c , r+1 , 和 c+1会给我们 专栏索引到我们想要访问的图像中,并通过将其作为输入扔到图像中进行索引,我们将准确地获得我们想要的像素位置。

在实现算法时,我想添加一些重要的细节:
  • 您需要确保在图像外部进行插值时访问图像的任何索引都设置为 1 或行数或列数,以确保不会越界。实际上,如果您扩展到图像的右侧或下方,则需要将其设置为一个 下面 最大值作为插值要求您访问像素的右侧或下方。这将确保您仍在范围内。
  • 您还需要确保将输出图像转换为与输入图像相同的类。
  • 我跑过一个 for循环以自行插入每个 channel 。您可以使用 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

    我在实践中注意到的一件事是,与双三次等其他方案相比,双线性上采样具有不错的性能......甚至 Lanczos .但是,当您缩小图像时,因为您正在删除细节,所以最近邻就足够了。我发现双线性或双三次是矫枉过正的。我不确定您的应用程序是什么,但可以尝试使用不同的插值算法,看看您喜欢什么结果。双三次是另一个故事,我将把它留给你作为练习。如果您感兴趣,我向您推荐的那些幻灯片确实有关于双三次插值的 Material 。

    祝你好运!

    关于image - 使用双线性插值调整图像大小而不使用 imresize,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26142288/

    相关文章:

    实现高阶分形的算法

    c - 在 Matlab 中编译 mex 文件时找不到标准 C 库

    android - 获得的位图是透明的,但是当设置为 ImageView 时变得不透明

    python - 使用opencv写入后,图像中的标题信息丢失

    html - 缩放具有不同高度的 .svg 图像以获得相同的宽度

    node.js - Angular 2+ 如何在 Angular 构建后动态添加图像

    jquery - 将变量从我的点击事件传递给函数

    objective-c - 如何使用 coretext 在标签文本上设置图像

    matlab - 时间序列聚合效率

    python - PNG、GIF 等的 Tensorflow Label_Image