Android 本机位图处理和ALPHA_8

Android 本机位图处理和ALPHA_8,android,android-ndk,Android,Android Ndk,我正在尝试通过一个本机函数将图像转换为灰度,使用一段来自Android in Action(第二版;您也可以看到它)的代码。不幸的是,返回的位图对象(而不是灰度)最终为空 以下是加载(.png)图像的方式: 位图通过了许多安全条件(请在下面检查)。以下是Java中的本机函数定义: public native void convertToGray(Bitmap bitmapIn,Bitmap bitmapOut); 电话: // Grayscale bitmap (initially empty

我正在尝试通过一个本机函数将图像转换为灰度,使用一段来自Android in Action(第二版;您也可以看到它)的代码。不幸的是,返回的位图对象(而不是灰度)最终为空

以下是加载(.png)图像的方式:

位图通过了许多安全条件(请在下面检查)。以下是Java中的本机函数定义:

public native void convertToGray(Bitmap bitmapIn,Bitmap bitmapOut);
电话:

// Grayscale bitmap (initially empty)     
Bitmap gray = Bitmap.createBitmap(original.getWidth(),original.getHeight(),Config.ALPHA_8);
// Native function call
convertToGray(original,gray);
下面是函数:

JNIEXPORT void JNICALL Java_com_example_Preprocessor_convertToGray(JNIEnv * env, jobject  obj, jobject bitmapcolor,jobject bitmapgray)
{
    AndroidBitmapInfo infocolor;
    AndroidBitmapInfo infogray; 
    void* pixelscolor;
    void* pixelsgray;
    int ret;
    int y;
    int x;    

    LOGI("convertToGray");
    if ((ret = AndroidBitmap_getInfo(env, bitmapcolor, &infocolor)) < 0) {
        LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
        return;
    }    

    if ((ret = AndroidBitmap_getInfo(env, bitmapgray, &infogray)) < 0) {
        LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
        return;
    }

    LOGI("color image :: width is %d; height is %d; stride is %d; format is %d;flags is %d",infocolor.width,infocolor.height,infocolor.stride,infocolor.format,infocolor.flags);
    if (infocolor.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
        LOGE("Bitmap format is not RGBA_8888 !");
        return;
    }  

    LOGI("gray image :: width is %d; height is %d; stride is %d; format is %d;flags is %d",infogray.width,infogray.height,infogray.stride,infogray.format,infogray.flags);
    if (infogray.format != ANDROID_BITMAP_FORMAT_A_8) {
        LOGE("Bitmap format is not A_8 !");
        return;
    }   

    if ((ret = AndroidBitmap_lockPixels(env, bitmapcolor, &pixelscolor)) < 0) {
        LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
    }

    if ((ret = AndroidBitmap_lockPixels(env, bitmapgray, &pixelsgray)) < 0) {
        LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
    }

    // modify pixels with image processing algorithm
    for (y=0;y<infocolor.height;y++) {
        argb * line = (argb *) pixelscolor;
        uint8_t * grayline = (uint8_t *) pixelsgray;
        for (x=0;x<infocolor.width;x++) {
            grayline[x] = 0.3 * line[x].red + 0.59 * line[x].green + 0.11*line[x].blue;
        }

        pixelscolor = (char *)pixelscolor + infocolor.stride;
        pixelsgray = (char *) pixelsgray + infogray.stride;
    }

    LOGI("Done! Unlocking pixels...");
    AndroidBitmap_unlockPixels(env, bitmapcolor);
    AndroidBitmap_unlockPixels(env, bitmapgray);
}
JNIEXPORT void JNICALL Java_com_示例_预处理器_convertToGray(JNIEnv*env、jobject obj、jobject bitmapcolor、jobject bitmapgray)
{
AndroidBitmapInfo信息颜色;
AndroidBitmapInfo信息灰色;
void*像素颜色;
void*像素射线;
int ret;
int-y;
int x;
物流(“convertToGray”);
if((ret=AndroidBitmap_getInfo(env、bitmapcolor和infocolor))<0){
LOGE(“AndroidBitmap_getInfo()失败!错误=%d”,ret);
返回;
}    
if((ret=AndroidBitmap_getInfo(env、bitmapgray和infogray))<0){
LOGE(“AndroidBitmap_getInfo()失败!错误=%d”,ret);
返回;
}
LOGI(“彩色图像::宽度为%d;高度为%d;步幅为%d;格式为%d;标志为%d”,infocolor.width,infocolor.height,infocolor.stride,infocolor.format,infocolor.flags);
如果(infocolor.format!=ANDROID\u位图\u格式\u RGBA\u 8888){
LOGE(“位图格式不是RGBA_8888!”);
返回;
}  
LOGI(“灰色图像::宽度为%d;高度为%d;步幅为%d;格式为%d;标志为%d”,infogray.width,infogray.height,infogray.stride,infogray.format,infogray.flags);
if(infogray.format!=ANDROID\u位图\u格式\u A\u 8){
LOGE(“位图格式不是A_8!”);
返回;
}   
if((ret=AndroidBitmap_lockPixels(env、bitmapcolor和pixelscolor))<0){
LOGE(“AndroidBitmap_lockPixels()失败!错误=%d”,ret);
}
if((ret=AndroidBitmap_lockPixels(env、bitmapgray和pixelsgray))<0){
LOGE(“AndroidBitmap_lockPixels()失败!错误=%d”,ret);
}
//用图像处理算法修改像素
对于(y=0;y我也有类似的问题。
首先,我对infogray使用android RGBA_8888格式,而不是A_8(原始位图是使用ARGB_8888格式创建的)。
然后,如果对灰度线使用argb struct而不是uint_8,则可以按如下方式填充像素:

for (y = 0; y < infocolor.height; ++y) {
       argb* line = (argb*) pixelscolor;
       argb* grayline = (argb*) pixelsgray;
       for (x = 0; x < infocolor.width; ++x) {         
          grayline[x].red = grayline[x].green = grayline[x].blue = 0.3 * line[x].red + 0.59 * line[x].green + 0.11 * line[x].blue;
       }
       pixelscolor = (char*)pixelscolor + infocolor.stride;
       pixelsgray = (char*)pixelsgray + infogray.stride;
   }
for(y=0;y
我也有同样的问题。 我没有尝试过让ALPHA_8正常工作,但是使用ARGB_8888解决了这个问题

顺便说一句,回复@white_pawn的评论(抱歉,我无法回复评论)

示例中的argb结构顺序错误。在我的模拟器或手机中, 将其转换为RGBA解决了这个问题(这可能是您的图像看起来是蓝色的原因,因为您使用alpa表示蓝色)。尽管我不确定此顺序是否取决于硬件

typedef struct
{
    uint8_t red;
    uint8_t green;
    uint8_t blue;
    uint8_t alpha;
} argb;

我也遇到了同样的问题,并发现了问题所在!当您使用APHA_8时,需要将背景更改为。\ffffffff

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffffff">


您是否考虑过尝试使用ByteBuffer作为输出?如果这样做有效,那么我们可以更确定AndroidBitmap是否有问题……还有
bitmapIn
bitmapOrig
original
同一个对象?我对JNI完全陌生,所以不,我没有尝试过。我会尝试一下,然后再报告。我我仍然会感谢一些可以加快过程的提示或指导。而且,是的,bitmapIn=bitmapOrig=original(对后两个很抱歉;我应该让它更清楚;修复了)。@SamuelAudet:好的,我试过了。结果是一个几乎空白的位图(带有黑色伪影的白色表面(随机黑点)).还有谁愿意试一试吗?你没有收到任何警告或日志中的任何内容吗?@SamuelAudet:没有,没有。格雷琳[x]计算肯定有效,因此,pixelsgray也应该使用正确的值填充。但是,bitmapgray仍然为空。它确实给出了一些结果,但输出图像是蓝色的。我希望使用_8来节省一些内存(我想尝试一些实时图像处理)。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffffff">