为什么模糊图像得到更好的拉普拉斯分数方差?
Why is the blurry image getting a better variance of laplacian score?
大多数情况下,以下代码会在一组图像中找到焦点最佳的图像,但有些图像 returns 对于我眼中更模糊的图像来说,它的值更高。
我在 Linux and/or 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)的图像,是从显微镜载玻片下方拍摄的,同时试图自动对焦载玻片顶面上的 coating/mask。
我希望有人能向我解释为什么我的算法无法检测到不那么模糊的图像。谢谢!
主要问题是 laplacian 内核大小太小。
你用的是kernel_size = 3
,上面的场景太小了
在上面的图像中,kernel_size = 3
主要受 噪声影响,因为边缘(在显示更多细节的图像中)比 3x3 像素大得多。
也就是说,细节的"special frequency"是低频,而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
大多数情况下,以下代码会在一组图像中找到焦点最佳的图像,但有些图像 returns 对于我眼中更模糊的图像来说,它的值更高。
我在 Linux and/or Mac.
上使用 OpenCV 3.4.2import 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)的图像,是从显微镜载玻片下方拍摄的,同时试图自动对焦载玻片顶面上的 coating/mask。
我希望有人能向我解释为什么我的算法无法检测到不那么模糊的图像。谢谢!
主要问题是 laplacian 内核大小太小。
你用的是kernel_size = 3
,上面的场景太小了
在上面的图像中,kernel_size = 3
主要受 噪声影响,因为边缘(在显示更多细节的图像中)比 3x3 像素大得多。
也就是说,细节的"special frequency"是低频,而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