ぼやけや不均一な明るさの可能性がある画像にしきい値を設定するための高速で信頼できる方法は何ですか?
例(ぼかしはあるが均一な明るさ):
画像の輝度が均一であることが保証されていないため、固定しきい値を使用することはできません。適応しきい値は問題なく機能しますが、ぼやけのために機能に切れ目や歪みが生じます(ここで重要な機能は数独の数字です)。
(OpenCVのequalizeHist
関数を使用して)ヒストグラム均等化を使用してみました。明るさの違いを減らすことなくコントラストを高めます。
私が見つけた最良の解決策は、画像をそのモルフォロジカルクロージング(クレジット この投稿 )で除算して明るさを均一にし、次に再正規化して、固定しきい値を使用することです(大津のアルゴリズムを使用して最適なしきい値レベル):
OpenCV for Androidでのコードは次のとおりです。
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(19,19));
Mat closed = new Mat(); // closed will have type CV_32F
Imgproc.morphologyEx(image, closed, Imgproc.MORPH_CLOSE, kernel);
Core.divide(image, closed, closed, 1, CvType.CV_32F);
Core.normalize(closed, image, 0, 255, Core.NORM_MINMAX, CvType.CV_8U);
Imgproc.threshold(image, image, -1, 255, Imgproc.THRESH_BINARY_INV
+Imgproc.THRESH_OTSU);
これはうまくいきますが、閉じる操作は非常に遅いです。構造化要素のサイズを小さくすると、速度は向上しますが精度が低下します。
編集:DCSの提案に基づいて、ハイパスフィルターを使用してみました。ラプラシアンフィルターを選択しましたが、SobelフィルターとScharrフィルターでも同様の結果が期待できます。フィルターは、特徴が含まれていない領域の高周波ノイズを拾い、ぼかしによる適応しきい値への同様の歪みの影響を受けます。また、クローズ操作と同じくらいの時間がかかります。これは、15x15フィルターの例です。
編集2:AruniRCの回答に基づいて、提案されたパラメーターで画像にキャニーエッジ検出を使用しました:
double mean = Core.mean(image).val[0];
Imgproc.Canny(image, image, 0.66*mean, 1.33*mean);
接続された桁を取得するためにパラメーターを確実に自動的に微調整する方法がわかりません。
Vaughn CatoとTheraotの提案を使用して、画像を閉じる前に縮小し、閉じた画像を通常のサイズに拡大しました。それに比例してカーネルサイズも小さくしました。
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(5,5));
Mat temp = new Mat();
Imgproc.resize(image, temp, new Size(image.cols()/4, image.rows()/4));
Imgproc.morphologyEx(temp, temp, Imgproc.MORPH_CLOSE, kernel);
Imgproc.resize(temp, temp, new Size(image.cols(), image.rows()));
Core.divide(image, temp, temp, 1, CvType.CV_32F); // temp will now have type CV_32F
Core.normalize(temp, image, 0, 255, Core.NORM_MINMAX, CvType.CV_8U);
Imgproc.threshold(image, image, -1, 255,
Imgproc.THRESH_BINARY_INV+Imgproc.THRESH_OTSU);
以下の画像は、3つの異なる方法の結果を並べて示しています。
左-通常サイズ(432ピクセル)、19カーネル
中-ハーフサイズ(216ピクセル)、サイズ9カーネル
右-四分の一サイズ(108ピクセル)、カーネルサイズ5
クローズに使用される画像のサイズが小さくなると、画質は低下しますが、特徴の認識アルゴリズムに影響を与えるほどの劣化ではありません。リサイズを行っても、1/4サイズのクロージングでは速度が16倍を少し上回ります。これは、クロージング時間が画像内のピクセル数にほぼ比例することを示しています。
この速度をさらに向上させる方法(速度をさらに下げるか、画質の低下を減らすこと)に関する提案は大歓迎です。
ここで説明する非常に類似した問題(背景から文字を分割し、不均一な光と不均一な背景色を使用する)には、Bradleysアルゴリズムを使用します。 http://people.scs.carleton.ca:8008/~roth/iit- publications-iti/docs/gerh-50002.pdf 、C#コードはこちら: http://code.google.com/p/aforge/source/browse/trunk/Sources/Imaging/Filters/Adaptive + Binarization/BradleyLocalThresholding.cs?r = 136 。 OpenCVのintegral
関数を使用して計算できるインテグラルイメージで機能します。非常に信頼性が高く高速ですが、それ自体はOpenCVに実装されていませんが、移植は簡単です。
別のオプションは、openCVのAdaptiveThresholdメソッドですが、試しませんでした http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html#adaptivethreshold 。 MEANバージョンはブラッドリーと同じですが、パーセンテージの代わりに定数を使用して平均値を変更する点が異なります。
また、良い記事はこちら: https://dsp.stackexchange.com/a/2504
代替アプローチ:
数値を明確に2値化することを意図していると想定します...画像全体ではなくコンポーネントに焦点を移動します。
これはかなり簡単なアプローチです:
各Canny Edgeを接続コンポーネントと見なして(つまり、cvFindContours()またはそのC++の対応物を使用して)、前景と背景のグレーレベルを推定して、しきい値に到達できます。
最後のビットについては、 この論文 のセクション2と3を見てください。 OpenCVに実装させることはそれほど難しくないはずです。
これが役に立てば幸い!
編集1:
Canny Edgeのしきい値に基づいて、値を微調整するのに十分な非常に大まかなアイデアを示します。 high_threshold
は、エッジを検出する前にエッジの強度を制御します。基本的に、エッジは最初に検出されるhigh_threshold
より大きい勾配の大きさを持っている必要があります。したがって、これはエッジの最初の検出を行います。
これで、low_threshold
は近くのエッジの接続を処理します。近くにある接続されていないエッジが1つのエッジに結合される量を制御します。より良いアイデアについては、 このウェブページ の「ステップ6」をお読みください。非常に小さいlow_thresholdを設定してみて、どのようになるかを確認してください。これらの画像で機能しない場合は、0.66 * [平均値]を破棄することができます。
楕円形状は、平面形状と比較すると計算が複雑です。変更してみてください:
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(19,19));
に:
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(19,19));
精度への影響が少ない十分なソリューションを高速化できます。
グリッドのトリミングが適切であることがわかっている場合は、タイルごとに作業してみることができます。写真全体ではなく9つのサブイメージで作業すると、各サブイメージの輝度がより均一になります。クロッピングが完璧な場合は、各桁セルを個別に試すこともできます。しかし、それはすべてあなたの作物の信頼性にかかっています。