[MATLAB] 图像的插值算法3:双线性插值

MATLAB图像插值算法文章集:

  1. 插值函数及其原理 https://blog.csdn.net/Effend/article/details/82870144
  2. 最近邻插值 https://blog.csdn.net/Effend/article/details/82897898
  3. 双线性插值 https://blog.csdn.net/Effend/article/details/82996871
  4. 双三次插值 (待完成)https://blog.csdn.net/Effend/article/details/82996899

1. 概要

双线性插值中最主要的算法思想有两点:第一是双,指的是在两个方向上(x,y)取值,一般在x方向上取两个值,在y方向上取两个值;第二是线性,将各方向取的两个值做线性函数的计算,一般以x和y方向上的权重计算实际值,类似于一次函数,越靠近映射点权重越高,并且让整体权重和=1。
根据上述的算法思想,通过映射点周围的4个点来进行计算,使得新像素点的颜色能具有不同于最近邻插值算法的简单颜色变化。由此使得图像插值算法得到一定改进。
然而,双线性插值算法仍然具有其短板,简单线性变化会带来边缘模糊化,在颜色变化程度大的边缘处,会明显发现插值的数据在边缘显得不符。另外由于增加了线性权重与像素值相乘,会存在一定的低通滤波性,高频分量会被削弱,在颜色变化程度大的地方可能无法得到正确的像素值。

2. 算法代码

根据概要中的原理,设计出以下代码。

代码原理:

原理图
原理按上图,其中(i,j)为新图像像素点对应原图像的实际像素点位置,为了便于理解,实际像素点位置坐标是包含小数点的,而小数值即是它的方向权重,u为水平方向上权重即i-x,v为垂直方向上权重即j-y。
则实际像素点处的线性值即为:
u*v*img(x,y)+(1-u)*v*img(x+1,y)+u*(1-v)*img(x,y+1)+(1-u)*(1-v)*img(x+1,y+1)
其中的权重和,uv+u(1-v)+v(1-u)+(1-u)(1-v)=1,该权重和能保证图像非插入颜色不会出现偏差,但对高频分量会有削弱的效果。

算法步骤:
(1)用户输入图像、放大率;
(2)根据放大率创建新图像;
(3)得到映射点及方向权重;
(4)根据权重进行计算获得新图像像素值;
(5)显示原图像和新图像。

算法代码:

% 双线性插值
% 输入图像文件及放大率
% 输出根据放大率变化后的新图像
function bilinear_interpolation = bilinear_interpolation(filename,R)

% 初始化,读入图像,图像数据为m*n*color
img = imread(filename);

% 变化后图像
[row,col,color] = size(img);    % 获得图像的行列数及色板数
row = round(row*R);     % 新图像行
col = round(col*R);     % 新图像列

% 新图像初始化
% 使用class获得原图像的数据类型,使得新图像数据类型与原图像保持一致
img_new = zeros(row,col,color,class(img));

% 对新图像的行、列、色板赋值
for i = 1:row
    for j = 1:col
        for n = 1:color
            x = round(i/R);
            y = round(j/R);
            if x == 0
                x = x+1;
            end
            if y ==0
                y = y+1;
            end
            u = i/R-floor(i/R); %求取水平方向上的权重
            v = j/R-floor(j/R); %求取垂直方向上的权重
            % 此处需要对图像边缘进行例外处理
            % 本例对图像右边缘及下边缘用最近邻插值计算
            if i >= row-R || j >= col-R
                img_new(i,j,n) = img(x,y,n);
            else
                img_new(i,j,n) = u*v*img(x,y,n)+(1-u)*v*img(x+1,y,n)+u*(1-v)*img(x,y+1,n)+(1-u)*(1-v)*img(x+1,y+1,n);
            end
        end
    end
end

% 显示原图像
figure;
imshow(img);
title("Original Image");

% 显示新图像
figure;
imshow(img_new);
title("New Image");

3. 算法分析

在双线性插值算法中,重要的点在于确定计算区域和权重,然后将像素值通过权重计算赋值给新图像。详细分析如下:
(1)从实际算法可以看出,其中对新图像右边缘和下边缘两处无法使用该算法原理的地方直接进行最近邻插值处理,该处理避免计算错误且不会破坏新图像整体,这样的边缘处理在双线性插值算法中是要考虑的;
(2)在算法中,使用了floor这个函数,此函数用于得到i/R和j/R的整数部分,再用原值相减即可得到小数点部分,即权重值;
(3)除了计算算法以外其它部分的内容与最近邻插值相同。
(4)该算法是否可优化呢?可以,在本例中使用的是简单线性方程来计算新像素值的,而对于特殊图像如满足某个函数方程的图像,就可选择用其他函数关系来计算,以此来进行代码优化。

4. 测试环境

选取的测试图像与最近邻插值相同,用2幅.jpg图像文件进行测试,分别观察放大率>1和<1的情况,文件分别为img.jpg和img1.jpg,具体图像如下:
img.jpg 图像大小720*720
img.jpg
img1.jpg 图像大小350*350
img1.jpg

5. 测试效果

(1)用img.jpg运行函数,设定放大率R=0.8,即缩小原图像。
结果为:
img_test
可以发现,图像的缩小符合预期,图像清晰,没有颜色错误。
放大图像某个部分观察像素点:
img_test
在划出的最上的红框区域中,可以发现锯齿化程度相比最近邻插值降低了不少,但在颜色边缘部分仍然会受到算法的限制导致少许锯齿化。
在划出的中间的红框区域中,可以明显发现原图像中,白色部分颜色由于低通滤波性被削弱,区域白色亮度不够。
在划出的下面的红框区域中,可以发现在变化程度大的颜色区块上,颜色会出现错误。
但整体而言,相比较最近邻插值,图像精细程度有了很好的提高,算法更优。

(2)用img1.jpg运行函数,设定放大率R=1.5,即放大原图像。
结果为:
img1_test
从图像可以看出,双线性插值算法得到的新图像比最近邻插值得到的图像颜色平滑度更好,且锯齿化程度也有少许改善。但锯齿化仍然较为明显。
放大图像某个部分观察像素点:
img1_test
放大观察像素点可以发现很有趣的事情那就是新图像中出现了像网格的颜色区域,仔细观察可以发现每个网格区域中的颜色都不同,显示出了明显的颜色变化,这表明算法的功能完成地非常好,线性颜色提供了更好的颜色平滑度。
但由于算法仅仅计算了4个点,因此在放大图像的操作中出现类似网格的区域且颜色存在线性关系,图像的边缘被模糊化,高频分量被削弱。
即便有些许缺陷,但相比较最近邻插值,双线性插值算法更有优势,简单解决了最近邻插值的颜色变化问题。

6. 总结

双线性插值算法的优势更加明显,相较于最近邻插值有效降低了锯齿程度,图像精细程度更高,虽然计算的时间和复杂程度比最近邻插值更高,但在目前的计算力下,双线性插值算法仍然是被最多选择的算法。

–注:本文为原创,未经允许,禁止转载!–

你可能感兴趣的:(MATLAB)