【问题标题】:Detecting if image is blurred using OpenCV使用 OpenCV 检测图像是否模糊
【发布时间】:2018-04-04 05:28:38
【问题描述】:

thisthis为参考,我将以下2个函数放在一起尝试检测图像是否模糊:

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

由于从相机拍摄的图像太大,我使用 BitmapRegionDecoder 获取其中的一部分,然后检查整个图像的那部分是否模糊。如果拉普拉斯算子的变化小于定义的阈值,则图像被声明为模糊,在本例中为 100(此值是从所附的第一篇文章中摘取的)。如果发现超过 50% 的图像“部分”模糊,则认为整个图像模糊。

经过测试,我发现结果不确定。我测试的大部分图像都被声明为模糊。我什至尝试改变所使用的拉普拉斯阈值的变化,但没有找到一个提供一致正确结果的值,这让我认为我做错了什么。

【问题讨论】:

  • 您好,您能否在问题中提供一张图片的缩影,以便我们轻松了解您面临的问题?

标签: android image opencv


【解决方案1】:

您可以使用以下方法来检测图像是否模糊。

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

【讨论】:

  • 此方法适用于小尺寸图像。但是,当我上传大尺寸图片时,应用程序崩溃了
  • 有点晚了,但如果您使用 OpenCV 的 onCameraFrame 方法,可以优化该方法的性能。在我的用例中,我已经有了一个转换后的灰色垫以及原始的 rgba 垫。可以省去很多位图转换:代码在下一条评论
  • isBlurredImage(Mat dst2, MatmatImageGrey) { 尝试 { 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(); [...]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-07
  • 2014-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-21
  • 2013-10-26
相关资源
最近更新 更多