图像放缩之双线性内插值

简介: 图像放缩之双线性内插值

一:数学原理


在临近点插值的数学基础上,双线性插值,不是简单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)

0_13197925873m7r.png


根据小数部分的(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;



四:程序运行效果如下

0_1319792608ZiNr.png




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



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

public class BilineInterpolationScale implements ImageScale {
  public BilineInterpolationScale() {
    
  }
  /**
   * 
   */
  @Override
  public int[] imgScale(int[] inPixelsData, int srcW, int srcH, int destW, int destH) {
    double[][][] input3DData = processOneToThreeDeminsion(inPixelsData, srcH, srcW);
    int[][][] outputThreeDeminsionData = new int[destH][destW][4];
    float rowRatio = ((float)srcH)/((float)destH);
    float colRatio = ((float)srcW)/((float)destW);
    for(int row=0; row<destH; row++) {
      // convert to three dimension data
      double srcRow = ((float)row)*rowRatio;
      double j = Math.floor(srcRow);
      double t = srcRow - j;
      for(int col=0; col<destW; col++) {
        double srcCol = ((float)col)*colRatio;
        double k = Math.floor(srcCol);
        double u = srcCol - k;
        double coffiecent1 = (1.0d-t)*(1.0d-u);
        double coffiecent2 = (t)*(1.0d-u);
        double coffiecent3 = t*u;
        double coffiecent4 = (1.0d-t)*u;
        
        
        outputThreeDeminsionData[row][col][0] = (int)(coffiecent1 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)k,srcW-1, 0)][0] +
        coffiecent2 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)k,srcW-1,0)][0] +
        coffiecent3 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)(k+1),srcW-1,0)][0] +
        coffiecent4 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)(k+1),srcW-1,0)][0]); // alpha
        
        outputThreeDeminsionData[row][col][1] = (int)(coffiecent1 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)k,srcW-1, 0)][1] +
            coffiecent2 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)k,srcW-1,0)][1] +
            coffiecent3 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)(k+1),srcW-1,0)][1] +
            coffiecent4 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)(k+1),srcW-1,0)][1]); // red
        
        outputThreeDeminsionData[row][col][2] = (int)(coffiecent1 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)k,srcW-1, 0)][2] +
            coffiecent2 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)k,srcW-1,0)][2] +
            coffiecent3 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)(k+1),srcW-1,0)][2] +
            coffiecent4 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)(k+1),srcW-1,0)][2]);// green
        
        outputThreeDeminsionData[row][col][3] = (int)(coffiecent1 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)k,srcW-1, 0)][3] +
            coffiecent2 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)k,srcW-1,0)][3] +
            coffiecent3 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)(k+1),srcW-1,0)][3] +
            coffiecent4 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)(k+1),srcW-1,0)][3]); // blue
      }
    }
    
    return convertToOneDim(outputThreeDeminsionData, destW, destH);
  }
  
  private int getClip(int x, int max, int min) {
    return x>max ? max : x<min? min : x;
  }
  
  /* <p> The purpose of this method is to convert the data in the 3D array of ints back into </p>
   * <p> the 1d array of type int. </p>
   * 
   */
  public int[] convertToOneDim(int[][][] data, int imgCols, int imgRows) {
    // Create the 1D array of type int to be populated with pixel data
    int[] oneDPix = new int[imgCols * imgRows * 4];
 
 
    // Move the data into the 1D array. Note the
    // use of the bitwise OR operator and the
    // bitwise left-shift operators to put the
    // four 8-bit bytes into each int.
    for (int row = 0, cnt = 0; row < imgRows; row++) {
      for (int col = 0; col < imgCols; col++) {
        oneDPix[cnt] = ((data[row][col][0] << 24) & 0xFF000000)
            | ((data[row][col][1] << 16) & 0x00FF0000)
            | ((data[row][col][2] << 8) & 0x0000FF00)
            | ((data[row][col][3]) & 0x000000FF);
        cnt++;
      }// end for loop on col
 
 
    }// end for loop on row
 
 
    return oneDPix;
  }// end convertToOneDim
  
  private double [][][] processOneToThreeDeminsion(int[] oneDPix2, int imgRows, int imgCols) {
    double[][][] tempData = new double[imgRows][imgCols][4];
    for(int row=0; row<imgRows; row++) {
      
      // per row processing
      int[] aRow = new int[imgCols];
      for (int col = 0; col < imgCols; col++) {
        int element = row * imgCols + col;
        aRow[col] = oneDPix2[element];
      }
      
      // convert to three dimension data
      for(int col=0; col<imgCols; col++) {
        tempData[row][col][0] = (aRow[col] >> 24) & 0xFF; // alpha
        tempData[row][col][1] = (aRow[col] >> 16) & 0xFF; // red
        tempData[row][col][2] = (aRow[col] >> 8) & 0xFF;  // green
        tempData[row][col][3] = (aRow[col]) & 0xFF;       // blue
      }
    }
    return tempData;
  }
 
 
}


相关文章
|
Java Unix 程序员
【OS Ctags】Vim 代码阅读工具 Ctags
【OS Ctags】Vim 代码阅读工具 Ctags
338 0
【OS Ctags】Vim 代码阅读工具 Ctags
|
消息中间件 Linux RocketMQ
【RocketMq】RocketMq 4.9.4 Windows-docker 部署
【RocketMq】RocketMq 4.9.4 Windows-docker 部署
717 0
【RocketMq】RocketMq 4.9.4 Windows-docker 部署
|
6月前
|
机器学习/深度学习 数据采集 数据可视化
Python数据分析,别再死磕Excel了!
Python数据分析,别再死磕Excel了!
285 2
|
11月前
|
数据采集 数据可视化 数据挖掘
利用Python自动化处理Excel数据:从基础到进阶####
本文旨在为读者提供一个全面的指南,通过Python编程语言实现Excel数据的自动化处理。无论你是初学者还是有经验的开发者,本文都将帮助你掌握Pandas和openpyxl这两个强大的库,从而提升数据处理的效率和准确性。我们将从环境设置开始,逐步深入到数据读取、清洗、分析和可视化等各个环节,最终实现一个实际的自动化项目案例。 ####
1987 10
|
10月前
|
数据可视化 数据挖掘 大数据
1.1 学习Python操作Excel的必要性
学习Python操作Excel在当今数据驱动的商业环境中至关重要。Python能处理大规模数据集,突破Excel行数限制;提供丰富的库实现复杂数据分析和自动化任务,显著提高效率。掌握这项技能不仅能提升个人能力,还能为企业带来价值,减少人为错误,提高决策效率。推荐从基础语法、Excel操作库开始学习,逐步进阶到数据可视化和自动化报表系统。通过实际项目巩固知识,关注新技术,为职业发展奠定坚实基础。
|
数据采集 Web App开发 测试技术
使用Selenium与WebDriver实现跨浏览器自动化数据抓取
在网络爬虫领域,Selenium与WebDriver是实现跨浏览器自动化数据抓取的利器。本文详细介绍了如何利用Selenium和WebDriver结合代理IP技术提升数据抓取的稳定性和效率。通过设置user-agent和cookie来模拟真实用户行为,避免被网站检测和阻止。文章提供了具体的代码示例,展示了如何配置代理IP、设置user-agent和cookie,并实现了跨浏览器的数据抓取。合理的参数配置能有效减少爬虫被封禁的风险,提高数据抓取效率。
1221 6
使用Selenium与WebDriver实现跨浏览器自动化数据抓取
|
前端开发 JavaScript Linux
分离前后端react和django3构建的应用
【6月更文挑战第4天】在本文中,我们介绍了如何设置React前端并连接到Django后端。并讨论了前后端分离的好处,并计划扩展API以支持更多HTTP操作和用户身份验证功能。
286 5
分离前后端react和django3构建的应用
|
存储 分布式计算 Hadoop
Hadoop 运行的三种模式
【8月更文挑战第31天】
1193 0
|
安全 Java API
【Java】已解决java.lang.SecurityException异常
【Java】已解决java.lang.SecurityException异常
2104 0
|
JavaScript
基于js和html的骰子游戏
基于js和html的骰子游戏
757 0