前3回は 古典的なHough変換・マルチスケールHough変換を実験しました。これらはめちゃくちゃ簡単にいうと 画面上にしらみつぶしに直線をひいてみてその上にどれだけエッジが乗っかるかで直線を見つける手法でした
今回実験する 確率的Hough変換は 画像の中から端点を持つ線分として線を検出する方法で decafishさんのブログにあるように 『適当に選んだ点が直線に並んでいたら、その間にも点があるだろう』とあたりをつけ直線を探し出す手法です。
OpenCvで確率的Hough変換を行うにはHoughLinesPを使います。
static void HoughLinesP(Mat image, Mat lines, double rho, double theta, int threshold)
static void HoughLinesP(Mat image, Mat lines, double rho, double theta, int threshold,
double minLineLength)
static void HoughLinesP(Mat image, Mat lines, double rho, double theta, int threshold,
double minLineLength,double maxLineGap)
Mat image : 8ビット,シングルチャンネルの2値入力画像。
この画像は関数により書き換えられる可能性があります。
Mat lines : 検出された直線が出力されるベクトル。各直線は,4要素のベクトル(x1,y1,x2,y2) で表現されます。
double rho : ピクセル単位で表される距離分解能。
double theta : ラジアン単位で表される角度分解能。
int threshold : 閾値パラメータ.十分なヒット数(> threshold)を得た直線のみが出力されます。
double minLineLength : 最小の線分長.これより短い線分は棄却されます。
double maxLineGap : 2点が同一線分上にあると見なす場合に許容される最大距離。
前3回で取り上げた HoughLinesと比べると minLineLength maxLineGap が目新しい引数で この2つの引数によりずいぶんわかりやすく感じます。ましてや 求まる直線が 4要素のベクトル(x1,y1,x2,y2) になるなど 直感的でうれしくなります。
実行結果 |
例によって グレースケール化した後 Canny変換、直線検出を行いました。
Mat image = android.BitmapToMat(src2); Mat edge = new Mat(); Mat lines = new Mat(); Imgproc.cvtColor(image , edge, Imgproc.COLOR_RGB2GRAY); Imgproc.Canny(edge, edge, 80, 100); Imgproc.HoughLinesP(edge, lines, 1, Math.PI / 180 , 50, 100 ,10); fncDrwLine(lines,image);
見つけた直線は 関数fncDrwLineで描画しています。古典的Hough変換と比べれば かなりすっきりしています。
private void fncDrwLine(Mat lin,Mat img) { double[] data; Point pt1 = new Point(); Point pt2 = new Point(); for (int i = 0; i < lin.cols(); i++){ data = lin.get(0, i); pt1.x = data[0]; pt1.y = data[1]; pt2.x = data[2]; pt2.y = data[3]; Core.line(img, pt1, pt2, new Scalar(255, 0, 0), 1); } }
引数を変えればもっと短い線分も拾えますが 最小100という かなり大きな値をあたえても(ちなみに画面のサイズは 600*480)それなりに拾っていることがわかります。引数を変えた場合も 期待した結果とあまりかけ離れない結果が得られました。HoughLinesよりは わかりやすいかも・・
by Android2.2 with OpenCv 2.3.1 for Android |
※マニュアル的に使おうと思うと、自分でもあまりに不便に感じたので『大山昇太のプログラム部屋』にIndexを作りました。ご利用ください。