2

I am new to android ndk.I have started learning through the image processing example by ruckus and by IBM blog. I am trying to graying out an image. Here is the code i am using

An xml file for the layout shown

<?xml version="1.0" encoding="utf-8"?>
  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"  
  >
    <ImageView
      android:id="@+id/gimageView1"
      android:layout_width="400px"
      android:src="@drawable/wallace"
      android:layout_height="266px"
    />

    <Button
      android:id="@+id/gbutton"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:text="Go Gray"
    />

    <ImageView
      android:id="@+id/gimageView2"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
    />
  </LinearLayout>

and the java code is

package com.example;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class GrayClass extends Activity {
      private ImageView imageView;
      private Bitmap bitmap;
      private Button button;
      private Bitmap original;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.gray);
      original  = BitmapFactory.decodeResource(getResources(), R.drawable.wallace);
      bitmap    = BitmapFactory.decodeResource(getResources(), R.drawable.wallace);
      button    = (Button) findViewById(R.id.gbutton);
      imageView = (ImageView) findViewById(R.id.gimageView2);
      button.setOnClickListener(new OnClickListener() {

      public void onClick(View v) {
            ((ImageView)findViewById(R.id.gimageView1)).setVisibility(View.GONE);
            button.setVisibility(View.GONE);
              GoGray();     
      }

    });

  }

  private void GoGray() {
        Bitmap oBitmap = original.copy(Bitmap.Config.ARGB_8888, true);
        Bitmap gBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);

        goGrayWithNative(oBitmap,gBitmap );
        imageView.setImageBitmap(gBitmap);

  }

  public native void goGrayWithNative(Bitmap bmp1, Bitmap bmp2);
}

and here is the .c file where i have written the code for gray out logic

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

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

    if (infocolor.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
        LOGE("Bitmap format is not RGBA_8888 !");
        return;
    }


LOGE("Bitmap format is not RGBA_8888 !====%d==", infocolor.format ) ;




    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
    LOGI("unlocking pixels height = %d",infocolor.height);
    for(y=0;y<infocolor.height;y++) {
    LOGI("unlocking pixels height = %d",infocolor.width);
        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("unlocking pixels");
    AndroidBitmap_unlockPixels(env, bitmapcolor);
    AndroidBitmap_unlockPixels(env, bitmapgray);


}

The code is running fine but output i am getting is different see the picsenter image description here

after clicking the GoGray button it shows image like this

enter image description here

Can anyone tell me where the mistake is ?

Alejandro Galera
  • 3,445
  • 3
  • 24
  • 42
anshul
  • 982
  • 1
  • 11
  • 33

2 Answers2

4

As far as i know, Android bitmaps can only handle 32-bit-per-pixel images, so you have to store the grayscale result as if it where a color image, by repeating the gray value in the red, green and blue channels, setting the alpha channel to fully opaque.

By the way if you analyze your screenshots, you'll realize that the grayscale version has a width of precisely 1/4 of the color image, which tends to show this is the problem.

Using this code in the C++ part should do the job:

// modify pixels with image processing algorithm
LOGI("unlocking pixels height = %d",infocolor.height);
for(y=0;y<infocolor.height;y++) {
LOGI("unlocking pixels height = %d",infocolor.width);
    argb * line = (argb *) pixelscolor;
    argb * grayline = (argb *) pixelsgray;

    for(x=0;x<infocolor.width;x++) {

        uint8_t v = 0.3 * line[x].red + 0.59 * line[x].green + 0.11*line[x].blue;
        grayline[x].red = v;
        grayline[x].green = v;
        grayline[x].blue = v;
        grayline[x].alpha = line[x].alpha
    }
    pixelscolor = (char *)pixelscolor + infocolor.stride;
    pixelsgray = (char *) pixelsgray + infogray.stride;
}

Hope this helps!

mbrenon
  • 4,851
  • 23
  • 25
  • Thanks for the valueable reply. As I am not a C / C++ guy i don't understand how can i store the grayscale result as if it where a color image, by repeating the gray value in the red, green and blue channels, setting the alpha channel to fully opaque? – anshul Oct 19 '12 at 13:08
  • Edited my answer to push some code. I'm more a C addict than a C++ fan, so this may require a little tweaking but i guess we're not far from it. Keep me posted! – mbrenon Oct 19 '12 at 13:36
  • Ok thanks i ll try this out and let you know about the progress. – anshul Oct 22 '12 at 05:36
  • @mbrenon m just a little curious, what is the difference between grayline[x] = 0.3 * line[x].red + 0.59 * line[x].green + 0.11*line[x].blue; and declaring v and then assigning it to all the channels? I have an issue with inversion, when only 1/4 of the image is inverted ,may be this could help ? – Rat-a-tat-a-tat Ratatouille Feb 16 '14 at 09:45
  • @mbrenon I have made some minor changes in Native function and it returned me an image with grayscale effect but the image losing its brightness.I am not able to figure out what is wrong.Can you please help me to get rid of this? http://stackoverflow.com/questions/22915293/apply-grayscale-effect-to-image-using-ndkc-c-in-android – AndroidLearner Apr 08 '14 at 07:16
0

I cannot help you with NDK but I'm pretty sure you can create a Grey image with normal Android SDK.

Ridcully
  • 23,362
  • 7
  • 71
  • 86