如何对这个模糊的图像进行阈值处理以使数字尽可能清晰?
在上一篇文章中,我尝试对模糊图像(左)进行自适应阈值处理,结果导致数字失真和断开连接(右):
从那时起,我尝试使用本文所述的形态闭合操作来使图像的亮度均匀:
如果我自适应地对该图像进行阈值处理,我不会得到明显更好的结果。但是,由于亮度大致均匀,我现在可以使用普通阈值:
这比以前好多了,但我有两个问题:
- 我不得不手动选择阈值。尽管关闭操作会导致亮度均匀,但其他图像的亮度级别可能会有所不同。
- 如果阈值水平略有变化,图像的不同部分会做得更好。例如,左上角的 9 和 7 出现部分褪色,应该有一个较低的阈值,而一些 6s 已经融合成 8s,应该有一个更高的阈值。
我认为回到自适应阈值,但块大小非常大(图像的 1/9)可以解决这两个问题。相反,我最终得到了一个奇怪的“光环效果”,其中图像的中心更亮,但边缘与正常阈值图像大致相同:
编辑:remi建议从形态上打开这篇文章右上角的阈值图像。这不太好用。使用椭圆内核,只有 3x3 足够小,可以避免完全消除图像,即使这样,数字也会出现明显的破损:
Edit2: mmgp建议使用 Wiener 过滤器来消除模糊。我将OpenCV 中的 Wiener 过滤代码改编为 OpenCV4Android,但它使图像更加模糊!这是使用我的代码和 5x5 内核过滤之前(左)和之后的图像:
这是我改编的代码,它就地过滤:
private void wiener(Mat input, int nRows, int nCols) { // I tried nRows=5 and nCols=5
Mat localMean = new Mat(input.rows(), input.cols(), input.type());
Mat temp = new Mat(input.rows(), input.cols(), input.type());
Mat temp2 = new Mat(input.rows(), input.cols(), input.type());
// Create the kernel for convolution: a constant matrix with nRows rows
// and nCols cols, normalized so that the sum of the pixels is 1.
Mat kernel = new Mat(nRows, nCols, CvType.CV_32F, new Scalar(1.0 / (double) (nRows * nCols)));
// Get the local mean of the input. localMean = convolution(input, kernel)
Imgproc.filter2D(input, localMean, -1, kernel, new Point(nCols/2, nRows/2), 0);
// Get the local variance of the input. localVariance = convolution(input^2, kernel) - localMean^2
Core.multiply(input, input, temp); // temp = input^2
Imgproc.filter2D(temp, temp, -1, kernel, new Point(nCols/2, nRows/2), 0); // temp = convolution(input^2, kernel)
Core.multiply(localMean, localMean, temp2); //temp2 = localMean^2
Core.subtract(temp, temp2, temp); // temp = localVariance = convolution(input^2, kernel) - localMean^2
// Estimate the noise as mean(localVariance)
Scalar noise = Core.mean(temp);
// Compute the result. result = localMean + max(0, localVariance - noise) / max(localVariance, noise) * (input - localMean)
Core.max(temp, noise, temp2); // temp2 = max(localVariance, noise)
Core.subtract(temp, noise, temp); // temp = localVariance - noise
Core.max(temp, new Scalar(0), temp); // temp = max(0, localVariance - noise)
Core.divide(temp, temp2, temp); // temp = max(0, localVar-noise) / max(localVariance, noise)
Core.subtract(input, localMean, input); // input = input - localMean
Core.multiply(temp, input, input); // input = max(0, localVariance - noise) / max(localVariance, noise) * (input - localMean)
Core.add(input, localMean, input); // input = localMean + max(0, localVariance - noise) / max(localVariance, noise) * (input - localMean)
}