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