OpenCV 图像内插

1. 最近邻内插

根据原图像和目标图像的尺寸,计算缩放的比例,然后根据缩放比例计算目标像素所依据的原像素,过程中自然会产生小数,这时就采用四舍五入,取与这个点最相近的点,当然向下取整也是可以的。

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace std;
void scale(cv::Mat& input_img, int width, int height);

int main()
{
    cv::Mat img = cv::imread("41.png",0);
    cv::imshow("src", img);
    scale(img, 450, 300);

    return 0;
}

//获取原图相应坐标的像素值
uchar get_scale_value(cv::Mat& input_img, int i, int j)
{
    uchar* p = input_img.ptr<uchar>(i);
    return p[j];
    
}

void scale(cv::Mat& input_img,int width,int height)
{
    cv::Mat output_img(height, width, CV_8UC1);
    output_img.setTo(0);
    float h_scale_rate = (float)input_img.rows/ height;  //高的比例
    float w_scale_rate = (float)input_img.cols / width;  //宽的比例
    for (int i = 0; i < height; i++)
    {
        uchar* p = output_img.ptr<uchar>(i);
        for (int j = 0; j < width; j++)
        {
            int i_scale = h_scale_rate * i;   //依照高的比例计算原图相应坐标中的x,这里采用的是向下取整,当然四舍五入也可以
            int j_scale = w_scale_rate * j;  //依照宽的比例计算原图相应坐标中的y
            //cout << "i_scale: " << i_scale <<" j_scale: "<< j_scale << endl;
 
            p[j] = get_scale_value(input_img,i_scale, j_scale);
        }
    }

    cv::imshow("scale", output_img);
    cv::imwrite("result.png", output_img);
    cv::waitKey();

}

2. 双线性内插

对于一个目的像素,设置坐标通过反向变换得到的浮点坐标为(x,y),当然我们也可以将其表示成整数+小数的形式,即(i+u,j+v),其中i、j均为非负整数,u、v为[0,1)区间的浮点数,则这个像素得值 f(i+u,j+v) 可由原图像中坐标为 (i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)所对应的周围四个像素的值决定,即:

    f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)

双线性内值算法的核心思想就是上面的那个公式,它解释了对于原图不存在的浮点像素(比如<1.5,1.5>)是如何确定其实际值的。其实它是以4个相邻的像素值来共同确定,即<1,1> <2,1> <1,2> <2,2>。谁离<1,1>比较近,谁就对它起的影响比较大,这些都在公式中有所体现,这就是双线性插值的精髓。

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace std;
void bin_linear_scale(cv::Mat& input_img, int width, int height);

int main()
{
    cv::Mat img = cv::imread("41.png", 0);
    cv::imshow("src", img);
    bin_linear_scale(img, 450, 300);

    return 0;
}


//f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)  
uchar get_scale_value(cv::Mat& input_img, float raw_i, float raw_j)
{
    int i = raw_i;
    int j = raw_j;
    float u = raw_i - i;
    float v = raw_j - j;

    //注意处理边界问题,容易越界
    if (i + 1 >= input_img.rows || j + 1 >= input_img.cols)
    {
        uchar* p = input_img.ptr<uchar>(i);
        return p[j];
    }
    
    uchar* p = input_img.ptr<uchar>(i);
    uchar x1 = p[j];  //f(i,j)
    uchar x2 = p[j + 1];  //f(i,j+1)
    p = input_img.ptr<uchar>(i+1);
    uchar x3 = p[j];   //(i+1,j)
    uchar x4 = p[j + 1];  //f(i+1,j+1) 
     
   // printf("%d %d\n", i, j);
    return ((1-u)*(1-v)*x1+(1-u)*v*x2+u*(1-v)*x3+u*v*x4);
}

         
void bin_linear_scale(cv::Mat& input_img, int width, int height)
{
    cv::Mat output_img(height, width, CV_8UC1);
    output_img.setTo(0);
    float h_scale_rate = (float)input_img.rows / height;
    float w_scale_rate = (float)input_img.cols / width;
    for (int i = 0; i < height; i++)
    {
        uchar* p = output_img.ptr<uchar>(i);
        for (int j = 0; j < width; j++)
        {
            float i_scale = h_scale_rate * i;
            float j_scale = w_scale_rate * j;
            //cout << "i_scale: " << i_scale <<" j_scale: "<< j_scale << endl;

            p[j] = get_scale_value(input_img, i_scale, j_scale);
        }
    }

    cv::imshow("scale", output_img);
    cv::imwrite("result.png", output_img);
    cv::waitKey();
}

3. 双三次内插

考虑的是周围16个像素的像素值,其权重因子的计算比较复杂。常用BiCubic插值原理。

 

参考1:https://www.cnblogs.com/skyfsm/p/7578302.html

参考2:https://blog.csdn.net/mynameislinduan/article/details/81561355

参考3:https://blog.csdn.net/xuan_zizizi/article/details/82747729?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪易

给我来点鼓励吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值