呼,花了一个下午,终于是写完加调试完了所有的代码。

双三次插值介绍

之前我写的这篇博客中讲了什么是超分,并实现了单线性插值算法和双线性插值算法。在这里将再介绍一种插值算法——双三次插值算法。

首先,双三次插值法需要参考16个点(4x4),因此插值效果会比双线性插值法要好,但同时时间开销也会更大。在 OpenCV 中,可在 cv::resize 函数中使用 cv::INTER_CUBIC 选项选择使用双三次插值算法改变图像大小。

在学习的过程中,我参考了这篇博客,其中的插值算法写成表达式的形式为:
f(x,y)=∑i=03∑j=03f(xi,yj)W(x−xi)W(y−yj)f(x,y)=\sum_{i=0}^3\sum_{j=0}^3f(x_i,y_j)W(x-x_i)W(y-y_j)f(x,y)=i=0∑3​j=0∑3​f(xi​,yj​)W(x−xi​)W(y−yj​)
其中,(x,y) 表示待插值的像素点的坐标,f(x,y)表示经过计算待插值像素点应该插入的值,(xi,yj)(x_i,y_j)(xi​,yj​) i,j=0,1,2,3i,j=0,1,2,3i,j=0,1,2,3 表示待插值点附近的 4x4 领域的点。

WWW函数称为 BiCubic 函数。与该博客中不同的是,原博客中的像素点可以是浮点数,而在 OpenCV 中坐标只能为整数。因此在这里 WWW 函数需要做个变换。

原博客中的 WWW 函数:
W(x)={(a+2)∣x∣3−(a+3)∣x∣2+1∣x∣≤1a∣x∣3−5a∣x∣2+8a∣x∣−4a1<∣x∣<20elseW(x)=\left\{ \begin{matrix} (a+2)|x|^3-(a+3)|x|^2+1 \qquad|x|\le1\\ a|x|^3-5a|x|^2+8a|x|-4a\qquad1<|x|<2\\ 0\qquad \qquad \qquad else\\ \end{matrix} \right. W(x)=⎩⎨⎧​(a+2)∣x∣3−(a+3)∣x∣2+1∣x∣≤1a∣x∣3−5a∣x∣2+8a∣x∣−4a1<∣x∣<20else​

在这里使用的 WWW 函数:
W(x)={(a+2)∣x/t∣3−(a+3)∣x/t∣2+1∣x∣≤ta∣x/t∣3−5a∣x/t∣2+8a∣x/t∣−4at<∣x∣<2t0elseW(x)=\left\{ \begin{matrix} (a+2)|x/t|^3-(a+3)|x/t|^2+1 \qquad |x|\le t\\ a|x/t|^3-5a|x/t|^2+8a|x/t|-4a\qquad t<|x|<2t \\ 0\qquad \qquad \qquad else\\ \end{matrix} \right. W(x)=⎩⎨⎧​(a+2)∣x/t∣3−(a+3)∣x/t∣2+1∣x∣≤ta∣x/t∣3−5a∣x/t∣2+8a∣x/t∣−4at<∣x∣<2t0else​

其中 ttt 为超分放大倍数,aaa 为指定的值,OpenCV 源码中给的是 -0.75。

代码实现

首先是需要循环遍历每个像素点,逐个计算像素点的值。

进一步地,如何计算像素点的值呢?例如,下图中绿色的点是原图像上的像素点,红色的点是待计算的点,则用黄色框起来的点为参考的像素点。假设其坐标为(i,j)(在dst上,即保存超分结果的图像上),以行为例,则参考src的行号如下图所标注。对于列也是同理。因此我们知道了上述表达式中 xix_ixi​ 和 yjy_jyj​ 的所有取值。
W(x−xi)W(x-x_i)W(x−xi​) 中的 x−xix-x_ix−xi​ 表示当前像素点距离参考像素点的 xxx 方向上的距离(yyy 方向同理)。根据 WWW 函数的表达式可以判断出,这个距离应该要小于两倍的 timestimestimes (放大倍数)。以左边的参考点为例(向右也是同理),在dst 图像中,对于离待计算点最近的左边的像素点,它们的 xxx 方向上的距离为 i%timesi\%timesi%times 。又因为在 dst 图中,两个绿色的点之间的间距为放大倍数,因此计算点离最左边的参考点的距离为 i%times+timesi\%times+timesi%times+times。同时考虑到右侧的点,可以写成更加一般的形式:i%times−i∗timesi\%times-i*timesi%times−i∗times。其中 i=−1,0,1,2i=-1,0,1,2i=−1,0,1,2 。对于列也是同理。

(注:在代码中,为了与逐个枚举像素点的循环变量区分开,此处的 i j 会写成 r c。其中 r 代表 row,表示行; c 代表 col, 表示列。)

以下是完整的代码:

//权重计算函数
//输入:x:自变量的值  times: 图片超分倍数
//返回值:W(x)计算之后的值
double W(int x,int times){x=std::abs(x);//OpenCV 中给的是 -0.75double a=-0.75;double abs_=std::abs((double)x/(double)times);if(x>=2*times) return 0.0;else if(x>times){double ans=a*(abs_)*(abs_)*(abs_)-5*a*(abs_)*(abs_)+8*a*(abs_)-4*a;return ans;}else{double ans=(a+2)*(abs_)*(abs_)*(abs_)-(a+3)*(abs_)*(abs_)+1;return ans;}//不会执行到这里的,哈哈return -1.0f;
}//双三次插值
//输入:原图像(单通道),超分倍数
//返回值:超分后的图像
cv::Mat biCubicInterp(const cv::Mat &src, int times){cv::Mat dst=cv::Mat::zeros(cv::Size(src.cols*times,src.rows*times),CV_8UC1);for(int i=0;i<dst.rows;i++){for(int j=0;j<dst.cols;j++){double val=0.0;//利用周围16个像素点计算插值for(int r=-1;r<=2;r++){//如果参考点超出图像范围,则舍弃if(i/times+r<0 || i/times+r>=src.rows) continue;for(int c=-1;c<=2;c++){//如果参考点超出图像范围,则舍弃if(j/times+c<0 || j/times+c>=src.cols) continue;val+=(src.at<uchar>(i/times+r,j/times+c)*W(i%times-r*times,times)*W(j%times-c*times,times));}}//防止越界溢出if(val>255) val=255;if(val<0) val=-val;dst.at<uchar>(i,j)=(unsigned char)val;}}return dst;
}

运行结果

对一张 100x100 分辨率的图片,分别用双线性插值法和双三次插值法放大8倍,处理成 800x800 分辨率的图片。运行结果如下:

双线性插值法:

双三次插值法:
仔细观察可以发现,在像素值发生突变的位置(如数字 5 的周围),双线性插值法超分后的图像会出现方块效应,而使用双三次插值法超分后的图像就显得比较光滑,但是时间开销也会更大。

算法复杂度分析

双线性插值法 O(3n2)O(3n^2)O(3n2)

双三次插值法 O(16n2)O(16n^2)O(16n2)

传统图片超分算法——双三次插值 (Bicubic)、附C++源码相关推荐

  1. AES-128算法实现(附C++源码)

    AES-128算法实现(附C++源码) 文章目录 AES-128算法实现(附C++源码) 前言 AES的算法流程 几个你会用到的常量 S盒 逆S盒 常量轮值表 密钥拓展 轮密钥加 字节代换 行移位 列 ...

  2. android 静态图片自动切换,Android静态图片人脸识别的完整demo(附完整源码)

    Android静态图片人脸识别的完整demo(附完整源码) 来源:互联网 作者:佚名 时间:2015-03-24 20:07 本文介绍了android静态识别人脸并进行标记人眼位置及人脸框的完整dem ...

  3. C++floyd warshall算法求最短路径(附完整源码)

    C++floyd warshall算法求最短路径 floyd warshall算法求最短路径的完整源码(定义,实现,main函数测试) floyd warshall算法求最短路径的完整源码(定义,实现 ...

  4. C++KMP算法字符串匹配(附完整源码)

    C++KMP算法字符串匹配 C++KMP算法字符串匹配完整源码(定义,实现,main函数测试) C++KMP算法字符串匹配完整源码(定义,实现,main函数测试) #include <iostr ...

  5. C++shell sort希尔排序的实现算法之二(附完整源码)

    C++shell sort希尔的实现算法 C++shell sort希尔的实现算法完整源码(定义,实现,main函数测试) C++shell sort希尔的实现算法完整源码(定义,实现,main函数测 ...

  6. C++Quick sort快速排序的实现算法之二(附完整源码)

    C++Quick sort快速排序的实现算法 C++Quick sort快速排序的实现算法完整源码(定义,实现,main函数测试) C++Quick sort快速排序的实现算法完整源码(定义,实现,m ...

  7. C++radix sort基数排序的实现算法之二(附完整源码)

    C++radix sort基数排序的实现算法 C++radix sort基数排序的实现算法完整源码(定义,实现,main函数测试) C++radix sort基数排序的实现算法完整源码(定义,实现,m ...

  8. c++Interpolation search插值搜索的实现算法之二(附完整源码)

    C++Interpolation search插值搜索的实现算法 C++Interpolation search插值搜索的实现算法完整源码(定义,实现,main函数测试) C++Interpolati ...

  9. C++用Tarjan 算法寻找桥(附完整源码)

    C++用Tarjan 算法寻找桥的实现 C++用Tarjan 算法寻找桥完整源码(定义,实现,main函数测试) C++用Tarjan 算法寻找桥完整源码(定义,实现,main函数测试) #inclu ...

最新文章

  1. Python 核心设计理念27个问题及解答
  2. 问题Re-installation failed due to different application signatures.解决
  3. QT学习:多线程运用
  4. 交叉验证选择最佳参数_如何为您的公司选择最佳的身份验证即服务提供商
  5. Remixer-谷歌的UI参数动态修改框架
  6. 【Android界面实现】Drawable Animation 使用介绍
  7. MicroProfile变成了Eclipse MicroProfile
  8. 6748如何设置edma为事件触发方式_全面分析前端的网络请求方式
  9. (转载)python re模块详解 正则表达式
  10. 写一个含数字,拼音,汉字的验证码生成类
  11. cv2 和matplotlib中画图时的颜色选取
  12. html调用本地电脑应用,实现HTML调用打开本地软件文件
  13. 图解机器学习:分类模型性能评估指标
  14. 基于Jsp+Servlet的在线考试系统
  15. MATLAB实现遥感图像分类——K均值算法
  16. 广告学概论--名词解释
  17. TypeError: 'str' object cannot be interpreted as an integer
  18. 入行数据科学,这些书一定要看
  19. 在服务器上部署自己的h5页面用于微信内部浏览器打开
  20. jquery+ajax实现分页功能

热门文章

  1. select2中文帮助文档_5款实用办公app , 石墨文档、收趣 | 发现有趣app
  2. 3-Go并发编程与协程Goroutine
  3. pikachu通关教程
  4. Java实现多个图片转化成PDF
  5. 苹果手机人脸识别不了是什么原因_iPhone和安卓手机的人脸识别有什么区别?
  6. 二叉树的操作--递归与非递归
  7. 【常用工具类】EasyExcel
  8. 真实评测 rtx3080ti对比rx6800xt选哪个好
  9. 电脑端微信可以打开微信小程序了
  10. 超声波的四个特性_超声波的几个特性