欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

图像插值-双三次插值(bicubic)

程序员文章站 2022-05-30 13:22:46
...

双三次插值
本文将未做插值的原始图像称作源图像,源图像插值缩放K倍后的图像称作目标图像。
以下标识符的意义:
图像插值-双三次插值(bicubic)

  1. 算法
    如下图,双三次插值就是通过对周边16个点(A,B,C,…N,O,P)进行加权计算得到目标像素点的值,图像插值-双三次插值(bicubic)
    (dstX/K,dstY/K)归一化后为(dstX/K,dstY/K),可推得:
    srcX=floor(dstX/K);
    srcY=floor(dstY/K);
    u=dstX/K-srcX;
    v=dstY/K-srcY;

    这样,就能得到16个点的位置。
    加权系数的计算方法有很多种,我采用基于BiCubic基函数的方法,该函数形式如下:
    图像插值-双三次插值(bicubic)
    其中,x,y为周围16个源像素点到(dstX/K,dstY/K)的行列方向的距离,
    那么,目标像素点的值应为:
    图像插值-双三次插值(bicubic)
  2. 实现
    本程序是matlab写的一个my_bicubic函数,与matlab自有的imresize的bicubic型函数相对应。可以实现任意倍数的放大。
    matlab代码:
function [output]=my_bicubic(src,K)
%
%输入:源图像src,放大倍数K
%输出:目标图像矩阵dst
 
[srcM,srcN,srcC]=size(src);%源图像元素点的行列数及色板数
dstM=round(K*srcM);%该处仍要确保当放大倍数K非整数时目标图像大小为整数
dstN=round(K*srcN);
 
%使用class将数据类型统一,目标图像初始化
dst=ones(dstM,dstN,srcC,class(src));
 
%逐像素点赋值
for dstX=1:dstM
    for dstY=1:dstN
            X=dstX/K;
            Y=dstY/K;
            if X<2||X>srcN-2||Y<2||Y>srcM-2 %在边界采用最近邻插值
                for dstC=1:srcC
            srcX=round(dstX/K);
            srcY=round(dstY/K);
            srcX(srcX>srcN)=srcN; %防止索引源图像界外位置,该函数很耗时但简洁
            srcX(srcX<1)=1;
            srcY(srcY>srcM)=srcM ;
            srcY(srcY<1)=1;
            dst(dstX,dstY,dstC)=src(srcX,srcY,dstC);
                end
            else            %非边界位置采用双三次插值
                srcX=floor(X);%最近邻左上方像素点位置
                srcY=floor(Y);
                v=X-srcX;
                u=Y-srcY;
                X1=zeros(4,4);  X2=zeros(4,4);  %距离矩阵
                W1=ones(4,4); W2=ones(4,4);    %系数矩阵
                for i=1:4
                    for j=1:4
                        X1(i,j)=abs(v-i+2);
                        X2(i,j)=abs(u-j+2);
                        if X1(i,j)<=1
                            W1(i,j)=1.5*(X1(i,j))^3-2.5*(X1(i,j))^2+1;
                        else
                            if  X1(i,j)<2
                                W1(i,j)=(-0.5)*(X1(i,j))^3+2.5*(X1(i,j))^2-4*X1(i,j)+2;
                            else
                                W1(i,j)=0;
                            end
                        end
                        if X2(i,j)<=1
                            W2(i,j)=1.5*(X2(i,j))^3-2.5*(X2(i,j))^2+1;
                        else
                            if  X2(i,j)<2
                                W2(i,j)=(-0.5)*(X2(i,j))^3+2.5*(X2(i,j))^2-4*X2(i,j)+2;
                            else
                                W2(i,j)=0;
                            end
                        end
                    end
                end
                W=W1.*W2;
                Z=ones(4,4);  %16个源像素点矩阵
                O=ones(4,4);  %16个加权后的源像素点矩阵
                for dstC=1:srcC
                    for i=1:4
                        for j=1:4
                            Z(i,j)=src(srcX-1+i-1,srcY-1+j-1,dstC);
                            O(i,j)=W(i,j).*Z(i,j);
                        end
                    end
                    O1=sum(sum(O));
                    dst(dstX,dstY,dstC)=O1;
                end
            end
    end
end
output=dst;
end

  1. 评估
    分别使用本文函数my_bicubic函数和matlab的imresize函数中的bicubic型对lena图进行2倍放大,并计时。

    test代码:

close all
figure
A=imread('D:\Files\Downloads\DIP\picture\Lena.jpg');
imshow(A);
figure
tic
imshow(my_bicubic(A,2));
toc
figure
tic
imshow(imresize(A,2,'bicubic'));
toc

结果:
图像插值-双三次插值(bicubic)
右下角边界细节:
图像插值-双三次插值(bicubic)
由于该算法在边界邻域会越界,所以我采用最近邻法来补充边界,matlab的imresize函数处理得完美,还不知道它是如何处理的,知道了我就更新。

耗时:
图像插值-双三次插值(bicubic)
综上,处理效果越来越好,但耗时也越来越长。
附:
最近邻插值
双线性插值