OpenCV函数:resize() 实现 (最近邻,双线性)

前言

在 OpenCV 中,resize()用来改变图像的大小,包含了 5 种插值方式。在这里,我用代码实现了其中两种最具代表性的插值方式:最近邻与双线性插值。

最近邻

最近邻插值方式如下:

xd=xsfxyd=ysfyfx=wd/wsfy=hd/hs

其中, xd,yd 为目标图像坐标, xs,ys 为源图像坐标。
实现最近邻的 resize() 代码:

Mat ReSizeForNearest(Mat src, Size dsize,double fx = 0, double fy = 0)
{
    if (src.empty())
        throw exception("Image is empty!");
    int c = src.channels();
    if (dsize.width!=0 && dsize.height!=0)
    {
        fx = (double)dsize.width / (double)src.cols;
        fy = (double)dsize.height / (double)src.rows;
    }
    else if (fx != 0 && fy != 0)
    {
        dsize.width = int(src.cols*fx);
        dsize.height = int(src.rows*fy);
    }
    else
    {
        throw exception("Invalid parameter!");
    }
    Mat dst(dsize, src.type(), Scalar::all(0));
    for (int i = 0; i < dst.rows; i++)
    {
        uchar* dstData = dst.ptr(i);
        int srcy = cvFloor(i / fy);
        srcy = min(srcy, src.rows - 1);
        uchar* srcData = src.ptr(srcy);
        for (int j = 0; j < dst.cols*c; j+=c)
        {
            int srcx = cvFloor((j/c) / fx);
            srcx = min(srcx, src.cols - 1);
            for (int k = 0; k < c; k++)
            {
                dstData[j + k] = srcData[srcx*c + k];
            }
        }
    }
    return dst;
}

实验结果:
原始图片:

OpenCV函数:resize() 实现 (最近邻,双线性)_第1张图片

调用 ReSizeForNearest(image, Size(600, 1000));的结果:

OpenCV函数:resize() 实现 (最近邻,双线性)_第2张图片

可以发现放大后的图片非常粗糙。

双线性插值

先给出双线性插值的公式:

Dst(xd,yd)=(1u)(1v)Src(xs,ys)+(1u)vSrc(xs,ys+1)+u(v1)Src(xs+1,ys)+uvSrc(xs+1,ys+1)

其矩阵表示为:
Dst(xd,yd)=[1uu][Src(xs,ys)Src(xs+1,ys)Src(xs,ys+1)Src(xs+1,ys+1)][1vv]

其中, xd,yd 的计算方式与最近邻相同,向下取整, u,v 为计算得到坐标值的小数部分。

实现双线性插值的 resize() 代码:

Mat ReSizeForLinear(Mat src, Size dsize, double fx = 0, double fy = 0)
{
    if (src.empty())
        throw exception("Image is empty!");
    int c = src.channels();
    if (dsize.width != 0 && dsize.height != 0)
    {
        fx = (double)dsize.width / (double)src.cols;
        fy = (double)dsize.height / (double)src.rows;
    }
    else if (fx != 0 && fy != 0)
    {
        dsize.width = int(src.cols*fx);
        dsize.height = int(src.rows*fy);
    }
    else
    {
        throw exception("Invalid parameter!");
    }
    Mat dst(dsize, src.type(), Scalar::all(0));
    for (int i = 0; i < dst.rows; i++)
    {
        uchar* dstData = dst.ptr(i);
        double srcy = i / fy;
        int y = cvFloor(srcy);
        double v = srcy - y;
        if (v < 0)
        {
            y = 0;
            v = 0;
        }
        if (y >= src.rows - 1)
        {
            y = src.rows - 2;
            v = 1;
        }
        uchar* srcData1 = src.ptr(y);
        uchar* srcData2 = src.ptr(y+1);
        for (int j = 0; j < dst.cols*c; j += c)
        {
            double srcx = (j/c) / fx;
            int x = cvFloor(srcx);
            double u = srcx - x;
            if (x < 0)
            {
                x = 0;
                u = 0;
            }
            if (x >= src.cols - 1)
            {
                x = src.cols - 2;
                u = 1;
            }
            for (int k = 0; k < c; k++)
            {
                dstData[j + k] = (1 - u)*(1 - v)*srcData1[x*c + k] +
                    (1 - u)*v*srcData2[x*c + k] +
                    u*(1 - v)*srcData1[(x + 1)*c + k] +
                    u*v*srcData2[(x + 1)*c + k];
            }
        }
    }
    return dst;
}

实验结果:
原图与上面一致,ReSizeForLinear(image, Size(600, 1000));的结果为:
OpenCV函数:resize() 实现 (最近邻,双线性)_第3张图片

其结果比上面的图片效果好了很多。

你可能感兴趣的:(图像处理)