Android 正在尝试将双线性插值代码从Java转换为C/C++;安卓上 背景

Android 正在尝试将双线性插值代码从Java转换为C/C++;安卓上 背景,android,c++,image-processing,java-native-interface,argb,Android,C++,Image Processing,Java Native Interface,Argb,我制作了一个小型Android库,用于使用JNI(链接)处理位图 在很久以前,我做了一些双线性插值的代码,作为一种可能的图像缩放算法。该算法有点复杂,使用周围的像素来形成目标像素 问题 即使没有错误(没有编译错误和运行时错误),输出图像看起来也是这样(按x2缩放宽度): 代码 基本上,最初的Java代码使用SWT,只支持RGB,但Alpha通道也是如此。它以前工作得很好(尽管现在我看到它,它似乎在途中创建了很多对象) 以下是Java代码: /** class for resizing imag

我制作了一个小型Android库,用于使用JNI(链接)处理位图

在很久以前,我做了一些双线性插值的代码,作为一种可能的图像缩放算法。该算法有点复杂,使用周围的像素来形成目标像素

问题 即使没有错误(没有编译错误和运行时错误),输出图像看起来也是这样(按x2缩放宽度):

代码 基本上,最初的Java代码使用SWT,只支持RGB,但Alpha通道也是如此。它以前工作得很好(尽管现在我看到它,它似乎在途中创建了很多对象)

以下是Java代码:

/** class for resizing imageData using the Bilinear Interpolation method */
public class BilinearInterpolation
  {
  /** the method for resizing the imageData using the Bilinear Interpolation algorithm */
  public static void resize(final ImageData inputImageData,final ImageData newImageData,final int oldWidth,final int oldHeight,final int newWidth,final int newHeight)
    {
    // position of the top left pixel of the 4 pixels to use interpolation on
    int xTopLeft,yTopLeft;
    int x,y,lastTopLefty;
    final float xRatio=(float)newWidth/(float)oldWidth,yratio=(float)newHeight/(float)oldHeight;
    // Y color ratio to use on left and right pixels for interpolation
    float ycRatio2=0,ycRatio1=0;
    // pixel target in the src
    float xt,yt;
    // X color ratio to use on left and right pixels for interpolation
    float xcRatio2=0,xcratio1=0;
    // copy data from source image to RGB values:
    RGB rgbTopLeft,rgbTopRight,rgbBottomLeft=null,rgbBottomRight=null,rgbTopMiddle=null,rgbBottomMiddle=null;
    RGB[][] startingImageData;
    startingImageData=new RGB[oldWidth][oldHeight];
    for(x=0;x<oldWidth;++x)
      for(y=0;y<oldHeight;++y)
        {
        rgbTopLeft=inputImageData.palette.getRGB(inputImageData.getPixel(x,y));
        startingImageData[x][y]=new RGB(rgbTopLeft.red,rgbTopLeft.green,rgbTopLeft.blue);
        }
    // do the resizing:
    for(x=0;x<newWidth;x++)
      {
      xTopLeft=(int)(xt=x/xRatio);
      // when meeting the most right edge, move left a little
      if(xTopLeft>=oldWidth-1)
        xTopLeft--;
      if(xt<=xTopLeft+1)
        {
        // we are between the left and right pixel
        xcratio1=xt-xTopLeft;
        // color ratio in favor of the right pixel color
        xcRatio2=1-xcratio1;
        }
      for(y=0,lastTopLefty=Integer.MIN_VALUE;y<newHeight;y++)
        {
        yTopLeft=(int)(yt=y/yratio);
        // when meeting the most bottom edge, move up a little
        if(yTopLeft>=oldHeight-1)
          yTopLeft--;
        // we went down only one rectangle
        if(lastTopLefty==yTopLeft-1)
          {
          rgbTopLeft=rgbBottomLeft;
          rgbTopRight=rgbBottomRight;
          rgbTopMiddle=rgbBottomMiddle;
          rgbBottomLeft=startingImageData[xTopLeft][yTopLeft+1];
          rgbBottomRight=startingImageData[xTopLeft+1][yTopLeft+1];
          rgbBottomMiddle=new RGB((int)(rgbBottomLeft.red*xcRatio2+rgbBottomRight.red*xcratio1),(int)(rgbBottomLeft.green*xcRatio2+rgbBottomRight.green*xcratio1),(int)(rgbBottomLeft.blue*xcRatio2+rgbBottomRight.blue*xcratio1));
          }
        else if(lastTopLefty!=yTopLeft)
          {
          // we went to a totally different rectangle (happens in every loop start,and might happen more when making the picture smaller)
          rgbTopLeft=startingImageData[xTopLeft][yTopLeft];
          rgbTopRight=startingImageData[xTopLeft+1][yTopLeft];
          rgbTopMiddle=new RGB((int)(rgbTopLeft.red*xcRatio2+rgbTopRight.red*xcratio1),(int)(rgbTopLeft.green*xcRatio2+rgbTopRight.green*xcratio1),(int)(rgbTopLeft.blue*xcRatio2+rgbTopRight.blue*xcratio1));
          rgbBottomLeft=startingImageData[xTopLeft][yTopLeft+1];
          rgbBottomRight=startingImageData[xTopLeft+1][yTopLeft+1];
          rgbBottomMiddle=new RGB((int)(rgbBottomLeft.red*xcRatio2+rgbBottomRight.red*xcratio1),(int)(rgbBottomLeft.green*xcRatio2+rgbBottomRight.green*xcratio1),(int)(rgbBottomLeft.blue*xcRatio2+rgbBottomRight.blue*xcratio1));
          }
        lastTopLefty=yTopLeft;
        if(yt<=yTopLeft+1)
          {
          // color ratio in favor of the bottom pixel color
          ycRatio1=yt-yTopLeft;
          ycRatio2=1-ycRatio1;
          }
        // prepared all pixels to look at, so finally set the new pixel data
        newImageData.setPixel(x,y,inputImageData.palette.getPixel(new RGB((int)(rgbTopMiddle.red*ycRatio2+rgbBottomMiddle.red*ycRatio1),(int)(rgbTopMiddle.green*ycRatio2+rgbBottomMiddle.green*ycRatio1),(int)(rgbTopMiddle.blue*ycRatio2+rgbBottomMiddle.blue*ycRatio1))));
        }
      }
    }
  }
/**用于使用双线性插值方法调整图像数据大小的类*/
公共类双线性插值
{
/**使用双线性插值算法调整图像数据大小的方法*/
公共静态空白大小调整(最终图像数据输入图像数据、最终图像数据新图像数据、最终整数oldWidth、最终整数oldHeight、最终整数newWidth、最终整数newHeight)
{
//要使用插值的4个像素中左上角像素的位置
intxtopleft,yTopLeft;
int x,y,lastTopLefty;
最终浮动比率=(浮动)新宽度/(浮动)旧宽度,yratio=(浮动)新高度/(浮动)旧高度;
//用于插值的左右像素的Y颜色比
浮动Ycratio=0,Ycratio=0;
//src中的像素目标
浮动xt,yt;
//用于插值的左右像素的X颜色比
浮点数xcRatio2=0,xcratio1=0;
//将数据从源图像复制到RGB值:
RGB rgbTopLeft、rgbTopRight、rgbBottomLeft=null、rgbBottomRight=null、rgbTopMiddle=null、rgbBottomMiddle=null;
RGB[][]开始图像数据;
startingImageData=新RGB[oldWidth][oldHeight];
对于(x=0;xblue=((像素>>8)和0xff);
argb->alpha=(像素和0xff);
}
...
/**使用称为“双线性插值”的高质量算法缩放图像*///
JNIEXPORT void JNICALL Java\u com\u jni\u位图\u 1操作\u JNIBITMopholder\u JNISCALEBI位图(
JNIEnv*env,jobject对象,jobject句柄,uint32\u t newWidth,
uint32(新高度)
{
JniBitmap*JniBitmap=(JniBitmap*)env->GetDirectBufferAddress(句柄);
如果(jniBitmap->_storedBitmapPixels==NULL)
返回;
uint32\u t oldWidth=jniBitmap->\u bitmapInfo.width;
uint32\u t oldHeight=jniBitmap->\u bitmapInfo.height;
uint32*previousData=jniBitmap->\u存储的位图像素;
uint32_t*newBitmapPixels=新uint32_t[newWidth*newHeight];
//要使用插值的4个像素中左上角像素的位置
intxtopleft,yTopLeft;
int x,y,lastTopLefty;
浮动X比率=(浮动)新宽度/(浮动)旧宽度,Y比率=
(浮动)新高度/(浮动)旧高度;
//用于插值的左右像素的Y颜色比
浮动Ycratio=0,Ycratio=0;
//src中的像素目标
浮动xt,yt;
//用于插值的左右像素的X颜色比
浮点数xcRatio2=0,xcratio1=0;
ARGB rgbTopLeft、rgbTopRight、rgbBottomLeft、rgbBottomRight、rgbTopMiddle、,
RGBBottomidle,结果;
对于(x=0;x=oldWidth-1)
xTopLeft--;
如果(xt=旧高度-1)
--伊托普利夫特;
if(lastTopLefty==yTopLeft-1)
{
//我们只下了一个长方形
rgbTopLeft=rgbBottomLeft;
rgbToRight=rgbBottomRight;
rgbTopMiddle=rgbBottomMiddle;
//rgbBottomLeft=开始图像数据[xTopLeft][yTopLeft+1];
convertIntToArgb(
以前的数据[((yTopLeft+1)*oldWidth)+xTopLeft],
&rgbBottomLeft);
//rgbBottomRight=开始图像数据[xTopLeft+1][yTopLeft+1];
convertIntToArgb(
以前的数据[((yTopLeft+1)*旧宽度)
+(xTopLeft+1)],&rgbBottomRight);
rgbBottomMiddle.alpha=rgbBottomLeft.alpha*xcRatio2
+rgbBottomRight.alpha*xcratio1;
rgbBottomMiddle.red=rgbBottomLeft.red*xcRatio2
+rgbBottomRight.red*xcratio1;
rgbBottomMiddle.green=rgbBottomLeft.green*xcRatio2
+rgbBottomRight.green*xcratio1;
rgbBottomMiddle.blue=rgbBottomLeft.blue*xcRatio2
+rgbBottomRight.blue*xcratio1;
}
else if(lastTopLefty!=yTopLeft)
{
//我们转到了一个完全不同的矩形(在每个循环开始时都会发生,当图片变小时可能会发生更多)
//rgbTopLeft=开始图像数据[xTopLeft][yTopLeft];
convertIntToArgb(以前的数据[(yTopLeft*oldWidth)+xTopLeft],
&RGBtoplft);
//rgbTopRight=开始图像数据[xTopLeft+1][yTopLeft];
convertIntToArgb(
以前的数据[((yTopLeft+1)*oldWidth)+xTopLeft],
&rgbTopRight);
rgbTopMiddle.alpha=rgbTopLeft.alpha*xcRatio2
+rgbTopRight.alpha*xcratio1;
rgbTopMiddle.red=rgbTopLeft.red*xcRatio2
+rgbTopRight.red*xcratio1;
rgbTopMiddle.green=rgbTopLeft.green*xcRatio2
+rgbTopRight.green*xcratio1;
rgbTopMiddle.blue=rgbTopLeft.blue*xcRatio2
+rgbTopRight.blue*xcratio1;
//rgbBottomLeft=开始图像数据[xTopLeft][yTopLeft+1];
convertIntToArgb(
以前的数据[((yTopLeft+1)*oldWidth)+xTopLeft],
&rgbBottomLeft);
//rgbBottomRight=开始图像数据[xTopLeft+1][yTopLeft+1];
convertIntToArgb(
以前的数据[((yTopLeft+1)*旧宽度)
+(xTopLeft+1)],&rgbBottomRight);
rgbBottomMiddle.alpha=rgbBottomLeft.alpha*xcRatio2
+rgbBottomRight.alpha*xcratio1;
RGBBottomidle
typedef struct
    {
    uint8_t alpha, red, green, blue;
    } ARGB;

int32_t convertArgbToInt(ARGB argb)
    {
    return (argb.alpha) | (argb.red << 16) | (argb.green << 8)
        | (argb.blue << 24);
    }

void convertIntToArgb(uint32_t pixel, ARGB* argb)
    {
    argb->red = ((pixel >> 24) & 0xff);
    argb->green = ((pixel >> 16) & 0xff);
    argb->blue = ((pixel >> 8) & 0xff);
    argb->alpha = (pixel & 0xff);
    }

...

/**scales the image using a high-quality algorithm called "Bilinear Interpolation" */ //
JNIEXPORT void JNICALL Java_com_jni_bitmap_1operations_JniBitmapHolder_jniScaleBIBitmap(
    JNIEnv * env, jobject obj, jobject handle, uint32_t newWidth,
    uint32_t newHeight)
    {
    JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle);
    if (jniBitmap->_storedBitmapPixels == NULL)
    return;
    uint32_t oldWidth = jniBitmap->_bitmapInfo.width;
    uint32_t oldHeight = jniBitmap->_bitmapInfo.height;
    uint32_t* previousData = jniBitmap->_storedBitmapPixels;
    uint32_t* newBitmapPixels = new uint32_t[newWidth * newHeight];
    // position of the top left pixel of the 4 pixels to use interpolation on
    int xTopLeft, yTopLeft;
    int x, y, lastTopLefty;
    float xRatio = (float) newWidth / (float) oldWidth, yratio =
        (float) newHeight / (float) oldHeight;
    // Y color ratio to use on left and right pixels for interpolation
    float ycRatio2 = 0, ycRatio1 = 0;
    // pixel target in the src
    float xt, yt;
    // X color ratio to use on left and right pixels for interpolation
    float xcRatio2 = 0, xcratio1 = 0;
    ARGB rgbTopLeft, rgbTopRight, rgbBottomLeft, rgbBottomRight, rgbTopMiddle,
        rgbBottomMiddle, result;
    for (x = 0; x < newWidth; ++x)
    {
    xTopLeft = (int) (xt = x / xRatio);
    // when meeting the most right edge, move left a little
    if (xTopLeft >= oldWidth - 1)
        xTopLeft--;
    if (xt <= xTopLeft + 1)
        {
        // we are between the left and right pixel
        xcratio1 = xt - xTopLeft;
        // color ratio in favor of the right pixel color
        xcRatio2 = 1 - xcratio1;
        }
    for (y = 0, lastTopLefty = -30000; y < newHeight; ++y)
        {
        yTopLeft = (int) (yt = y / yratio);
        // when meeting the most bottom edge, move up a little
        if (yTopLeft >= oldHeight - 1)
        --yTopLeft;
        if (lastTopLefty == yTopLeft - 1)
        {
        // we went down only one rectangle
        rgbTopLeft = rgbBottomLeft;
        rgbTopRight = rgbBottomRight;
        rgbTopMiddle = rgbBottomMiddle;
        //rgbBottomLeft=startingImageData[xTopLeft][yTopLeft+1];
        convertIntToArgb(
            previousData[((yTopLeft + 1) * oldWidth) + xTopLeft],
            &rgbBottomLeft);
        //rgbBottomRight=startingImageData[xTopLeft+1][yTopLeft+1];
        convertIntToArgb(
            previousData[((yTopLeft + 1) * oldWidth)
                + (xTopLeft + 1)], &rgbBottomRight);
        rgbBottomMiddle.alpha = rgbBottomLeft.alpha * xcRatio2
            + rgbBottomRight.alpha * xcratio1;
        rgbBottomMiddle.red = rgbBottomLeft.red * xcRatio2
            + rgbBottomRight.red * xcratio1;
        rgbBottomMiddle.green = rgbBottomLeft.green * xcRatio2
            + rgbBottomRight.green * xcratio1;
        rgbBottomMiddle.blue = rgbBottomLeft.blue * xcRatio2
            + rgbBottomRight.blue * xcratio1;
        }
        else if (lastTopLefty != yTopLeft)
        {
        // we went to a totally different rectangle (happens in every loop start,and might happen more when making the picture smaller)
        //rgbTopLeft=startingImageData[xTopLeft][yTopLeft];
        convertIntToArgb(previousData[(yTopLeft * oldWidth) + xTopLeft],
            &rgbTopLeft);
        //rgbTopRight=startingImageData[xTopLeft+1][yTopLeft];
        convertIntToArgb(
            previousData[((yTopLeft + 1) * oldWidth) + xTopLeft],
            &rgbTopRight);
        rgbTopMiddle.alpha = rgbTopLeft.alpha * xcRatio2
            + rgbTopRight.alpha * xcratio1;
        rgbTopMiddle.red = rgbTopLeft.red * xcRatio2
            + rgbTopRight.red * xcratio1;
        rgbTopMiddle.green = rgbTopLeft.green * xcRatio2
            + rgbTopRight.green * xcratio1;
        rgbTopMiddle.blue = rgbTopLeft.blue * xcRatio2
            + rgbTopRight.blue * xcratio1;
        //rgbBottomLeft=startingImageData[xTopLeft][yTopLeft+1];
        convertIntToArgb(
            previousData[((yTopLeft + 1) * oldWidth) + xTopLeft],
            &rgbBottomLeft);
        //rgbBottomRight=startingImageData[xTopLeft+1][yTopLeft+1];
        convertIntToArgb(
            previousData[((yTopLeft + 1) * oldWidth)
                + (xTopLeft + 1)], &rgbBottomRight);
        rgbBottomMiddle.alpha = rgbBottomLeft.alpha * xcRatio2
            + rgbBottomRight.alpha * xcratio1;
        rgbBottomMiddle.red = rgbBottomLeft.red * xcRatio2
            + rgbBottomRight.red * xcratio1;
        rgbBottomMiddle.green = rgbBottomLeft.green * xcRatio2
            + rgbBottomRight.green * xcratio1;
        rgbBottomMiddle.blue = rgbBottomLeft.blue * xcRatio2
            + rgbBottomRight.blue * xcratio1;
        }
        lastTopLefty = yTopLeft;
        if (yt <= yTopLeft + 1)
        {
        // color ratio in favor of the bottom pixel color
        ycRatio1 = yt - yTopLeft;
        ycRatio2 = 1 - ycRatio1;
        }
        // prepared all pixels to look at, so finally set the new pixel data
        result.alpha = rgbTopMiddle.alpha * ycRatio2
            + rgbBottomMiddle.alpha * ycRatio1;
        result.blue = rgbTopMiddle.blue * ycRatio2
            + rgbBottomMiddle.blue * ycRatio1;
        result.red = rgbTopMiddle.red * ycRatio2
            + rgbBottomMiddle.red * ycRatio1;
        result.green = rgbTopMiddle.green * ycRatio2
            + rgbBottomMiddle.green * ycRatio1;
        newBitmapPixels[(y * newWidth) + x] = convertArgbToInt(result);
        }
    }
    //get rid of old data, and replace it with new one
    delete[] previousData;
    jniBitmap->_storedBitmapPixels = newBitmapPixels;
    jniBitmap->_bitmapInfo.width = newWidth;
    jniBitmap->_bitmapInfo.height = newHeight;
    }