【问题标题】:Why is the blurry image getting a better variance of laplacian score?为什么模糊图像的拉普拉斯分数方差更好?
【发布时间】:2020-06-28 13:32:37
【问题描述】:

以下代码在大多数情况下会在一组图像中找到最佳焦点图像,但在某些图像中,它会为我的眼睛更模糊的图像返回更高的值。

我在 Linux 和/或 Mac 上使用 OpenCV 3.4.2。

import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;

import static org.opencv.core.Core.BORDER_DEFAULT;

public class LaplacianExample {

    public static Double calcSharpnessScore(Mat srcImage) {

        /// Remove noise with a Gaussian filter
        Mat filteredImage = new Mat();
        Imgproc.GaussianBlur(srcImage, filteredImage, new Size(3, 3), 0, 0, BORDER_DEFAULT);


        int kernel_size = 3;
        int scale = 1;
        int delta = 0;
        Mat lplImage = new Mat();
        Imgproc.Laplacian(filteredImage, lplImage, CvType.CV_64F, kernel_size, scale, delta, Core.BORDER_DEFAULT);

        // converting back to CV_8U generate the standard deviation
        Mat absLplImage = new Mat();
        Core.convertScaleAbs(lplImage, absLplImage);

        // get the standard deviation of the absolute image as input for the sharpness score
        MatOfDouble median = new MatOfDouble();
        MatOfDouble std = new MatOfDouble();
        Core.meanStdDev(absLplImage, median, std);

        return Math.pow(std.get(0, 0)[0], 2);
    }

}

这是两张使用相同照明(荧光,DAPI)的图像,从显微镜载玻片下方拍摄,同时尝试自动对焦于载玻片顶部表面的涂层/掩模。

我希望有人可以向我解释为什么我的算法无法检测到不太模糊的图像。谢谢!

【问题讨论】:

    标签: java opencv imaging autofocus laplacian


    【解决方案1】:

    主要问题是拉普拉斯内核尺寸太小

    你使用的是kernel_size = 3,对于上面的场景来说太小了。
    在上面的图像中,kernel_size = 3 主要受噪声的影响,因为边缘(在显示更多细节的图像中)远大于 3x3 像素。

    换句话说,细节的“特殊频率”是低频,而3x3内核强调的特殊频率要高得多。

    可能的解决方案:

    • 您可以增加内核大小 - 例如设置kernel_size = 11
    • 作为替代方法,您可以在每个轴上将源图像的大小调整(缩小)0.25 倍。 您还可以在调整大小之前和之后计算 std 的加权和(以防在焦点良好时缩小的图像不够准确)。

    您的代码中有一个小问题:
    Core.convertScaleAbs(lplImage, absLplImage) 计算拉普拉斯结果的绝对值,因此计算的 STD 不正确。

    我建议进行以下修复:

    • 将拉普拉斯深度设置为CvType.CV_16S(而不是CvType.CV_64F):

      Imgproc.Laplacian(filteredImage, lplImage, CvType.CV_16S, kernel_size, scale, delta, Core.BORDER_DEFAULT);
      
    • 不要执行Core.meanStdDev(absLplImage, median, std),在lplImage上计算tee STD:

      Core.meanStdDev(lplImage, median, std);
      

    我使用以下 Python 代码进行测试:

    import cv2
    
    def calc_sharpness_score(srcImage):
        """ Compute sharpness score for automatic focus """
        filteredImage = cv2.GaussianBlur(srcImage, (3, 3), 0, 0)
    
        kernel_size = 11
        scale = 1
        delta = 0
        #lplImage = cv2.Laplacian(filteredImage, cv2.CV_64F, ksize=kernel_size, scale=scale, delta=delta)
        lplImage = cv2.Laplacian(filteredImage, cv2.CV_16S, ksize=kernel_size, scale=scale, delta=delta)
    
        # converting back to CV_8U generate the standard deviation
        #absLplImage = cv2.convertScaleAbs(lplImage)
    
        # get the standard deviation of the absolute image as input for the sharpness score
        # (mean, std) = cv2.meanStdDev(absLplImage)
        (mean, std) = cv2.meanStdDev(lplImage)
    
        return std[0][0]**2
    
    
    im1 = cv2.imread('im1.jpg', cv2.COLOR_BGR2GRAY)  # Read input image as Grayscale
    im2 = cv2.imread('im2.jpg', cv2.COLOR_BGR2GRAY)  # Read input image as Grayscale
    
    var1 = calc_sharpness_score(im1)
    var2 = calc_sharpness_score(im2)
    

    结果:

    std1 = 668464355
    std2 = 704603944

    【讨论】:

    • 将 kernel_size 更改为 11 并删除 convertScaleAbs() 效果很好!然而,更改深度导致我的其他几个图像集由于某种原因失败,即使它适用于包含我共享的 2 个图像的集。感谢您对此的帮助!
    • 如果计算时间不是问题,你最好保留CV_64F。您也可以尝试更大的内核大小。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-27
    • 2019-09-03
    • 2017-01-29
    • 1970-01-01
    • 1970-01-01
    • 2011-09-13
    • 2019-05-08
    相关资源
    最近更新 更多