图像放缩------双线性内插值

一:数学原理

在临近点插值的数学基础上,双线性插值,不是简单copy源像素的值,而是获取四个最邻

近目标像素的像素值乘以权重系数,简单的数学公式可以表示为:

D(x, y) = S(j, k) * a + S(j+1, k) *b + S(j+1,k+1) * c + S(j, K+1) * d             公式一

 

问题转化如何提取源像素的中四个临近点,根据临近点插值中从目标像素寻找最临近的源像

素点的方法:

Sx= Dx * (Sh/Dh) // row

Sy= Dy * (Sw/Dw) // column

公式的详细说明参见这里http://blog.csdn.net/jia20003/article/details/6907152

计算出来的值是浮点数坐标,分别取整数部分坐标为(j, k), 小数部分坐标为(t, u)

根据小数部分的(t,u)坐标,首先进行水平方向的权重计算得出

Q11 = S(j,k) * (1-t) + S(j, k+1) * t;

Q22 = S(j+1, k) * (1-t) + S(j+1,K+1) *t

利用Q11, Q22的值,进行垂直方向权重计算得出计算采样点值

D(x, y) = Q11*(1-u) + Q22 * u; 把Q11, Q22带入,最终有等式:

D(x, y) = S(j, k) *(1-t)*(1-u) + S(j, k+1)*t*(1-u) + S(j+1,k)*(1-t)*u + S(j+1,k+1)*t*u

从而得出四个对应的权重系数分别为:

a = (1-t)*(1-u)

b = (1-t)*u

c = t*u

d = t*(1-u)

带入公式一,即可得出目标像素的值。

 

二:双线性内插值算法优缺点

双线性内插值算法在图像的放缩处理中,具有抗锯齿功能, 是最简单和常见的图像放缩算法,但是双线性内插值算法没有考虑边缘和图像的梯度变化,相比之下双立方插值算法更好解决这些问题。

 

三:关键程序代码解析

根据目标像素坐标,计算采样点浮点数坐标的代码如下:

float rowRatio = ((float)srcH)/((float)destH);

float colRatio = ((float)srcW)/((float)destW);

double srcRow = ((float)row)*rowRatio;

double srcCol = ((float)col)*colRatio;

 

计算采样点的整数坐标和小数部分坐标代码如下:

double j = Math.floor(srcRow);

double t = srcRow – j

double k = Math.floor(srcCol);

double u = srcCol - k;

 

根据小数坐标(t,u)来计算四个相邻像素点权重系数代码如下:

double coffiecent1 = (1.0d-t)*(1.0d-u);

double coffiecent2 = (t)*(1.0d-u);

double coffiecent3 = t*u;

double coffiecent4 = (1.0d-t)*u;

 

处理边缘像素代码如下:

return x>max ? max : x<min? min : x;

 

四:程序运行效果如下


左边为源图像,右边为基于双线性内插值放大两倍以后的图像

五:双线性内插值JAVA算法代码

[java] view plaincopy

  1. public class BilineInterpolationScale implements ImageScale {  
  2.     public BilineInterpolationScale() {  
  3.           
  4.     }  
  5.     /** 
  6.      *  
  7.      */  
  8.     @Override  
  9.     public int[] imgScale(int[] inPixelsData, int srcW, int srcH, int destW, int destH) {  
  10.         double[][][] input3DData = processOneToThreeDeminsion(inPixelsData, srcH, srcW);  
  11.         int[][][] outputThreeDeminsionData = new int[destH][destW][4];  
  12.         float rowRatio = ((float)srcH)/((float)destH);  
  13.         float colRatio = ((float)srcW)/((float)destW);  
  14.         for(int row=0; row<destH; row++) {  
  15.             // convert to three dimension data  
  16.             double srcRow = ((float)row)*rowRatio;  
  17.             double j = Math.floor(srcRow);  
  18.             double t = srcRow - j;  
  19.             for(int col=0; col<destW; col++) {  
  20.                 double srcCol = ((float)col)*colRatio;  
  21.                 double k = Math.floor(srcCol);  
  22.                 double u = srcCol - k;  
  23.                 double coffiecent1 = (1.0d-t)*(1.0d-u);  
  24.                 double coffiecent2 = (t)*(1.0d-u);  
  25.                 double coffiecent3 = t*u;  
  26.                 double coffiecent4 = (1.0d-t)*u;  
  27.                   
  28.                   
  29.                 outputThreeDeminsionData[row][col][0] = (int)(coffiecent1 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)k,srcW-1, 0)][0] +  
  30.                 coffiecent2 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)k,srcW-1,0)][0] +  
  31.                 coffiecent3 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)(k+1),srcW-1,0)][0] +  
  32.                 coffiecent4 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)(k+1),srcW-1,0)][0]); // alpha  
  33.                   
  34.                 outputThreeDeminsionData[row][col][1] = (int)(coffiecent1 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)k,srcW-1, 0)][1] +  
  35.                         coffiecent2 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)k,srcW-1,0)][1] +  
  36.                         coffiecent3 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)(k+1),srcW-1,0)][1] +  
  37.                         coffiecent4 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)(k+1),srcW-1,0)][1]); // red  
  38.                   
  39.                 outputThreeDeminsionData[row][col][2] = (int)(coffiecent1 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)k,srcW-1, 0)][2] +  
  40.                         coffiecent2 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)k,srcW-1,0)][2] +  
  41.                         coffiecent3 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)(k+1),srcW-1,0)][2] +  
  42.                         coffiecent4 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)(k+1),srcW-1,0)][2]);// green  
  43.                   
  44.                 outputThreeDeminsionData[row][col][3] = (int)(coffiecent1 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)k,srcW-1, 0)][3] +  
  45.                         coffiecent2 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)k,srcW-1,0)][3] +  
  46.                         coffiecent3 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)(k+1),srcW-1,0)][3] +  
  47.                         coffiecent4 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)(k+1),srcW-1,0)][3]); // blue  
  48.             }  
  49.         }  
  50.           
  51.         return convertToOneDim(outputThreeDeminsionData, destW, destH);  
  52.     }  
  53.       
  54.     private int getClip(int x, int max, int min) {  
  55.         return x>max ? max : x<min? min : x;  
  56.     }  
  57.       
  58.     /* <p> The purpose of this method is to convert the data in the 3D array of ints back into </p> 
  59.      * <p> the 1d array of type int. </p> 
  60.      *  
  61.      */  
  62.     public int[] convertToOneDim(int[][][] data, int imgCols, int imgRows) {  
  63.         // Create the 1D array of type int to be populated with pixel data  
  64.         int[] oneDPix = new int[imgCols * imgRows * 4];  
  65.   
  66.   
  67.         // Move the data into the 1D array. Note the  
  68.         // use of the bitwise OR operator and the  
  69.         // bitwise left-shift operators to put the  
  70.         // four 8-bit bytes into each int.  
  71.         for (int row = 0, cnt = 0; row < imgRows; row++) {  
  72.             for (int col = 0; col < imgCols; col++) {  
  73.                 oneDPix[cnt] = ((data[row][col][0] << 24) & 0xFF000000)  
  74.                         | ((data[row][col][1] << 16) & 0x00FF0000)  
  75.                         | ((data[row][col][2] << 8) & 0x0000FF00)  
  76.                         | ((data[row][col][3]) & 0x000000FF);  
  77.                 cnt++;  
  78.             }// end for loop on col  
  79.   
  80.   
  81.         }// end for loop on row  
  82.   
  83.   
  84.         return oneDPix;  
  85.     }// end convertToOneDim  
  86.       
  87.     private double [][][] processOneToThreeDeminsion(int[] oneDPix2, int imgRows, int imgCols) {  
  88.         double[][][] tempData = new double[imgRows][imgCols][4];  
  89.         for(int row=0; row<imgRows; row++) {  
  90.               
  91.             // per row processing  
  92.             int[] aRow = new int[imgCols];  
  93.             for (int col = 0; col < imgCols; col++) {  
  94.                 int element = row * imgCols + col;  
  95.                 aRow[col] = oneDPix2[element];  
  96.             }  
  97.               
  98.             // convert to three dimension data  
  99.             for(int col=0; col<imgCols; col++) {  
  100.                 tempData[row][col][0] = (aRow[col] >> 24) & 0xFF; // alpha  
  101.                 tempData[row][col][1] = (aRow[col] >> 16) & 0xFF; // red  
  102.                 tempData[row][col][2] = (aRow[col] >> 8) & 0xFF;  // green  
  103.                 tempData[row][col][3] = (aRow[col]) & 0xFF;       // blue  
  104.             }  
  105.         }  
  106.         return tempData;  
  107.     }  
  108.   
  109.   
  110. }  
时间: 2024-09-23 06:30:26

图像放缩------双线性内插值的相关文章

图像放缩------临近点插值

一:数学原理 当一幅二维数字图像从源图像N*M被放为(j*N) * (k*M)目标图像是,参照数学斜率计算公式 必然有: (X1 – Xmin)/(Xmax - Xmin) = (Y1 - Ymin)/(Ymax-Ymin)   当Xmin 和 Ymin均为从零开始的像素点时,公式可以简化为:          X=Y1 (Xmax/Ymax)   对于任意一幅源图像来说,假设放大后目标图像的宽为Dw高为Dh,任意目标像素点(Dx, Dy) 在源图像上的位置为:          Sx= Dx

图像放缩------双立方插值

一:数学原理 如果已知一个函数f(x)以及它在x=0,x=1处的导数,那么函数可以在[0,1]之间插值,当函数 表达为三次多项式时我们称之谓立方插值.一个三次多项式及其导数:         f(x) =ax^3 +bx^2 + cx + d          f'(x)=3ax^2 + 2bx +c 多项式在x=0, x=1处值及其导数值为:          f(0)= d;          f(1)= a + b + c + d;          f'(0)=c          f'

《数字图像处理与机器视觉——Visual C++与Matlab实现》——1.5 图像的显示

1.5 图像的显示 数字图像处理与机器视觉--Visual C++与Matlab实现一般使用imshow函数来显示图像,该函数可以创建一个图像对象,并可以自动设置图像的诸多属性,从而简化编程操作.这里介绍imshow函数的几种常见调用方式. 1.imshow函数imshow函数用于显示工作区或图像文件中的图像,在显示的同时可控制部分效果(参见例12.6),常用的调用形式为: imshow(I, [low high], param1, value1, param2, value2, -) imsh

如何在两小时内搞懂PHOTOSHOP基础工具?

  初学者面对Photoshop这个庞然大物,第一直观感受是不知道从何下手.那么多工具,学完这个忘那个,有木有什么教程可以一次性学完呢?今天这篇好文,只要童鞋们打起精神来,两个小时就可以搞懂基础的工具使用!绝对是新手速成Photoshop的一个好机会!赶紧来学习! 教程很有意思,从A--Z 依次讲解每个工具的使用,精辟彻底,不拖泥带水呦. 3D面板:作为Adobe Photoshop Extended的一部分,你可以在Adobe Photoshop CC中找到它.3D面板中展示了所有3D文件中允

《Java数字图像处理:编程技巧与应用实践》——2.3 基于BufferedImageOp的图像滤镜演示

2.3 基于BufferedImageOp的图像滤镜演示 通过前面两节的学习,我们已经大致了解BufferedImageOp接口及其实现类的功能.实践出真知,本节将演示BufferedImageOp接口中每个实现类的实际使用场景,达到知行合一.学以致用的目的,帮助大家解决项目中遇到的实际问题.为了让大家对应用效果有更加深刻的印象,下面会使用BufferedImageOp的实现类来实现如下几个滤镜特效功能. 黑白滤镜:将彩色图像自动转换为黑白两色图像. 灰度滤镜:将彩色图像自动转换为灰度图像. 模

《Adobe After Effects CS6中文版经典教程》——1.3 创建合成图像与组织图层

1.3 创建合成图像与组织图层 工作流程中的下一步就是创建合成图像.所有动画.图层和特效都将在合成图像中创建.After Effects合成图像同时具有空间尺度和时间尺度(时长). 合成图像包含一个或多个图层,它们排列在合成图像面板和Timeline(时间线)面板中.添加到合成图像中的素材项-如静态图像.动画文件.音频文件.灯光图层.摄像图层,甚至是其他合成图像-都将成为一个新的图层.简单项目可能只包含一个合成图像,而一个精心制作的项目则可能包含几个合成图像,用以组织大量的素材或复杂的特效序列.

简单PS合成图像(抹去某个人等)

  1. 仿制图章工具(s)右键可以调节大小和硬度(越大越清晰),大面积修复时,一般比污点修复工具好用,让过度更加自然也是先按住alt键选择源点,仍然是是用上面是大括号下面是中括号的按键减小或者增大圆圈. 2.多边形套索工具(L)选择不规则图像会更方便. 3.有时往往有一种工具选择不完美,可以使用多种工具,如先用了多边形工具,选择加入到选区,再点击矩形工具等选择其他选区,则自动构成了一个选区. 4.涂抹的话,最好先选好需要涂抹的地方,否则会出现意想不到结果:边界的话必须用仿制图章工具,内部可用修

图像处理------噪声之美 - 随机噪声产生

数学原理: 首先看两张图片,大小均为256 * 256个像素, 第一张是纯蓝色 图一: 第二张是加有随机噪声的蓝色  图二: 产生随机噪声的算法简单的不能再简单了 假设RGB的R与G颜色分量均为零, 则 Blue = 255 * Math.Random() 随机数的取值范围在 [0, 1]之间, 程序的核心代码如下: for(int row=0; row<256; row++) {                             for(int col=0; col<256; col+

高密度环境下行人检测和统计

好文要转! 实验程序视频 下载 1 问题描述   高密度环境下的行人统计一直没有得到很好的解决,主要原因是对高密度人群中的行人检测和跟踪是一个很难的问题,如下图所示环境,存在的困难包括: 检测方面: 由于人群整体处于运动状态,占据了背景的60%以上的面积,导致许多目标检测的方法,如基于背景差的运动目标检测.分割方法难以奏效.另外,由于人群存在大量遮挡,导致基于行人轮廓的检测方法,如HOG也难以奏效. 跟踪方面: 高密度环境中的多目标跟踪,由于存在大量的遮挡.合并.分离,实现准确的跟踪是一个富有挑