2

I am building a scanner app, and trying to determine the "preview quality" from the preview callback of the camera. I want to customize the camera's AUTO_FLASH_MODE where it will be turned on if the environment is too dark.

How can I detect if there is a high average of dark pixels? This means (in preview) I am getting darkness and therefore need to turn on the camera's flash light.

VC.One
  • 14,790
  • 4
  • 25
  • 57
Bajrang Hudda
  • 3,028
  • 1
  • 36
  • 63
  • Actually i want to customize the camera's AUTO_FLASH_MODE and i found any darkness in environment (in pixels) then just turn on the flesh till my scanner is on. – Bajrang Hudda Mar 04 '16 at 06:44
  • 1
    I removed the **Flash** tag (read that tag's description before you use it). Anyways all pixels have a intensity value of 0 to 255... So 128 is halfway between fully bright (255) and dark (0). Decide what number means "too dark" for you and then check pixel values in the preview image by using a `for` loop in your code. Look up Histograms as well since that could be useful & faster than checking every single pixel. – VC.One Mar 04 '16 at 07:06
  • 1
    @VC.One how is looking up a histogram faster than checking every single pixel. How do you think a histogram is calculated? – Piglet Mar 04 '16 at 09:01
  • @VC.One and @ Pgilet i am new in android, i don't have much more idea to do so, i used this [http://stackoverflow.com/questions/25721410/how-to-detect-color-of-the-center-of-camera-streaming-in-android-without-opencv] – Bajrang Hudda Mar 04 '16 at 10:32
  • @piglet I hear you. I'm not an Android Dev (he tagged Flash) but usually a graphics programming system gives access to the histogram. Example by the time you see an image it already knows its histogram so why begin looping all-over again when you can just extract the known one. Anyways Android SDK is harsh, no such feature as `camera.getHistogram()` so a for-loop is the solution after all.. – VC.One Mar 04 '16 at 23:33

2 Answers2

1

Either find out how to access pixel values of your image and calculate the average intensity yourself or use any image processing library to do so.

Dark pixels have low values, bright pixels have high values. You want to calculate the average of all red, green and blue values divided by three times your pixel count. Define a threshold for when to turn on the flash, but keep in mind that you have to get a new exposure time then. Prefer flash over exposure time increase as long exposure times yield higher image noise.

Piglet
  • 27,501
  • 3
  • 20
  • 43
1

I tried this approach but i think it is taking unnecessary time of processing the bitmap and then get an average screen color,

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        Size cameraResolution = resolution;
        PreviewCallback callback = this.callback;
        if (cameraResolution != null && callback != null)
        {
            int format = camera.getParameters().getPreviewFormat();
            SourceData source = new SourceData(data, cameraResolution.width, cameraResolution.height, format, getCameraRotation());
            callback.onPreview(source);
            final int[] rgb = decodeYUV420SP(data, cameraResolution.width, cameraResolution.height);

            //Bitmap bmp =  decodeBitmap(source.getData());
            Bitmap bmp = Bitmap.createBitmap(rgb, cameraResolution.width, cameraResolution.height, Bitmap.Config.ARGB_8888);
            if (bmp != null)
            {
                //bmp = decodeBitmap(source.getData());
                ByteArrayOutputStream bytes = new ByteArrayOutputStream();
                // bmp.compress(Bitmap.CompressFormat.JPEG, 70, bytes);
                Bitmap resizebitmap = Bitmap.createBitmap(bmp,
                        bmp.getWidth() / 2, bmp.getHeight() / 2, 60, 60);

                int color = getAverageColor(resizebitmap);
                Log.i("Color Int", color + "");
                // int color = resizebitmap.getPixel(resizebitmap.getWidth()/2,resizebitmap.getHeight()/2);

                String strColor = String.format("#%06X", 0xFFFFFF & color);
                //String colorname = sColorNameMap.get(strColor);

                Log.d("strColor", strColor);
                Log.i("strColor", color + "");
                if(!mIsOn)
                {
                    if (color == -16777216 || color < -16777216)//minimum color code (full dark)
                    {

                        mIsOn = true;
                        setTorch(true);
                        Log.d("Yahooooo", "" + color);
                    }
                }

                Log.i("Pixel Value",
                        "Top Left pixel: " + Integer.toHexString(color));
            }
        }
        else
        {
            Log.d(TAG, "Got preview callback, but no handler or resolution available");
        }
    }
}
    private int[] decodeYUV420SP(byte[] yuv420sp, int width, int height)
   {
      final int frameSize = width * height;

    int rgb[]=new int[width*height];
    for (int j = 0, yp = 0; j < height; j++) {
        int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
        for (int i = 0; i < width; i++, yp++) {
            int y = (0xff & ((int) yuv420sp[yp])) - 16;
            if (y < 0) y = 0;
            if ((i & 1) == 0) {
                v = (0xff & yuv420sp[uvp++]) - 128;
                u = (0xff & yuv420sp[uvp++]) - 128;
            }

            int y1192 = 1192 * y;
            int r = (y1192 + 1634 * v);
            int g = (y1192 - 833 * v - 400 * u);
            int b = (y1192 + 2066 * u);

            if (r < 0) r = 0; else if (r > 262143) r = 262143;
            if (g < 0) g = 0; else if (g > 262143) g = 262143;
            if (b < 0) b = 0; else if (b > 262143) b = 262143;

            rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) &
                    0xff00) | ((b >> 10) & 0xff);


        }
    }
    return rgb;
}

    private int getAverageColor(Bitmap bitmap)
    {
    int redBucket = 0;
    int greenBucket = 0;
    int blueBucket = 0;
    int pixelCount = 0;

    for (int y = 0; y < bitmap.getHeight(); y++) {
        for (int x = 0; x < bitmap.getWidth(); x++) {
            int c = bitmap.getPixel(x, y);

            pixelCount++;
            redBucket += Color.red(c);
            greenBucket += Color.green(c);
            blueBucket += Color.blue(c);
            // does alpha matter?
        }
    }

    int averageColor = Color.rgb(redBucket / pixelCount, greenBucket
            / pixelCount, blueBucket / pixelCount);
    return averageColor;
}
Bajrang Hudda
  • 3,028
  • 1
  • 36
  • 63
  • I'm no android expert. I'm sure there is a way to get the byte data of your preview image. Isn't it your byte array "data" in this function anyway? You use it as input for the Bitmap decoding.... If not I suggest you create a new simple question here: How to get pixel values from Android camera, or google for it... I guess your title here is a bit vague. – Piglet Mar 04 '16 at 11:47