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.