transformaciones interpolacion impresoras imagenes geometricas doble cubica cuadratica bilineal algoritmo android c++ image-processing jni argb

interpolacion - Intentando convertir código de interpolación bilineal de Java a C/C++ en Android



interpolacion opencv (1)

Fondo

Creé una pequeña biblioteca de Android para manejar mapas de bits usando JNI (enlace aquí )

En el pasado, hice un código de interpolación bilineal como posible algoritmo para escalar imágenes. El algoritmo es un poco complejo y usa píxeles para formar el píxel objetivo.

El problema

Aunque no hay errores (sin errores de compilación y sin errores de tiempo de ejecución), la imagen de salida se ve así (escalado el ancho en x2):

El código

Básicamente, el código original de Java usaba SWT y solo soportaba RGB, pero es lo mismo para el canal Alpha. Funcionó antes perfectamente (aunque ahora que lo miro, parece crear muchos objetos en el camino).

Aquí está el código de 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)))); } } } }

Y aquí está el código C / C ++ que he intentado hacer con él:

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; }

La pregunta

¿Qué estoy haciendo mal?

¿También es posible hacer que el código sea un poco más legible? Estoy un poco oxidado en C / C ++ y era más un desarrollador C que un desarrollador C ++.

EDITAR: ahora funciona bien. He editado y reparado el código.

Lo único que ustedes pueden ayudar es dar consejos sobre cómo mejorarlo.


OK, todo comenzó con una mala conversión de los colores, luego pasó al uso de punteros y luego al básico de dónde colocar los píxeles.

El código que he escrito ahora funciona bien (agregó todas las correcciones necesarias).

Pronto todos podrán usar el nuevo código en el proyecto Github.