10

このぼやけた画像にしきい値を設定して、数字をできるだけ明確にするにはどうすればよいですか?

以前の投稿で、ぼやけた画像 (左) を適応的にしきい値処理しようとしましたが、その結果、数字が歪んで切断されました (右)。

ここに画像の説明を入力

それ以来、画像の明るさを均一にするために、この投稿で説明されているようにモルフォロジー クロージング操作を使用してみました。

ここに画像の説明を入力

この画像を適応的にしきい値処理しても、あまり良い結果は得られません。ただし、明るさはほぼ均一であるため、通常のしきい値を使用できるようになりました。

ここに画像の説明を入力

これは以前よりもはるかに優れていますが、2 つの問題があります。

  1. しきい値を手動で選択する必要がありました。クローズ操作により均一な明るさになりますが、他の画像では明るさのレベルが異なる場合があります。
  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)
}
4

4 に答える 4

6

各ボックスの最適なしきい値を決定するために、Otsu のアルゴリズム (CV_OTSU - ありがとう remi!) を使用して、各 3x3 ボックスを個別にしきい値処理してみました。これは、画像全体をしきい値処理するよりも少しうまく機能し、おそらくもう少し堅牢です。

ここに画像の説明を入力

ただし、より良いソリューションは大歓迎です。

于 2012-12-01T01:35:04.557 に答える
6

あなたが試すかもしれないいくつかのヒント:

  • 元のしきい値処理された画像 (最初の画像の右側にあるノイズのある画像) にモルフォロジー オープニングを適用します。バックグラウンド ノイズのほとんどを取り除き、数字を再接続できるはずです。

  • モルフォ クロージングの代わりに、元の画像の別の前処理を使用します。メディアン フィルター (エッジがぼやける傾向があります) やバイラテラル フィルター処理など、エッジをより適切に保持しますが、計算は遅くなります。

  • しきい値に関する限り、cv::threshold で CV_OTSU フラグを使用して、グローバルしきい値の最適値を決定できます。ローカルのしきい値処理はまだ優れている可能性がありますが、バイラテラルまたはメディアン フィルターを使用するとより適切に機能するはずです。

于 2012-11-30T08:38:56.347 に答える
6

いくつかのサイクルを費やしても構わないと思っている場合は、処理前に画像をシャープにするために使用できるブレ除去技術があります. OpenCV にはまだ何もありませんが、これが成否を左右するようなものである場合は、追加できます。

この件に関する文献はたくさんあります: http://www.cse.cuhk.edu.hk/~leojia/projects/motion_deblurring/index.html http://www.google.com/search?q=motion+deblurring

また、OpenCV メーリング リストでのおしゃべり: http://tech.groups.yahoo.com/group/OpenCV/message/20938

あなたが見ている奇妙な「ハロー効果」は、適応しきい値が画像の端または近くにあり、それが使用しているウィンドウが画像以外の端に「ぶら下がっている」場合に、OpenCV が色を黒と仮定することが原因である可能性があります。地域。これを修正する方法はいくつかあります。ほとんどの場合、カメラからの画像よりも少なくとも 2 つのフル ブロック サイズの高さと幅の一時的な画像を作成します。次に、カメラ画像をその中央にコピーします。次に、一時画像の周囲の「空白」部分をカメラからの画像の平均色に設定します。適応しきい値を実行すると、エッジまたはその近くのデータがより正確になります。実際の画像ではないため完璧ではありませんが、OpenCV が想定している黒よりも良い結果が得られます。

于 2012-12-06T18:01:07.143 に答える
5

私の提案は、あなたが数独セルを特定できることを前提としていますが、それはあまり多くを求めていないと思います。もちろん、私の意見では、最初のステップとしてモルフォロジー演算子(私はそれらが本当に好きですが)および/または二値化方法を適用しようとするのは間違った方法です。何らかの理由で、画像が少なくとも部分的にぼやけています (元のカメラの角度や動きなどの理由)。したがって、デコンボリューションを実行して、それを元に戻す必要があります。もちろん、完全なデコンボリューションを求めるのは多すぎますが、いくつか試すことができます。

これらの「もの」の 1 つはWiener フィルターであり、たとえば、Matlab では関数の名前はdeconvwnrです。ぼやけが垂直方向にあることに気付いたので、特定の長さ (次の例では 10) の垂直カーネルを使用してデコンボリューションを実行し、入力にノイズがないと仮定できます (5% の仮定) -- I'ここでは非常に表面的な見方をしようとしているだけです。Matlab では、次のようにすることで、問題は少なくとも部分的に解決されます。

f = imread('some_sudoku_cell.png');
g = deconvwnr(f, fspecial('motion', 10, 90), 0.05));
h = im2bw(g, graythresh(g)); % graythresh is the Otsu method

以下は、いくつかのセルの結果です (オリジナル、otsu、領域成長の otsu、形態学的強調画像、領域成長を伴う形態学的強調画像の otsu、デコンボリューションの otsu):

ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力
ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力
ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力
ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力
ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力
ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力

強化された画像は、オリジナル + トップハット (オリジナル) - ボトムハット (オリジナル) を半径 3 のフラット ディスクで実行することによって生成されました。領域成長のシード ポイントを手動で選択し、最適なしきい値を手動で選択しました。

空のセルの場合、奇妙な結果が得られます (デコンボリューションの元と otsu):

ここに画像の説明を入力 ここに画像の説明を入力

しかし、セルが空かどうかを検出するのに苦労することはないと思います (グローバルしきい値は既に解決しています)。

編集:

別のアプローチで得られる最良の結果を追加しました: 領域の拡大。他のアプローチも試みましたが、これが 2 番目に優れた方法でした。

于 2012-12-03T00:19:52.740 に答える