zoukankan      html  css  js  c++  java
  • 实现基于最近邻内插和双线性内插的图像缩放C++实现

    平时我们写图像处理的代码时,如果需要缩放图片,我们都是直接调用图像库的resize函数来完成图像的缩放。作为一个机器视觉或者图像处理算法的工作者,图像缩放代码的实现应该是必须掌握的。在众多图像缩放算法中,最近邻内插算法和双线性内插算法最为基本和常见,所以这篇文章就说一说如何用c++实现这两种算法下的图像缩放。

    最近邻内插

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

    #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();
    
    }
    

    原图

    缩放图

    最近邻内插算法实现的图像缩放的原理很简单,编码起来也容易,缺点就是得到的图像效果不太好。

    双线性内插

    对于一个目的像素,设置坐标通过反向变换得到的浮点坐标为(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
    ", 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();
    }
    

  • 相关阅读:
    爬虫(五):生产者消费者方法
    三. Anagram detection problem for string(字符串中回文词汇检测问题)
    二. Object-Oriented Programming in Python: Defining Classes
    一.Introduction
    爬虫(四):正则表达式(提取str中网址)
    centos7源代码编译安装heartbeat
    linux yum配置
    java常见证书类型和密钥库类型
    常用的加密算法
    iptables学习理解
  • 原文地址:https://www.cnblogs.com/skyfsm/p/7578302.html
Copyright © 2011-2022 走看看