2011-10-01 7 views
6

sto cercando di convertire un'immagine in scala di grigi con una funzione nativa, utilizzando un pezzo di codice preso da Android in azione (2a ed .; si può anche vedere here). Sfortunatamente, l'oggetto bitmap restituito, anziché la scala di grigi, finisce vuoto.nativo di elaborazione bitmap e ALPHA_8

Questo è come mi caricare l'immagine (.png):

Bitmap original = BitmapFactory.decodeResource(this.getResources(), R.drawable.sample, options); 

C'è un certo numero di condizioni di sicurezza che il bitmap passa (si prega di controllare qui di seguito). Ecco la definizione nativa funzione in Java:

public native void convertToGray(Bitmap bitmapIn,Bitmap bitmapOut); 

e la chiamata:

// Grayscale bitmap (initially empty)  
Bitmap gray = Bitmap.createBitmap(original.getWidth(),original.getHeight(),Config.ALPHA_8); 
// Native function call 
convertToGray(original,gray); 

Ed ecco la funzione:

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

La bitmap colore viene passato in modo corretto, e la parte di elaborazione di il codice sembra funzionare correttamente, ma bitmapgray rimane vuoto. Immagino che mi manchi qualcosa di cruciale qui.

Ambiente di test: emulatore, v2.2. Con questa versione, la funzione funziona quando viene chiamato il codice nativo dal thread principale . Su un emulatore 2.3, la funzione non funziona indipendentemente dal thread che chiama il codice C o il modo in cui viene caricata la bitmap. NDK Android: 4b & 6b.

UPDATE # 1: Troverete il codice sorgente completo here.

UPDATE # 2: RGB_565 invece di ALPHA_8 fornisce alcuni risultati. Sembra che nemmeno setPixels() in Java funzioni per ALPHA_8 e sto riscontrando problemi con per trovare informazioni su questo tipo di configurazione. Ogni tipo di aiuto sarebbe molto apprezzato.

+0

Avete preso in considerazione cercando di utilizzare un ByteBuffer come output? Se funziona, potremmo essere più sicuri che ci sia qualcosa di sbagliato in AndroidBitmap ... Inoltre sono 'bitmapIn',' bitmapOrig' e 'original' lo stesso oggetto? –

+0

Sono completamente nuovo a JNI, quindi no, non l'ho provato. Darò un colpo e poi riferire. Sarei ancora grato per alcuni suggerimenti o indicazioni che potrebbero accelerare il processo. E sì, bitmapIn = bitmapOrig = original (mi dispiace per gli ultimi due, avrei dovuto renderlo più chiaro, corretto). –

+0

@ SamuelAudet: OK, ho provato [questo] (http://imrannazar.com/Augmented-Reality-with-the-Android-NDK:-Part-2). Il risultato è un bitmap * quasi * vuoto (una superficie bianca con artefatti neri (punti neri casuali)). Qualcun altro sarebbe così gentile da dare una possibilità? –

risposta

1

Ho avuto un problema simile. Prima di tutto, ho utilizzato il formato Android RGBA_8888 per infogray anziché A_8 (la bitmap originale è stata creata utilizzando il formato ARGB_8888). Poi, se si utilizza argb struct per grayline invece di uint_8, è possibile riempire i pixel in questo modo:

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

Bene, fornisce alcuni risultati, ma l'immagine di output è bluastra. Speravo di usare A_8 per risparmiare un po 'di memoria (mi piacerebbe provare l'elaborazione delle immagini in tempo reale). –

1

ho avuto gli stessi problemi. Non ho provato molto a far funzionare ALPHA_8 ma usare ARGB_8888 risolve il problema.

A proposito, in risposta a @ di white_pawn commento (mi dispiace non posso rispondere ai commenti)

La struct argb in IBM's esempio è in ordine sbagliato. nei miei emulatori o telefono, convertendolo in RGBA risolve il problema (questo è probabilmente il motivo per cui l'immagine sembra blu perché si usa alpa per il blu). Anche se non sono sicuro che questo ordine dipende dall'hardware.

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

Ho avuto lo stesso problema e ho scoperto che cosa è andato storto!Quando si utilizza APHA_8 è necessario cambiare sfondo al #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">