このぼやけた画像にしきい値を設定して、数字をできるだけ明確にするにはどうすればよいですか?
以前の投稿で、ぼやけた画像 (左) を適応的にしきい値処理しようとしましたが、その結果、数字が歪んで切断されました (右)。
それ以来、画像の明るさを均一にするために、この投稿で説明されているようにモルフォロジー クロージング操作を使用してみました。
この画像を適応的にしきい値処理しても、あまり良い結果は得られません。ただし、明るさはほぼ均一であるため、通常のしきい値を使用できるようになりました。
これは以前よりもはるかに優れていますが、2 つの問題があります。
- しきい値を手動で選択する必要がありました。クローズ操作により均一な明るさになりますが、他の画像では明るさのレベルが異なる場合があります。
- 画像のさまざまな部分は、しきい値レベルをわずかに変化させたほうがうまくいきます。たとえば、左上の 9 と 7 は部分的にフェードアウトし、しきい値が低くなるはずですが、6 の一部は融合して 8 になり、しきい値が高くなるはずです。
適応しきい値に戻ると考えましたが、非常に大きなブロック サイズ (画像の 1/9) を使用すると、両方の問題が解決します。代わりに、画像の中心がはるかに明るくなるという奇妙な「ハロー効果」が発生しますが、エッジは通常のしきい値の画像とほぼ同じです。
編集: remiは、この投稿の右上にあるしきい値処理された画像を形態学的に開くことを提案しました。これはあまりうまくいきません。楕円形のカーネルを使用すると、3x3 だけが画像を完全に消去するのを避けるのに十分小さく、それでも桁に大きな破損があります。
Edit2: mmgpは、ウィーナー フィルターを使用してぼかしを除去することを提案しました。このコードを 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)
}