Line Segment Detector線分検出器で秋をおいしくいただく

夏の暑さもだいぶやわらぎ,おさかなが美味しい季節になってきましたね.

画像からの線分検出といえばHough変換やRANSACなどがあり,そんな手法のひとつであるLSD;Line Segment Detectorを使ってみた.
原著は2010年のIEEE論文誌で発表されたようですね.今でもこれ系の分野がアツいということで見ていて楽しいですw

さて,ところで今日の記事は,
JugglerYou日記 :: LineSegmentDetectorを使ってみた
さんの記事の丸パクリに近い.
juggler_youさんはリアル知り合いだったりします.thx!

概要

http://www.ipol.im/pub/art/2012/gjmr-lsd/

ホントはアルゴリズムについてまとめたかったんですが気力がなかったし説明ページを読めば英語だけどけっこうわかりやすいので,詳細を知りたい方はそちらで.

サブピクセル精度なこと,パラメータ調整があまり必要ないこと,Hough変換よりrobustなこととかが結構アピールポイントのようです.

おさかなさん流のサンプルコード

http://www.ipol.im/pub/art/2012/gjmr-lsd/からソースを落としてきて,そのうちlsd.cとlsd.hだけが必要です.

ソース
#include <iostream>
#include <opencv2/opencv.hpp>
#include "lsd.h"

cv::Mat img;
int n_lines;
double* lines; 

void change_th_lsd(int nfa, void* dummy)
{
    cv::Mat result = img.clone();
    for(int i = 0; i < n_lines; i++)
    {
        const double *line = &lines[i * 7];
        if(nfa < line[6])
        {
            const cv::Point p1(line[0], line[1]);
            const cv::Point p2(line[2], line[3]);
            cv::line(result, p1, p2, cv::Scalar(0, 0, 255));
        }
    }
    cv::imshow("result_image", result);
}

int main(int argc, char *argv[])
{
    //画像をグレースケールとして読み込み
    img = cv::imread(argv[1], 0);

    //LSD用画像に変換><
    double *dat = new double[img.rows * img.cols];
    for(int y = 0; y < img.rows; y++)
        for(int x = 0; x < img.cols; x++)
            dat[y * img.cols + x] = img.at<unsigned char>(y, x);

    //LSD処理
    lines = lsd(&n_lines, dat, img.cols, img.rows);

    //しきい値の最大値と最小値をもってくる
    int max_NFA = 0;
    for(int i = 0; i < n_lines; i++)
        max_NFA = std::max(max_NFA, static_cast<int>(lines[i * 7 + 6]));

    //結果描画用画像
    cv::cvtColor(img, img, CV_GRAY2RGB);

    //結果表示用ウィンドウ
    cv::namedWindow("result_image");
    cv::createTrackbar("NFA", "result_image", NULL, max_NFA, change_th_lsd);
    cv::setTrackbarPos("NFA", "result_image", max_NFA);

    //結果表示
    cv::imshow("result_image", img);
    cv::waitKey(0);
}
コード解説

あまり必要ないとは思いますが….

  • LSDライブラリの内部処理のために画像をdouble配列に変換する必要があります

    • cv::Matではどうしても中のデータを直にそのまま流用できないようです…
  • 画面に出すときトラックバーで検出結果スコアでしきい値調整したいので,スコアの最大値をとってきてトラックバーの最大値とします
  • OpenCVのhighguiまわりについては他をご参照ください
実行方法

Linuxの場合のコンパイルと実行は

% g++ prog.cpp lsd.c -lopencv_core -lopencv_highgui -O3
% ./a.out hoge.jpg

実行例

実行例はこんなかんじ.しきい値をインタラクティブに変えながら結果を見ることができます.

けっこう綺麗にとれてて,いろんな画像をいれながらやるとなかなか楽しいです.

ライブラリとしての実装はなかなか残念なかんじだけどまぁOpenCV使ってたら驚くほどでもないかと(こら

以上,今月のタイトル詐欺でした!

コメントを残す

メールアドレスが公開されることはありません。