图像处理之三种常见双立方插值算法

http://blog.csdn.net/jia20003/article/details/40020775

图像处理之三种常见双立方插值算法

双立方插值计算涉及到16个像素点,其中(i’, j’)表示待计算像素点在源图像中的包含

小数部分的像素坐标,dx表示X方向的小数坐标,dy表示Y方向的小数坐标。具体

可以看下图:

根据上述图示与双立方插值的数学表达式可以看出,双立方插值本质上图像16个像素点

权重卷积之和作为新的像素值。

其中R(x)表示插值表达式,可以根据需要选择的表达式不同。常见有基于三角取值、Bell

分布表达、B样条曲线表达式。

1. 基于三角形采样数学公式为

最简单的线性分布,代码实现如下:

[java] view plain copy

  1. private double triangleInterpolation( double f )
  2. {
  3. f = f / 2.0;
  4. if( f < 0.0 )
  5. {
  6. return ( f + 1.0 );
  7. }
  8. else
  9. {
  10. return ( 1.0 - f );
  11. }
  12. }

2.基于Bell分布采样的数学公式如下:

Bell分布采样数学公式基于三次卷积计算实现。代码实现如下:

[java] view plain copy

  1. private double bellInterpolation( double x )
  2. {
  3. double f = ( x / 2.0 ) * 1.5;
  4. if( f > -1.5 && f < -0.5 )
  5. {
  6. return( 0.5 * Math.pow(f + 1.5, 2.0));
  7. }
  8. else if( f > -0.5 && f < 0.5 )
  9. {
  10. return 3.0 / 4.0 - ( f * f );
  11. }
  12. else if( ( f > 0.5 && f < 1.5 ) )
  13. {
  14. return( 0.5 * Math.pow(f - 1.5, 2.0));
  15. }
  16. return 0.0;
  17. }

3.基于B样条曲线采样的数学公式如下:

是一种基于多项式的四次卷积的采样计算,代码如下:

[java] view plain copy

  1. private double bspLineInterpolation( double f )
  2. {
  3. if( f < 0.0 )
  4. {
  5. f = -f;
  6. }
  7. if( f >= 0.0 && f <= 1.0 )
  8. {
  9. return ( 2.0 / 3.0 ) + ( 0.5 ) * ( f* f * f ) - (f*f);
  10. }
  11. else if( f > 1.0 && f <= 2.0 )
  12. {
  13. return 1.0 / 6.0 * Math.pow( ( 2.0 - f  ), 3.0 );
  14. }
  15. return 1.0;
  16. }

实现图像双立方插值的完整源代码如下:

[java] view plain copy

  1. package com.gloomyfish.zoom.study;
  2. import java.awt.image.BufferedImage;
  3. import java.awt.image.ColorModel;
  4. import com.gloomyfish.filter.study.AbstractBufferedImageOp;
  5. public class BicubicInterpolationFilter extends AbstractBufferedImageOp  {
  6. public final static int TRIANGLE__INTERPOLATION = 1;
  7. public final static int BELL__INTERPOLATION = 2;
  8. public final static int BSPLINE__INTERPOLATION = 4;
  9. public final static int CATMULLROOM__INTERPOLATION = 8;
  10. public final static double B = 0.0;
  11. public final static double C = 0.5; // constant
  12. private int destH; // zoom height
  13. private int destW; // zoom width
  14. private int type;
  15. public BicubicInterpolationFilter()
  16. {
  17. this.type = BSPLINE__INTERPOLATION;
  18. }
  19. public void setType(int type) {
  20. this.type = type;
  21. }
  22. public void setDestHeight(int destH) {
  23. this.destH = destH;
  24. }
  25. public void setDestWidth(int destW) {
  26. this.destW = destW;
  27. }
  28. private double bellInterpolation( double x )
  29. {
  30. double f = ( x / 2.0 ) * 1.5;
  31. if( f > -1.5 && f < -0.5 )
  32. {
  33. return( 0.5 * Math.pow(f + 1.5, 2.0));
  34. }
  35. else if( f > -0.5 && f < 0.5 )
  36. {
  37. return 3.0 / 4.0 - ( f * f );
  38. }
  39. else if( ( f > 0.5 && f < 1.5 ) )
  40. {
  41. return( 0.5 * Math.pow(f - 1.5, 2.0));
  42. }
  43. return 0.0;
  44. }
  45. private double bspLineInterpolation( double f )
  46. {
  47. if( f < 0.0 )
  48. {
  49. f = -f;
  50. }
  51. if( f >= 0.0 && f <= 1.0 )
  52. {
  53. return ( 2.0 / 3.0 ) + ( 0.5 ) * ( f* f * f ) - (f*f);
  54. }
  55. else if( f > 1.0 && f <= 2.0 )
  56. {
  57. return 1.0 / 6.0 * Math.pow( ( 2.0 - f  ), 3.0 );
  58. }
  59. return 1.0;
  60. }
  61. private double triangleInterpolation( double f )
  62. {
  63. f = f / 2.0;
  64. if( f < 0.0 )
  65. {
  66. return ( f + 1.0 );
  67. }
  68. else
  69. {
  70. return ( 1.0 - f );
  71. }
  72. }
  73. private double CatMullRomInterpolation( double f )
  74. {
  75. if( f < 0.0 )
  76. {
  77. f = Math.abs(f);
  78. }
  79. if( f < 1.0 )
  80. {
  81. return ( ( 12 - 9 * B - 6 * C ) * ( f * f * f ) +
  82. ( -18 + 12 * B + 6 *C ) * ( f * f ) +
  83. ( 6 - 2 * B ) ) / 6.0;
  84. }
  85. else if( f >= 1.0 && f < 2.0 )
  86. {
  87. return ( ( -B - 6 * C ) * ( f * f * f )
  88. + ( 6 * B + 30 * C ) * ( f *f ) +
  89. ( - ( 12 * B ) - 48 * C  ) * f +
  90. 8 * B + 24 * C)/ 6.0;
  91. }
  92. else
  93. {
  94. return 0.0;
  95. }
  96. }
  97. @Override
  98. public BufferedImage filter(BufferedImage src, BufferedImage dest) {
  99. int width = src.getWidth();
  100. int height = src.getHeight();
  101. if (dest == null)
  102. dest = createCompatibleDestImage(src, null);
  103. int[] inPixels = new int[width * height];
  104. int[] outPixels = new int[destH * destW];
  105. getRGB(src, 0, 0, width, height, inPixels);
  106. float rowRatio = ((float) height) / ((float) destH);
  107. float colRatio = ((float) width) / ((float) destW);
  108. int index = 0;
  109. for (int row = 0; row < destH; row++) {
  110. int ta = 0, tr = 0, tg = 0, tb = 0;
  111. double srcRow = ((float) row) * rowRatio;
  112. // 获取整数部分坐标 row Index
  113. double j = Math.floor(srcRow);
  114. // 获取行的小数部分坐标
  115. double t = srcRow - j;
  116. for (int col = 0; col < destW; col++) {
  117. double srcCol = ((float) col) * colRatio;
  118. // 获取整数部分坐标 column Index
  119. double k = Math.floor(srcCol);
  120. // 获取列的小数部分坐标
  121. double u = srcCol - k;
  122. double[] rgbData = new double[3];
  123. double rgbCoffeData = 0.0;
  124. for(int m=-1; m<3; m++)
  125. {
  126. for(int n=-1; n<3; n++)
  127. {
  128. int[] rgb = getPixel(j+m, k+n, width, height, inPixels);
  129. double f1 = 0.0d;
  130. double f2 = 0.0d;
  131. if(type == TRIANGLE__INTERPOLATION)
  132. {
  133. f1  = triangleInterpolation( ((double) m ) - t );
  134. f2 = triangleInterpolation ( -(( (double) n ) - u ) );
  135. }
  136. else if(type == BELL__INTERPOLATION)
  137. {
  138. f1  = bellInterpolation( ((double) m ) - t );
  139. f2 = bellInterpolation ( -(( (double) n ) - u ) );
  140. }
  141. else if(type == BSPLINE__INTERPOLATION)
  142. {
  143. f1  = bspLineInterpolation( ((double) m ) - t );
  144. f2 = bspLineInterpolation ( -(( (double) n ) - u ) );
  145. }
  146. else
  147. {
  148. f1  = CatMullRomInterpolation( ((double) m ) - t );
  149. f2 = CatMullRomInterpolation ( -(( (double) n ) - u ) );
  150. }
  151. // sum of weight
  152. rgbCoffeData += f2*f1;
  153. // sum of the RGB values
  154. rgbData[0] += rgb[0] * f2 * f1;
  155. rgbData[1] += rgb[1] * f2 * f1;
  156. rgbData[2] += rgb[2] * f2 * f1;
  157. }
  158. }
  159. ta = 255;
  160. // get Red/green/blue value for sample pixel
  161. tr = (int) (rgbData[0]/rgbCoffeData);
  162. tg = (int) (rgbData[1]/rgbCoffeData);
  163. tb = (int) (rgbData[2]/rgbCoffeData);
  164. index = row * destW + col;
  165. outPixels[index] = (ta << 24) | (clamp(tr) << 16)
  166. | (clamp(tg) << 8) | clamp(tb);
  167. }
  168. }
  169. setRGB(dest, 0, 0, destW, destH, outPixels);
  170. return dest;
  171. }
  172. public int clamp(int value) {
  173. return value > 255 ? 255 :
  174. (value < 0 ? 0 : value);
  175. }
  176. private int[] getPixel(double j, double k, int width, int height,
  177. int[] inPixels) {
  178. int row = (int) j;
  179. int col = (int) k;
  180. if (row >= height) {
  181. row = height - 1;
  182. }
  183. if (row < 0) {
  184. row = 0;
  185. }
  186. if (col < 0) {
  187. col = 0;
  188. }
  189. if (col >= width) {
  190. col = width - 1;
  191. }
  192. int index = row * width + col;
  193. int[] rgb = new int[3];
  194. rgb[0] = (inPixels[index] >> 16) & 0xff;
  195. rgb[1] = (inPixels[index] >> 8) & 0xff;
  196. rgb[2] = inPixels[index] & 0xff;
  197. return rgb;
  198. }
  199. public BufferedImage createCompatibleDestImage(
  200. BufferedImage src, ColorModel dstCM) {
  201. if ( dstCM == null )
  202. dstCM = src.getColorModel();
  203. return new BufferedImage(dstCM,
  204. dstCM.createCompatibleWritableRaster(destW, destH),
  205. dstCM.isAlphaPremultiplied(), null);
  206. }
  207. }

运行效果:原图

双立方插值放大以后:


总结:

基于这里三种方法实现的双立方插值以后图片跟原图像相比,都有一定模糊

这里时候可以通过后续处理实现图像锐化与对比度提升即可得到Sharpen版本

当然也可以通过寻找更加合适的R(x)函数来实现双立方卷积插值过程时保留

图像边缘与对比度。

时间: 2024-10-13 22:51:20

图像处理之三种常见双立方插值算法的相关文章

Java几种常见的编码方式

Java综合 几种常见的编码格式 为什么要编码 不知道大家有没有想过一个问题,那就是为什么要编码?我们能不能不编码?要回答这个问题必须要回到计算机是如何表示我们人类能够理解的符号的,这些符号也就是我们人类使用的语言.由于人类的语言有太多,因而表示这些语言的符号太多,无法用计算机中一个基本的存储单元—— byte 来表示,因而必须要经过拆分或一些翻译工作,才能让计算机能理解.我们可以把计算机能够理解的语言假定为英语,其它语言要能够在计算机中使用必须经过一次翻译,把它翻译成英语.这个翻译的过程就是编

(转载)Android之三种网络请求解析数据(最佳案例)

[置顶] Android之三种网络请求解析数据(最佳案例) 2016-07-25 18:02 4725人阅读 评论(0) 收藏 举报  分类: Gson.Gson解析(1)  版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 小武:相信大家都用过网络请求解析数据,只是方法不一样而已,但是,逻辑都是差不多的: 一:AsyncTask解析数据 AsyncTask主要用来更新UI线程,比较耗时的操作可以在AsyncTask中使用. AsyncTask是个抽象类,使用时需要继承这个

JAVA几种常见的编码格式(转)

简介 编码问题一直困扰着开发人员,尤其在 Java 中更加明显,因为 Java 是跨平台语言,不同平台之间编码之间的切换较多.本文将向你详细介绍 Java 中编码问题出现的根本原因,你将了解到:Java 中经常遇到的几种编码格式的区别:Java 中经常需要编码的场景:出现中文问题的原因分析:在开发 Java web 程序时可能会存在编码的几个地方,一个 HTTP 请求怎么控制编码格式?如何避免出现中文问题? 为什么要编码 不知道大家有没有想过一个问题,那就是为什么要编码?我们能不能不编码?要回答

Redis 的几种常见使用方式

常见使用方式 Redis 的几种常见使用方式包括: Redis 单副本 Redis 多副本(主从) Redis Sentinel(哨兵) Redis Cluster Redis 自研 各种使用方式的优缺点 Redis 单副本 Redis 单副本,采用单个 Redis 节点部署架构,没有备用节点实时同步数据,不提供数据持久化和备份策略,适用于数据可靠性要求不高的纯缓存业务场景. 优点: 架构简单,部署方便. 高性价比:缓存使用时无需备用节点(单实例可用性可以用 supervisor 或 cront

四种常见的数据结构、LinkedList、Set集合、Collection、Map总结

四种常见的数据结构:    1.堆栈结构:        先进后出的特点.(就像弹夹一样,先进去的在后进去的低下.)    2.队列结构:        先进先出的特点.(就像安检一样,先进去的先出来)    3.数组结构:        查找元素快,但是增删元素慢    4.链表结构:        增删元素快,但是查找元素慢 LinkedList:(List接口下的一个子类,和ArrayList是同级别关系)    1.底层是链表结构    2.它的一些特有方法:        addFir

爬虫学习 05.Python网络爬虫之三种数据解析方式

爬虫学习 05.Python网络爬虫之三种数据解析方式 引入 回顾requests实现数据爬取的流程 指定url 基于requests模块发起请求 获取响应对象中的数据 进行持久化存储 其实,在上述流程中还需要较为重要的一步,就是在持久化存储之前需要进行指定数据解析.因为大多数情况下的需求,我们都会指定去使用聚焦爬虫,也就是爬取页面中指定部分的数据值,而不是整个页面的数据.因此,本次课程中会给大家详细介绍讲解三种聚焦爬虫中的数据解析方式.至此,我们的数据爬取的流程可以修改为: 指定url 基于r

linux下几种常见安装方式

linux下几种常见的安装方式:1:rpm包安装(二进制安装)    安装---   rpm -ivh +安装包包名 2:tar包安装(源码安装)    安装---   tar zxvf(解压)---./configure(配置,编译前准备)---make(编译)---make install(安装)此过程中./configure后可以指定安装路径,也可不指定,不指定的话就类似于windows下的默认安装 3:yum安装(自动解决依赖关系)    安装---   yum install

java几种常见的排序算法总结

[java] view plain copy /*************几种常见的排序算法总结***************************/ package paixu; public class PaiXu { final int MAX=20; int num[]=new int[MAX]; { System.out.print("生成的随机数组是:"); for(int i=0;i<20;i++){ num[i]=(int)(Math.random()*100)

[2]工欲善其事必先利其器-------UML中的几种常见关系(二)

目录 1.UML类图中几种常见的关系 经过(一)中介绍,我选择的是StarUML作为UML的学习工具,个人喜好,至少在功能上能够满足我现在的需求, 在介绍StarUML的使用之前首先介绍下UML中几种常见的关系: UML类图中常见的关系按照关系的强弱可分为:泛化 ,实现 ,组合, 聚合 , 依赖这几种 1.泛化关系:是一种继承关系,也就是XX is a kind of XX 描述. 2.实现关系:是一种类与接口的关系. 3. 组合关系:是一种强关联,属于一种整体与部分的关系,但是部分不能离开整体