直線を検出する(マルチスケールHough変換)

前々回前回と古典的Hough変換の実験をしました。今回はマルチスケールHough変換を実行してみます。
OpenCvのC++リファレンスによるとHoughLinesメソッドの形式は

static void HoughLines(Mat image, Mat lines, double rho, double theta, int threshold)
static void HoughLines(Mat image, Mat lines, double rho, double theta, int threshold, double srn)
static void HoughLines(Mat image, Mat lines, double rho, double theta, int threshold, double srn, double stn)
の3種類があり 3番目の形式で  srn stnに正の整数を指定することにより マルチスケールHough変換が行われ、マルチスケールHough変換では投票空間の粗い距離分解能はrhoとなり,細かい分解能はrho/srn になる とあります。
そもそもこの投票空間という言葉がかなり 怪しい(!!)言葉ですが まそれはそれとして粗い距離分解能・細かい分解能とはどういうことなのでしょう あちこちググってみても あまりぴったりした解説がみつからないので 勢いで実験することにします。
テストデータは 詰碁の本をカメラで撮影した画像です。

 古典的Hough変換 

例によって Canny変換でエッジを検出し、直線を検出すると 次のようになりました。
Imgproc.HoughLines(edge, lines, 1, Math.PI / 180, 120);
直線を検出しているかのように見せるには 結構このパラメータはシビアです(笑)それでもかなり 怪しいです
黒石が並んでいる行列の罫線はうまく拾えません。(全体的に黒いため 罫線のエッジが少ないせいでしょう)

実は、OpenCvSharp版 実験中に 前回書いた検出直線の表示処理に 検出したにも関わらず 表示されない直線があることが判明しました。
直線表示ロジックを以下のように修正します。

double[] data;
double rho, theta;
for (int i = 0; i < lin.cols(); i++){
data = lin.get(0, i);
rho = data[0];
theta = data[1];

double cosTheta = Math.cos(theta);
double sinTheta = Math.sin(theta);
double x0 = cosTheta * rho;
double y0 = sinTheta * rho;
Point pt1 = new Point(x0 + 10000 * (-sinTheta), y0 + 10000 * cosTheta);
Point pt2 = new Point(x0 - 10000 * (-sinTheta), y0 - 10000 * cosTheta);
Core.line(img, pt1, pt2, new Scalar(255, 0, 0), 1);
}

実行結果は
水平に近い線が増えています。

 マルチスケールHough変換 

分解能を変えるつもりで thresholdはそのままにして rho、thetaは2倍 srn、stn に2を設定してみました。
Imgproc.HoughLines(edge, lines, 2, Math.PI / 180 * 2 , 120, 2 , 2);

ギャ 真っ赤 まるで血の海!!!
前々回から 分解能を粗くすると この血の海を何回も見てきましたが やはり・・
thresholdをいじってみます。threshold=190にしてようやく少しましになりました。
Imgproc.HoughLines(edge, lines, 2, Math.PI / 180 * 2 , 190, 2 , 2);

でも横線はあまり拾わず 石のあるところの縦線の拾い具合は変です。
srn、stnを指定すると かなり重くなるのですが このデータでは 重くなった割りに期待はずれの結果でした。

ところで ここで srn=0、stn=0とし 
Imgproc.HoughLines(edge, lines, 2, Math.PI / 180 * 2 , 190, 0, 0);
とすれば 古典的変換になると思って 実験してみたところ 
結果はsrn=2、stn=2 上図の結果と同じ・・・
当然 Imgproc.HoughLines(edge, lines, 2, Math.PI / 180 * 2 , 190); とも同じ結果
もっと極端に引数を変えるとかしないと いけないのかな?? 

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

シェアする

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

フォローする