zoukankan      html  css  js  c++  java
  • OpenCV 图像缩放cv::resize 各种插值方式的比较

    1. resize函数说明
        OpenCV提供了resize函数来改变图像的大小,函数原型如下:

    void resize(InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0, int interpolation=INTER_LINEAR );

    参数说明:

    src:输入,原图像,即待改变大小的图像;
    dst:输出,改变大小之后的图像,这个图像和原图像具有相同的内容,只是大小和原图像不一样而已;
    dsize:输出图像的大小。如果这个参数不为0,那么就代表将原图像缩放到这个Size(width,height)指定的大小;如果这个参数为0,那么原图像缩放之后的大小就要通过下面的公式来计算:
           dsize = Size(round(fx*src.cols), round(fy*src.rows))
    
           其中,fx和fy就是下面要说的两个参数,是图像width方向和height方向的缩放比例。
    
    fx:width方向的缩放比例,如果它是0,那么它就会按照(double)dsize.width/src.cols来计算;
    fy:height方向的缩放比例,如果它是0,那么它就会按照(double)dsize.height/src.rows来计算;
    interpolation:这个是指定插值的方式,图像缩放之后,肯定像素要进行重新计算的,就靠这个参数来指定重新计算像素的方式,有以下几种:
          INTER_NEAREST - 最邻近插值
          INTER_LINEAR - 双线性插值,如果最后一个参数你不指定,默认使用这种方法
          INTER_AREA -区域插值 resampling using pixel area relation. 
                    It may be a preferred method for image decimation, as it gives moire’-free results.
                    But when the image is zoomed, it is similar to the INTER_NEAREST method.       INTER_CUBIC - 4x4像素邻域内的双立方插值       INTER_LANCZOS4 - 8x8像素邻域内的Lanczos插值

    使用注意事项:

       dsize和fx/fy不能同时为0,要么你就指定好dsize的值,让fx和fy空置直接使用默认值,就像

    resize(img, imgDst, Size(30,30));

    要么你就让dsize为0,指定好fx和fy的值,比如fx=fy=0.5,那么就相当于把原图两个方向缩小一倍!

    OpenCV官方说明:注意红色方框那句话:

    To shrink an image, it will generally look best with cv::INTER_AREA interpolation, whereas to enlarge an image, 
    it will generally look best with cv::INTER_CUBIC (slow) or cv::INTER_LINEAR (faster but still looks OK).


    2.各种插值方式的比较
        OpenCV的cv::resize函数支持多种插值方式,这里主要比较下面四个常用的插值方式。

    2.1 INTER_NEAREST(最近邻插值)
        最近邻插值是最简单的插值方法,选取离目标点最近的点作为新的插入点,计算公式表示如下:

    插值后的边缘效果:由于是以最近的点作为新的插入点,因此边缘不会出现缓慢的渐慢过度区域,这也导致放大的图像容易出现锯齿的现象

    2.2 INTER_CUBIC  (三次样条插值)

    插值后的边缘效果:可以有效避免出现锯齿的现象

    2.3 INTER_LINEAR(线性插值)

        线性插值是以距离为权重的一种插值方式。

    插值后的边缘效果:可以有效避免出现锯齿的现象

    2.4 INTER_AREA  (区域插值)
       区域插值共分三种情况,图像放大时类似于双线性插值,图像缩小(x轴、y轴同时缩小)又分两种情况,此情况下可以避免波纹出现。因此对图像进行缩小时,为了避免出现波纹现象,推荐采用区域插值方法。

      OpenGL说明文档有这么解释:To shrink an image, it will generally look best with #INTER_AREA interpolation, whereas to enlarge an image, it will generally look best with #INTER_CUBIC (slow) or #INTER_LINEAR (faster but still looks OK).

        如果要缩小图像,通常推荐使用INTER_AREA插值效果最好,而要放大图像,通常使用INTER_CUBIC(速度较慢,但效果最好),或者使用INTER_LINEAR(速度较快,效果还可以)。

    插值后的边缘效果:

    测试代码:

     1 #include <chrono>
     2 #include <opencv2/opencv.hpp>
     3 #define  millisecond 1000000
     4 #define DEBUG_PRINT(...)  printf( __VA_ARGS__); printf("
    ")
     5 #define DEBUG_TIME(time_) auto time_ =std::chrono::high_resolution_clock::now()
     6 #define RUN_TIME(time_)  (double)(time_).count()/millisecond
     7 using namespace std;
     8  
     9  
    10 int main()
    11 {
    12     string image_path = "D:\imageEnhance\hdrnet\1.jpg";
    13     cv::Mat image = cv::imread(image_path);
    14     cv::Mat image2X_INTER_NEAREST;
    15     cv::Mat image2X_INTER_LINEAR;
    16     cv::Mat image2X_INTER_AREA;
    17     cv::Mat image2X_INTER_CUBIC;
    18     double scale = 3.0;
    19  
    20     cv::Mat initMat;
    21     cv::resize(image, initMat, cv::Size(), scale, scale, cv::INTER_NEAREST);
    22  
    23  
    24     DEBUG_PRINT("image size[%d,%d],scale=%3.1f", image.rows,image.cols, scale);
    25     DEBUG_TIME(T0);
    26     cv::resize(image, image2X_INTER_NEAREST, cv::Size(), scale, scale, cv::INTER_NEAREST);//最近邻插值
    27     DEBUG_TIME(T1);
    28     cv::resize(image, image2X_INTER_LINEAR, cv::Size(), scale, scale, cv::INTER_LINEAR); //线性插值(默认)
    29     DEBUG_TIME(T2);
    30     cv::resize(image, image2X_INTER_AREA, cv::Size(), scale, scale, cv::INTER_AREA);     //区域插值,图像放大时类似于线性插值,图像缩小时可以避免波纹出现。
    31     DEBUG_TIME(T3);
    32     cv::resize(image, image2X_INTER_CUBIC, cv::Size(), scale, scale, cv::INTER_CUBIC);   //三次样条插值
    33     DEBUG_TIME(T4);
    34  
    35     DEBUG_PRINT("INTER_NEAREST:%3.3fms", RUN_TIME(T1 - T0));
    36     DEBUG_PRINT("INTER_LINEAR :%3.3fms", RUN_TIME(T2 - T1));
    37     DEBUG_PRINT("INTER_AREA   :%3.3fms", RUN_TIME(T3 - T2));
    38     DEBUG_PRINT("INTER_CUBIC  :%3.3fms", RUN_TIME(T4 - T3));
    39  
    40     return 0;
    41 }

    运行结果:

    image size[2912,4368],scale=3.0
    INTER_NEAREST:211.946ms
    INTER_LINEAR :510.467ms
    INTER_AREA   :541.749ms
    INTER_CUBIC  :213.416ms

    3. 总结
        测试结果表明:

    速度比较:INTER_NEAREST(最近邻插值)>INTER_CUBIC  (三次样条插值)>INTER_LINEAR(线性插值)>INTER_AREA  (区域插值)
    对图像进行缩小时,为了避免出现波纹现象,推荐采用INTER_AREA 区域插值方法。
    OpenCV推荐:如果要缩小图像,通常推荐使用#INTER_AREA插值效果最好,而要放大图像,通常使用INTER_CUBIC(速度较慢,但效果最好),或者使用INTER_LINEAR(速度较快,效果还可以)。至于最近邻插值INTER_NEAREST,一般不推荐使用
    特殊说明:鄙人在测试的时候,发现使用INTER_CUBIC方法,并不慢啊啊啊,比INTER_LINEAR还快!!!!这个就比较尴尬了!我猜是OpenCV有对INTER_CUBIC插值方法进行特殊的优化吧!



  • 相关阅读:
    JQuery的摸索之路(一)
    C#操作excel(NPOI篇)
    Mschart学习(MSchart介绍)
    JQuery的摸索之路(二比较)
    Mschart学习(开篇)
    Mschart学习(官方demo共享)
    SQL进阶提升(疑惑篇order by)学习sql server2005 step by step(十一)
    一步一步学习C#(二C#基础)
    NickLee的学习
    Linux 命令学习一
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/12825644.html
Copyright © 2011-2022 走看看