• 图像放缩------双线性内插值 分类: 视频图像处理 2015-07-24 09:17 24人阅读 评论(0) 收藏


    一:数学原理

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

    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-10)][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-10)][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-10)][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-10)][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. }  

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    语言基础
    进制转换
    ado属性扩展
    ado数据模型和数据访问类,泛型集合
    完整的修改和删除
    完整的删除
    修改
    类库
    接口
    抽象类
  • 原文地址:https://www.cnblogs.com/mao0504/p/4706383.html
Copyright © 2020-2023  润新知