数字图像缩放之最近邻插值与双线性插值处理效果对比

基本原理

1、最近邻插值:变换后的目标图像某点像素值等于源图像中与变换前相应点最近的点的像素值。具体操作为,设水平方向和垂直方向缩放的比例分别为w和h,那么目标图像中的点des(x,y)对应的源图像中的点src的坐标为(x0,y0)=(x/w,y/h)。其中,x0,y0可能为小数,故对其四舍五入,即(x0,y0)=int(x0+0.5,y0+0.5),因此点des(x,y)的像素值就是点src(x0,y0)的像素值。

2、双线性插值:由1中最近邻插值中的四舍五入前的点src(x0,y0)得到它的2*2区域4个邻域像素点的坐标,即(x1,y1)=(int(x0),int(y0))(x1,y2)=int(x1,y1+1),(x2,y1)=(x1+1,y1),(x2,y2)=(x1+1,y1+1),然后计算权重q1=(x0-x1)*(y0-y1),q2=(1.0-(x0-x1))*(y0-y1),q4=(x0-x1)*(1.0-(y0-y1)),q3=(1.0-(x0-x1))*(1.0-(y0-y1),用value(x,y)表示点(x,y)处的像素值,则目标图像中的点des(x,y)对应像素值value(x,y)=value(x2,y2)*q1+value(x1,y2)*q2+value(x1,y1)*q3+value(x2,y1)*q4,


c/c++实现及处理效果:

void GeometryTrans::Zoom(float ratioX, float ratioY)
{
     
    //释放旧的输出图像缓冲区
    if(m_pImgDataOut!=NULL){
        delete []m_pImgDataOut;
        m_pImgDataOut=NULL;
    }
     
    //输出图像的宽和高
    m_imgWidthOut=int(m_imgWidth*ratioX+0.5) ;
    m_imgHeightOut=int(m_imgHeight*ratioY+0.5); 
 
    //输入图像每行像素字节数
    int lineByteIn=(m_imgWidth*m_nBitCount/8+3)/4*4;
     
    //输出图像每行像素字节数
    int lineByteOut=(m_imgWidthOut*m_nBitCount/8+3)/4*4;
 
    //申请缓冲区,存放输出结果
    m_pImgDataOut=new unsigned char[lineByteOut*m_imgHeightOut];
 
    //每像素字节数,输入图像与输出图像相同
    int pixelByte=m_nBitCount/8;
     
    //输出图像在输入图像中待插值的位置坐标
    int coordinateX, coordinateY;
     
    //循环变量,输出图像的坐标
    int i, j;
     
    //循环变量,像素的每个通道
    int k;
     
    //近邻插值
    for(i=0; i< m_imgHeightOut; i++){
        for(j=0; j<m_imgWidthOut; j++){  
            //输出图像坐标为(j,i)的像素映射到原图中的坐标值,即插值位置
            coordinateX=j/ratioX+0.5;
            coordinateY=i/ratioY+0.5;
             
            //若插值位置在输入图像范围内,则近邻插值
            if(0<=coordinateX&&coordinateX<m_imgWidth
                && coordinateY>=0&&coordinateY<m_imgHeight){
                for(k=0;k<pixelByte;k++)
                    *(m_pImgDataOut + i * lineByteOut + j*pixelByte + k) 
                    =*(m_pImgData+ coordinateY*lineByteIn+ coordinateX*pixelByte + k) ;
            }
            else //若不在输入图像范围内,则置255  
            {
                for(k=0;k<pixelByte;k++)
                    *(m_pImgDataOut + i * lineByteOut + j*pixelByte+k) = 255;
            }          
        }
    }
}


最近邻插值处理结果

2、双线性插值

void GeometryTrans::Zoom(float ratioX, float ratioY)
{
     
    //释放旧的输出图像缓冲区
    if(m_pImgDataOut!=NULL){
        delete []m_pImgDataOut;
        m_pImgDataOut=NULL;
    }
     
    //输出图像的宽和高
    m_imgWidthOut=int(m_imgWidth*ratioX+0.5) ;
    m_imgHeightOut=int(m_imgHeight*ratioY+0.5); 
 
    //输入图像每行像素字节数
    int lineByteIn=(m_imgWidth*m_nBitCount/8+3)/4*4;
     
    //输出图像每行像素字节数
    int lineByteOut=(m_imgWidthOut*m_nBitCount/8+3)/4*4;
 
    //申请缓冲区,存放输出结果
    m_pImgDataOut=new unsigned char[lineByteOut*m_imgHeightOut];
 
    //每像素字节数,输入图像与输出图像相同
    int pixelByte=m_nBitCount/8;
     
    //输出图像在输入图像中待插值的位置坐标
    float coordinateX, coordinateY;
     
    //循环变量,输出图像的坐标
    int i, j;
     
    //循环变量,像素的每个通道
    int k;
 
    int y1,y2, x1,x2;
    float fx1,fx2, fy1, fy2;
     
    //双线性插值
    for(i=0; i< m_imgHeightOut; i++)
    {
        coordinateY = i/ratioY;
        y1 = (int)coordinateY;
        if(y1 == m_imgHeightOut-1)    
            y2 = y1;
        else y2 = y1 + 1;
 
        fy1 = coordinateY-y1; 
        fy2 = (float)1.0 - fy1;
 
        for(j=0; j<m_imgWidthOut; j++)
        {  
            coordinateX = j/ratioX;
            x1 = (int)coordinateX;
            if(x1 == m_imgWidthOut-1)    
                x2 = x1;
            else x2 = x1+1;
 
            fx1 = coordinateX-x1;
            fx2 = (float)1.0 - fx1;
            //所求的源图像中的2*2区域4个邻近象素点坐标为(x1, y1) (x1, y2) (x2, y1) (x2,y2)
            //计算4个权重
            float s1 = fx1*fy1;
            float s2 = fx2*fy1;
            float s3 = fx2*fy2;
            float s4 = fx1*fy2;
            //输出图像坐标为(j,i)的像素映射到原图中的坐标值,即插值位置
             
            //若插值位置在输入图像范围内,则双线性插值
            if(0<=coordinateX&&coordinateX<m_imgWidth
                && coordinateY>=0&&coordinateY<m_imgHeight)
            {
                for(k=0;k<pixelByte;k++)
                    *(m_pImgDataOut + i * lineByteOut + j*pixelByte + k) 
                    =(int)((*(m_pImgData+ y2*lineByteIn+ x2*pixelByte + k))*s1+
                           (*(m_pImgData+ y2*lineByteIn+ x1*pixelByte + k))*s2+
                           (*(m_pImgData+ y1*lineByteIn+ x1*pixelByte + k))*s3+
                           (*(m_pImgData+ y1*lineByteIn+ x2*pixelByte + k))*s4);
            }
            else //若不在输入图像范围内,则置255  
            {
                for(k=0;k<pixelByte;k++)
                    *(m_pImgDataOut + i * lineByteOut + j*pixelByte+k) = 255;
            }
             
        }
    }
}


双线性插值处理结果

比较结果可知,双线性插值处理的图像比最近邻插值处理的图像平滑、清晰。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值