3

Using this and this as reference, I put together the following 2 functions to attempt to detect whether an image is blurry or not:

public static boolean checkIfImageIsBlurred(BitmapRegionDecoder bitmapRegionDecoder) {
    if (bitmapRegionDecoder == null) {
        Timber.e("Expected bitmapRegionDecoder was null");
        return true;
    }

    int loadImageHeight = bitmapRegionDecoder.getHeight();
    int loadImageWidth = bitmapRegionDecoder.getWidth();

    int checkImageTopPosition = 0;
    int checkImageBottomPosition = loadImageHeight / 10;
    int checkImageLeftPosition = 0;
    int checkImageRightPosition = loadImageWidth / 10;

    int totalDividedRectangles = 0;
    int numberOfBlurredRectangles = 0;

    while ((checkImageRightPosition <= loadImageWidth) && (checkImageLeftPosition < checkImageRightPosition)) {
        while ((checkImageBottomPosition <= loadImageHeight) && (checkImageTopPosition < checkImageBottomPosition)) {
            Timber.d("left: " + checkImageLeftPosition + " right: " + checkImageRightPosition + " top: " + checkImageTopPosition + " bottom: " + checkImageBottomPosition);

            Rect rect = new Rect(checkImageLeftPosition,checkImageTopPosition,checkImageRightPosition,checkImageBottomPosition);
            totalDividedRectangles++;

            Bitmap processBitmap = bitmapRegionDecoder.decodeRegion(rect,null);

            if (checkIfImageIsBlurred(processBitmap)) {
                numberOfBlurredRectangles++;
            }

            checkImageTopPosition = checkImageBottomPosition;
            checkImageBottomPosition += (checkImageBottomPosition < (loadImageHeight - checkImageBottomPosition)) ? checkImageBottomPosition: (loadImageHeight - checkImageBottomPosition);
        }

        checkImageTopPosition = 0; //reset to start
        checkImageBottomPosition = loadImageHeight / 10; //reset to start
        checkImageLeftPosition = checkImageRightPosition;
        checkImageRightPosition += (checkImageRightPosition < (loadImageWidth - checkImageRightPosition)) ? checkImageRightPosition : (loadImageWidth - checkImageRightPosition);
    }

    Timber.d("blurred rectangles count = " + numberOfBlurredRectangles + ", total rectangles count = " + totalDividedRectangles);
    return numberOfBlurredRectangles > totalDividedRectangles * 0.50;
}

public static boolean checkIfImageIsBlurred(Bitmap bitmap) {
    if(bitmap == null) {
        Timber.e("Expected bitmap was null");
        return false;
    }

    Mat imageBitmapMat = new Mat(bitmap.getWidth(),bitmap.getHeight(),CvType.CV_8UC1);
    Utils.bitmapToMat(bitmap,imageBitmapMat);

    Mat grayscaleBitmapMat = new Mat();
    Imgproc.cvtColor(imageBitmapMat,grayscaleBitmapMat,Imgproc.COLOR_RGB2GRAY);

    Mat postLaplacianMat = new Mat();
    Imgproc.Laplacian(grayscaleBitmapMat,postLaplacianMat,3);

    MatOfDouble mean = new MatOfDouble();
    MatOfDouble standardDeviation = new MatOfDouble();
    Core.meanStdDev(postLaplacianMat,mean,standardDeviation);

    double result = Math.pow(standardDeviation.get(0,0)[0],2);
    Timber.d("blurry result = " + result);
    return result < 100;       
}

Since the images taken off the camera are too large, I use BitmapRegionDecoder to get parts of them and then check if that part of the entire image is blurry. An image is declared as blurry if the variation of the Laplacian is less than the threshold defined, which in this case is 100(This value was picked off from the first article attached). If more than 50% of the "parts" of the image are found to be blurry then the entire image is considered blurry.

Upon testing, I have found results to be inconclusive. Pretty much most of the images I put to the test are declared as blurry. I have even tried altering the variation of Laplacian threshold used but have not found a value that provided consistently correct results, which leads me to think that I am doing something wrong.

Bluesir9
  • 121
  • 5
  • 11
  • Hi, could you provide in you question a miniature of an image in order we can easily understand the problem that are you facing off? – Duloren Oct 24 '17 at 02:54

1 Answers1

3

You can be used below method that can detect image is blurry or not.

 private synchronized boolean isBlurredImage(Bitmap image) {
    try {
        if (image != null) {
            BitmapFactory.Options opt = new BitmapFactory.Options();
            opt.inDither = true;
            opt.inPreferredConfig = Bitmap.Config.ARGB_8888;
            int l = CvType.CV_8UC1;
            Mat matImage = new Mat();
            Utils.bitmapToMat(image, matImage);
            Mat matImageGrey = new Mat();
            Imgproc.cvtColor(matImage, matImageGrey, Imgproc.COLOR_BGR2GRAY);

            Mat dst2 = new Mat();
            Utils.bitmapToMat(image, dst2);

            Mat laplacianImage = new Mat();
            dst2.convertTo(laplacianImage, l);
            Imgproc.Laplacian(matImageGrey, laplacianImage, CvType.CV_8U);
            Mat laplacianImage8bit = new Mat();
            laplacianImage.convertTo(laplacianImage8bit, l);
            System.gc();

            Bitmap bmp = Bitmap.createBitmap(laplacianImage8bit.cols(),
                    laplacianImage8bit.rows(), Bitmap.Config.ARGB_8888);

            Utils.matToBitmap(laplacianImage8bit, bmp);

            int[] pixels = new int[bmp.getHeight() * bmp.getWidth()];
            bmp.getPixels(pixels, 0, bmp.getWidth(), 0, 0, bmp.getWidth(),
                    bmp.getHeight());
            if (bmp != null)
                if (!bmp.isRecycled()) {
                    bmp.recycle();

                }
            int maxLap = -16777216;

            for (int i = 0; i < pixels.length; i++) {

                if (pixels[i] > maxLap) {
                    maxLap = pixels[i];
                }
            }
            int soglia = -6118750;

            if (maxLap < soglia || maxLap == soglia) {


                return true;
            } else {


                return false;
            }
        } else {
            return false;
        }
    } catch (NullPointerException e) {
        return false;
    } catch (OutOfMemoryError e) {
        return false;
    }
}
Sanjay Bhalani
  • 2,424
  • 18
  • 44
  • this method working well for small size images. But, app crashed when i upload large size image – Vigneswaran A Feb 19 '18 at 09:45
  • a bit late to the party but the performance of the method can be optimised if you're working with the `onCameraFrame` method for OpenCV. In my use case i already had a converted gray Mat as well as the original rgba Mat. You can eliminate a lot of bitmap conversion: code in next comment – davy307 Mar 14 '19 at 17:23
  • isBlurredImage(Mat dst2, Mat matImageGrey) { try { if (dst2 != null && matImageGrey != null) { int l = CvType.CV_8UC1; Mat laplacianImage = new Mat(); dst2.convertTo(laplacianImage, l); Imgproc.Laplacian(matImageGrey, laplacianImage, CvType.CV_8U); Mat laplacianImage8bit = new Mat(); laplacianImage.convertTo(laplacianImage8bit, l); System.gc(); [...] – davy307 Mar 14 '19 at 17:23