Почему размытое изображение получает лучшую дисперсию оценки Лапласа? - PullRequest
1 голос
/ 17 марта 2020

Следующий код большую часть времени находит изображение с наилучшей фокусировкой в ​​пределах набора, но есть некоторые изображения, в которых он возвращает более высокое значение для изображения, которое является более размытым для моего глаза.

Я использую OpenCV 3.4.2 для Linux и / или Ma c.

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), взятые из ниже предметного стекла микроскопа при попытке автоматически сфокусироваться на покрытии / маске на верхней поверхности предметного стекла.

very blurry image

more in-focus image

Я надеюсь, что кто-то может объяснить мне, почему мой алгоритм не работает обнаружить изображение, которое менее размыто. Спасибо!

1 Ответ

1 голос
/ 17 марта 2020

Основная проблема в том, что размер лапласианского ядра слишком мал .

Вы используете kernel_size = 3, и он слишком мал для вышеуказанной сцены.
На изображениях, представленных выше, на kernel_size = 3 влияет в основном шум , потому что края (в изображение, которое показывает больше деталей), намного больше, чем 3x3 пикселей.

Другими словами, «особая частота» деталей - это низкая частота, а ядро ​​3x3 подчеркивает гораздо более высокую специальную частоту.

Возможные решения:

  • Вы можете увеличить размер ядра - установите kernel_size = 11, например.
  • В качестве альтернативы вы можете изменить (уменьшить) исходное изображение, скажем, в 0,25 раза по каждой оси. Вы также можете вычислить взвешенную сумму стандартных значений до и после изменения размера (в случае, если сжатое изображение недостаточно точное, когда фокусировка хорошая).

В вашем коде есть небольшая проблема:
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), вычислить значение STD на lplImage:

    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

...