画像を2値化する

画像の2値化は 閾(しきい)値処理をして 画像を白と黒の色だけで表現された2階調の二値画像にすることです。OpenCv for Androidでは Imgprocクラスのthresholdメソッドで閾値処理を行います。
Imgproc.threshold(Mat src, Mat dst, double thresh, double maxval, int type)

  • src    2値化処理前のMat
  • dst      2値化処理後のMat
  • thresh 閾値
  • maxval 変換指定値
  • type     以下に示す 変換手法(Imgprocクラスの定数として定義されています)
 【変換手法】(OpenCv Cookbookより抜粋)
  • THRESH_BINARY:閾値以下の値は0に,それ以外は指定した値(maxVal)になります.
  • THRESH_BINARY_INV:上記とは逆に,閾値より大きい値が0に,それ以外は指定した値(maxVal)になります.
  • THRESH_TRUNC:閾値より大きい値は閾値まで切り詰められ,それ以外はそのまま残ります.
  • THRESH_TOZERO:閾値より大きい値はそのまま残り,それ以外は0になります.
  • THRESH_TOZERO_INV:上記とは逆に,閾値以下の値はそのまま残り,それ以外は0になります.
これを見ると 実際には THRESH_BINARY、THRESH_BINARY_INV以外は 正確に2階調ではなく 中間色が発生することがわかります。
また 特殊な値 THRESH_OTSU を用いると、関数は大津のアルゴリズムを用いて最適な閾値を決定し,それを引数 thresh で指定された値の代わりに利用します.つまり,自分で閾値を決める必要がありません.
なお2値化処理はグレースケール化した後行います。
以下に実行結果を示します。

(1)元の画像 (2)グレースケール    
(3)THRESH_BINARY  (4)THRESH_BINARY_INV  

(5)グレースケール (6)THRESH_TRUNC   
(7)THRESH_TOZERO (8)THRESH_TOZERO_INV 

変換処理のコーディングは以下の通りです。

(3)Imgproc.threshold(mat, mat_bin, 0.0, 255.0, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);
(4)Imgproc.threshold(mat, mat_bininv, 0.0, 255.0, Imgproc.THRESH_BINARY_INV | Imgproc.THRESH_OTSU);
(6)Imgproc.threshold(mat, mat_trunc, 0, 255, Imgproc.THRESH_TRUNC | Imgproc.THRESH_OTSU);
(7)Imgproc.threshold(mat, mat_tozero, 0, 255, Imgproc.THRESH_TOZERO | Imgproc.THRESH_OTSU);
(8)Imgproc.threshold(mat, mat_tozeroinv, 0, 255, Imgproc.THRESH_TOZERO_INV | Imgproc.THRESH_OTSU);

処理の順番は以下の順番で行わないと エラーになったり 何も表示されない現象が発生します。(ここを参照)
a. BitmapからMatに変換 
    Mat mat = android.BitmapToMat(src2);
b. グレースケール化        
    Imgproc.cvtColor(mat , mat, Imgproc.COLOR_RGB2GRAY);
c. 2値化
    Imgproc.threshold(mat, mat_bin, 0.0, 255.0, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);
d. BGRAに変換
    Imgproc.cvtColor(mat_bin, mat_bin, Imgproc.COLOR_GRAY2BGRA,4);
e. BitMapに変換
    android.MatToBitmap(mat_bininv, bmp_bininv); 

 【adaptiveThresholdメソッド】 

OpenCvでは2値化を行うもうひとつの方法に ImgprocクラスのadaptiveThresholdメソッドを使う方法があります。
OpenCv Cookbookによると 『adaptiveThresholdは、適応的な閾値処理を行います。この適応的というのは,閾値が入力によって適応的に決まることを意味します
とあります。
適応的とはadaptiveの直訳で、日本語らしく無い表現で意味がよくわかりません。、『入力に応じて 適切に閾値を求めると理解すればよさそうで、実際には対象となるピクセルの近傍のピクセルの平均値をもとに閾値が求められます。

adaptiveThreshold(Mat src, Mat dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C)

  • src 2値化処理前のMat
  • dst 2値化処理後のMat
  • maxValue 条件を満たすピクセルに割り当てられる値
  • adaptiveMethod 閾値決定の手法
  • thresholdType  変換手法 THRESH_BINARYまたはTHRESH_BINARY_INV
  • blockSize      対象のピクセルの近傍何ピクセルを元に平均値を求めるかを示す(奇数のみ可)
  • C
【閾値決定】の手法は、以下の2つの手法がImgprocクラスの定数として定義されています

  • ADAPTIVE_THRESH_MEAN_C:閾値 T(x,y) は,(x,y) の近傍 blockSize * blockSize の平均から C を引いた値
  • ADAPTIVE_THRESH_GAUSSIAN_C:閾値 T(x,y) は,(x,y) の近傍 blockSize x blockSize の(ガウス分布を用いた)加重平均から C を引いた値になります.このガウス分布の標準偏差は,blockSize から決定されます.
ますますよくわからなくなりました。ともかく実行してみると
(1)MEAN blockSize=7   C=2 (2)GAUSSIAN blockSize=7   C=2
(3)MEAN blockSize=15 C=8 (4)GAUSSIAN blockSize=15 C=8
  1. Imgproc.adaptiveThreshold(mat, mat_mean72, 255.0, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 7, 2);
  2. Imgproc.adaptiveThreshold(mat, mat_gaussin72, 255.0, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C, Imgproc.THRESH_BINARY, 7, 2);
  3. Imgproc.adaptiveThreshold(mat, mat_mean158, 255.0, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 15, 8);
  4. Imgproc.adaptiveThreshold(mat, mat_gaussin158, 255.0, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C, Imgproc.THRESH_BINARY, 15, 8);

BlockSizeを大きくすると ノイズが消えてこの例では輪郭がはっきりしてくる感じがします。

 by Android2.2 with OpenCv 2.3.1 for Android   
スポンサーリンク
Rectangle大広告
Rectangle大広告

シェアする

  • このエントリーをはてなブックマークに追加

フォローする