图片双线性插值算法

算法原理简介

双线性插值是一阶插值,常用于图像的旋转、缩放处理。

它利用原图中对应的四个点的像素值来确定目标图像中的像素值。

为了便于理解,我们来看两张尺寸不一样的图片:

原图

 

变换图

假设原图图片的宽度为yw,高度为xh

变换图的宽度为jw,高度为ih

于是对于变换图中任意一个像素点(j’, i’)我们可以用以下的方法映射到原图中去:

y' = yw/jw * j'
x' = xh/ih * i'
  • 1
  • 2
  • 3

通常情况下,y’和x’不为整数。

例如,原图尺寸:

yw = 1000
xh = 800
  • 1
  • 2
  • 3

变换图尺寸:

jw = 700
ih = 700
  • 1
  • 2
  • 3

对于变换图中的(400, 400)像素点:

y' = 1000/700 * 400 = 571.42857
x' = 800/700 * 400 = 457.14286
  • 1
  • 2
  • 3

我们将变换图中的(400, 400)像素点映射到原图中的(571.42857, 457.14286)。

于是我们就用原图中对应的4点(571,457),(572,457),(571,458),(572,458)来确定变换图像中的(400,400)点像素值。

t = 571.42857 - 571 = 0.42857
u = 457.14286 - 457 = 0.14286
  • 1
  • 2
  • 3

我们认为距离(y’, x’)点距离越近,其对目标像素影响的权重应该越大,距离越远,影响权重越小。

(571,457)点权重为s4面积,(572,457)点权重为s3面积,(571,458)点权重为s2面积,(572,458)点权重为s1面积。

于是我们得到:

(400,400)目标图 = (571,457)xs4 + (572,457)xs3 + (571,458)xs2 + (572,458)xs1

其中,s1+s2+s3+s4 = 1

以上就是双线性插值法目标像素计算公式。

算法的c代码实现

/*
 * param: 
 * Mat src 原始图片
 * Mat dst 目标图片
 */
void BGRBilinearScale(const Mat src, Mat dst) {

    double dstH = dst.rows;  //目标图片高度
    double dstW = dst.cols;  //目标图片宽度
    double srcW = src.cols;  //原始图片宽度,如果用int可能会导致(srcH - 1)/(dstH - 1)恒为零
    double srcH = src.rows;  //原始图片高度
    double xm = 0;      //映射的x
    double ym = 0;      //映射的y
    int xi = 0;         //映射x整数部分
    int yi = 0;         //映射y整数部分
    int xl = 0;         //xi + 1
    int yl = 0;         //yi + 1
    double xs = 0;   
    double ys = 0;

    /* 为目标图片每个像素点赋值 */
    for(int i = 0; i < dstH; i ++) {
        for(int j = 0; j < dstW; j ++) {
            //求出目标图像(i,j)点到原图像中的映射坐标(mapx,mapy)
            xm = (srcH - 1)/(dstH - 1) * i;
            ym = (srcW - 1)/(dstW - 1) * j;
            /* 取映射到原图的xm的整数部分 */
            xi = (int)xm;
            yi = (int)ym;
            /* 取偏移量 */
            xs = xm - xi;
            ys = ym - yi;

            xl = xi + 1;
            yl = yi + 1;
            //边缘点
            if((xi+1) > (srcH-1)) xl = xi-1;
            if((yi+1) > (srcW-1)) yl = yi-1;

            //b
            dst.at<Vec3b>(i,j)[0] = (int)(src.at<Vec3b>(xi,yi)[0]*(1-xs)*(1-ys) + 
                    src.at<Vec3b>(xi,yl)[0]*(1-xs)*ys +
                    src.at<Vec3b>(xl,yi)[0]*xs*(1-ys) +
                    src.at<Vec3b>(xl,yl)[0]*xs*ys);
            //g
            dst.at<Vec3b>(i,j)[1] = (int)(src.at<Vec3b>(xi,yi)[1]*(1-xs)*(1-ys) + 
                    src.at<Vec3b>(xi,yl)[1]*(1-xs)*ys +
                    src.at<Vec3b>(xl,yi)[1]*xs*(1-ys) +
                    src.at<Vec3b>(xl,yl)[1]*xs*ys);
            //r
            dst.at<Vec3b>(i,j)[2] = (int)(src.at<Vec3b>(xi,yi)[2]*(1-xs)*(1-ys) + 
                    src.at<Vec3b>(xi,yl)[2]*(1-xs)*ys +
                    src.at<Vec3b>(xl,yi)[2]*xs*(1-ys) +
                    src.at<Vec3b>(xl,yl)[2]*xs*ys);

        }
    }
}

 

放缩效果预览

原图为1024 x 640图片,变换目标图片为800 x 800图片

原图

目标图

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a153375250/article/details/50992610

posted on 2018-05-29 08:33  销售人生  阅读(918)  评论(0编辑  收藏  举报