BE CREATIVE

OpenCVよりな理系大学生による主に研究ブログ(個人用) - Egocentric Vision・SURF・SIFT・Optical Flow・AR・ Motion Analyses・Kinect・Leap Motion - 最近、VCでアルバイト始めました。

ポイントクラウドで物体検知 - 3次元座標の活用 -

近頃はDepthセンサーを使って物体検知をするというテーマを主としてやっていました。
で、大事なのはセンサから取得した距離データをどう扱うかってとこです。
普通は2次元の画像として出力するのが一番簡単なのですが、
どうやら3次元の画像としても扱えるみたいです。
考えてみれば当たり前ですが、ウィンドウズサイズの中の各ポイントに距離データは存在してるので
それを予め3次元座標で表現するだけですから。
一つ一つの点(ポイント)に格納されたデータ(x, y ,z)を三軸上にプロットしていき
その集合として出力する、ポイントクラウドと定義されるそうです。
実際にポイントクラウドで表現してみました。


3DPoint - YouTube


これは、ある範囲で領域を立方体で細かく区切って、それぞれの立方体内にあるポイント数を
色の濃淡で表しています。
センサで取得した距離情報を元に実世界の3軸上にプロットしていき、
仮想の領域を設けるというイメージでしょうか。
センサを使って距離情報を取得するのは至ってシンプルでこれ以上発展しなさそうなので
次は初心に戻って基本的なデジタル信号処理を勉強しておこうかな。

Qualcomm の知的財産戦略とその背景

クアルコムは知的財産上手く活用することにより利益を上げている企業の一つである。その中でもクアルコムCDMA 方式の技術ライセンスを持つ会社として広く知られているが、技術ライセンスのロイヤリティのみで利益を上げているのではなく、利益の大半は半導体で売り上げを占めている。このようにあくまでも半導体メーカーとしての位置づけである一方でスマホ市場においてライセンスが市場に及ぼす影響がかなり大きいが故に知的財産を上手く 活用して発展を遂げている企業である。ライセンスビジネスがスマホ市場に大きな影響を与える背景としては、言うまでもなくスマホは現在あらゆる技術の結晶として成り立っており、技術ライセンスを持つ企業は一般的に1台あたりいくらといった計算でロイヤリティの収入がある。それにより、ひとつの製品を開発するのにも、複数の異なる企業の技術ライセンスが必要となり、場合によってはロイヤリティだけで非常にコストがかかり、結果的に製品コストが高くなることがある。また、どうしても研究開発の設備投資に莫大なコストがかかり利益率もよくない業界である。従って、研究開発のコストを下げざるを得ず、 ハイエンド機種の開発に対して他社より抜きにでた技術が生まれにくい。もちろんローエンドの機種に対しても開発コストを下げるのに技術ライセンスが邪魔になってしまう。そこで、クアルコムはあらゆる関連企業を買収し技術ライセンスをある意味独占的に支配している。しかし、知的財産を独占するのではなく、ロイヤリティで得た収入を研究開発に回し、研究開発によるイノベーションを通信用半導体チップと知的所有権という形で提供している。このようにクアルコムは様々な知的財産権保有者とライセンス契約を受け持つことで、携 帯メーカーはより低いコストで、こうした技術を扱えるようになる。知的財産権のトータルコストを下げることはスマホ市場において競争を活性化することにつながり、より多くの新規参入を促し、市場の拡大にもつながる。


改めてクアルコム知的財産権戦略を考察してみると、ビジネスではいかにマーケットが重要かを感じますね。

参考:
Mobile IT Asia:“スマートデバイス化”をサポートするQualcommの技術と強み - ITmedia Mobile
ライセンス契約の研究-クアルコム社韓国独占禁止法事件紹介(二又 俊文)/コラム/東京大学政策ビジョン研究センター
CDMA10周年特別企画 日本のケータイの進化を支えてきたクアルコムのワイヤレステクノロジー
ITmedia ビジネスモバイル:技術を開発し、チップで儲ける──Qualcommのビジネスモデル (1/3)

ProcessingでKinectを動かしてみた!(OpenNI + Processing + Kinect) - 深度センサの動向

最近、Kinectを使って研究しているのですがmacでも扱えないかなと何となく探していたらProcessingで簡単にKinectを扱えるとのこと。さっそく調べてみるとsimple-OpenNIというProcessingでKinectを扱うためのライブラリを使えば良さそう。OpenNIという距離画像を扱うライブラリもあったのですが、サービス終了してしまったみたいでこの界隈は色々ありそうですね。ちなみにKinectといっても色々ありますけど、今回はKinect Xbox 360センサーを用いました。最近だと、Kinect v2が新しくリリースされたりどちらかというとDepthセンサー自体はToF方式の方が主流になってきたのかなと思います。でも今回はそこに関してはあまり重要ではないので無視です(笑)、ということで早速Processingを使って幾つかサンプルプログラムを実行。
f:id:junn511:20141027232934p:plain
こんな感じでDepthMapも簡単に取得できました。で、どの程度まで正確に距離を測れるかですが、800mm-4000mm程度らしいです。実際に調べてみたところこんな感じになりました。
f:id:junn511:20141027233525p:plain
本当は誤差率を割合で表示すべきでしたね、反省。1000-4000mmの範囲は割と正確に測ることができたかなという印象です。今後はこの人達みたいにKinectを頭につけてリアルタイムに距離推定をしていこうと考え中です。笑

NAVI -- Navigational Aids for the Visually Impaired ...

全く話しは変わりますが、この間デジタルコンテンツExpoに行ってきました、というのも目的の一つに株式会社アイプラスプラスさんの製品であるAuxDecoを体験してみたかったので。簡単にいうと画像情報を触覚で伝えて視覚障害者のための歩行補助装置です。光センサーで認識した対象物のエッジだけを強調してそれをそのまま触覚で表すと、これは実際に体験してみないと分かりにくいですね。ToFセンサーも使っていて距離情報も扱えていました。色々とお話を伺ったところやはり今後Google Tangoみたいなのが登場することで、身近なスマートフォンでも赤外線センサみたいなのが付いてくると。そうなると、距離を推定、計測する研究よりもその情報をいかにして表現するか。そっちのアプリケーションが重要であり我々は触覚の研究をしているとのことでした。ただ、赤外線センサが搭載されたからといって太陽光に弱いところもあったりして、その点ステレオビジョンを用いた方が実際のアプリケーションには実現性があるのかなといった気がしました。個人的にはDepthセンサーが今後どう汎用化していくか非常に気になるところです。

異なる手法を用いた頑健性比較

OpenCVでは特徴点抽出,特徴記述,特徴点のマッチングついて様々なアルゴリズムが実装されており、いまいちどのアルゴリズムを使えば、どのシーンに一番適応されるのが良く分かっていなかったので今回は色んなアルゴリズムの組み合わせを実際に試してみた。

評価画像と比較画像を用いて、スケール変化や回転にもロバストな手法を導きだす為に
マッチングの誤差率に着目した。
まず特徴点を検出し、特徴量を記述、そしてマッチングこの3つ過程がある訳だが、
それぞれにOpenCVには色々な関数が用意されている。

f:id:junn511:20140719175806p:plain

今回は特徴点検出にはFAST SIFT SURF ORB
記述にはSIFT SURF ORB
マッチングにはBruteForceとFlannBasedを使用した。

はじめに評価画像:lena.pngと比較画像:lena.pngを90度回転した画像を用意し
マッチング率を算出。結果はざっくりとこんな感じ。

FlannBased
f:id:junn511:20140719180506p:plain

BruteForce
f:id:junn511:20140719180518p:plain

なぜかFlannBasedの場合、記述でORBを使うと上手くいかなかったので割愛した。

次に、評価画像:lena.pngと比較画像:lena.pngを縮小し45度回転した画像を用いて
マッチング率を算出。

FlannBased
f:id:junn511:20140719180911p:plain

BruteForce
f:id:junn511:20140719180927p:plain

さっきと比較すると大幅にマッチング率が悪い・・・

少し予想していた結果とは異なるが今回の結果をまとめると
・スケール変化なしの回転だけの場合SURF SIFTのマッチング率が良い
・スケール変化及び回転をした場合はORB + SIFT or SURFのマッチング率が良い

恐らくスケール変化した際に、SURF SIFTの検出を用いた結果が悪いのは
マッチングの算出の仕方が原因かも。
他にも、原因があるかもしれないので今一度それぞれの特質などをしかっり復習しておこう。


参考としたサイトはこの辺り:
Comparison of the OpenCV’s feature detection algorithms - Computer Vision TalksComputer Vision Talks

Feature Detection and Description — OpenCV 3.0.0-dev documentation
c++ - improve matching of feature points with openCV - Stack Overflow
OpenCV on iOS: False matching with SurfFeatureDetector and FlannBasedMatcher - Stack Overflow
Feature Matching with FLANN — OpenCV v2.4.2 documentation

特徴点マッチング・FAST

前回、SIFT SURFを使って特徴点を検出、特徴量を記述し比較画像とマッチングを行いましたが
今回は特徴点の検出をFASTで行いました。
基本的なソースは前回と同様です。

#include "fast_matching.h"
#include <iostream>
#include <opencv/cv.h>
#include <opencv2/opencv.hpp>
#include <opencv/highgui.h>
#include <opencv/cxcore.h>
#include <ctype.h>
#include <stdio.h>
#include <opencv2/nonfree/nonfree.hpp>
#include <opencv2/nonfree/features2d.hpp>
#include <opencv2/legacy/legacy.hpp>  


int
main(int argc, char *argv[])
{
    
    //画像読み込み
    cv::Mat colorImg1 = cv::imread("/image/lena2.png");
    cv::Mat colorImg2 = cv::imread("/image/lena3.png");
    if(colorImg1.empty() || colorImg2.empty()){
        std::cout << "No Image" << std::endl;
        return -1;
    }

    //特徴点抽出用のグレー画像用意
    cv::Mat grayImg1, grayImg2;
    cv::cvtColor(colorImg1, grayImg1, CV_BGR2GRAY);
    cv::normalize(grayImg1, grayImg1, 0, 255, cv::NORM_MINMAX);
    cv::cvtColor(colorImg2, grayImg2, CV_BGR2GRAY);
    cv::normalize(grayImg2, grayImg2, 0, 255, cv::NORM_MINMAX);
    
    // FAST 検出器に基づく特徴点検出
    // threashld=70, nonMaxSuppression=true
    cv::FastFeatureDetector detector(70, false);
    cv::SiftDescriptorExtractor extractor;

    //------------ 処理時間計測 開始 --------------
    double ticFrequency;    // 1マイクロ秒あたりのTick数
    double processTime;     // 実行時間
    int    startTic;        // 開始
    int    stopTic;         // 終了時間
    // 1マイクロ秒あたりのTick数を得ます。最初に1回だけ実行すればよいです。
    ticFrequency = cvGetTickFrequency();
    // 計測開始点でのTick数を得ます。
    startTic = (int)cvGetTickCount();
    
    //-------------------------------------------
    
    //画像から特徴点を検出
    std::vector<cv::KeyPoint> keypoints1;
    detector.detect(grayImg1, keypoints1);
    std::cout << "Detected " << (int) keypoints1.size() << " keypoints1" <<std::endl;   //特徴点算出
    std::vector<cv::KeyPoint> keypoints2;
    detector.detect(grayImg2, keypoints2);
    std::cout << "Detected " << (int) keypoints2.size() << " keypoints2" <<std::endl;   //特徴点算出
    
    cv::Mat descriptors1;
    extractor.compute(grayImg1, keypoints1, descriptors1);
    cv::Mat descriptors2;
    extractor.compute(grayImg2, keypoints2, descriptors2);
    
    //特徴点の対応付け
    std::vector<cv::DMatch> matches;
    cv::BruteForceMatcher<cv::L2<float> > matcher;
    matcher.match(descriptors1, descriptors2, matches);
    std::cout << "Matching " << (int) matches.size() << " matching" <<std::endl;   //特徴点算出
    
    //ソートしたn番目までの対応線を表示させる。nth_elementは要素を基準要素よりも手前に移動させるある種のソート
    int N=50;
    nth_element(matches.begin(), matches.begin()+N-1, matches.end());
    matches.erase(matches.begin()+N, matches.end());
    
    //------------ 処理時間計測 終了 --------------
    
    // 計測終了点でのTick数を得ます。
    stopTic = (int)cvGetTickCount();
    // 実行時間を計算します。単位はマイクロ秒であることに注意してください。
    processTime = (stopTic-startTic)/ticFrequency;
    printf("%f",processTime);
    
    //------------------------------------------
    
    cv::Mat matchedImg;
    cv::drawMatches(colorImg1, keypoints1, colorImg2, keypoints2, matches, matchedImg);
    
    cv::namedWindow("FAST", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);
    cv::imshow("FAST", matchedImg);
    cv::waitKey(0);
    return 0;

}


実行するとこうなります。
f:id:junn511:20140713152715p:plain


今回はしきい値を設定したので検出した特徴点は169点とSIFT SURFに比べると少なめでした。

SIFT SURFを用いた特徴点マッチング

回転やスケール変化にも頑健なSIFTとSURFを用いて特徴点の対応づけをしてみた。
計算時間とマッチング数もそれぞれ算出。

プログラム

#include <iostream>
#include <opencv/cxcore.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/nonfree/nonfree.hpp>
#include <opencv2/legacy/legacy.hpp>   
int main(int argc, char *argv[])
{

    //画像読み込み
    cv::Mat colorImg1 = cv::imread("/image/lena2.png");
    cv::Mat colorImg2 = cv::imread("/image/lena3.png");
    if(colorImg1.empty() || colorImg2.empty()){
        std::cout << "No Image" << std::endl;
        return -1;
    }
    //特徴点抽出用のグレー画像用意
    cv::Mat grayImg1, grayImg2;
    cv::cvtColor(colorImg1, grayImg1, CV_BGR2GRAY);
    cv::normalize(grayImg1, grayImg1, 0, 255, cv::NORM_MINMAX);
    cv::cvtColor(colorImg2, grayImg2, CV_BGR2GRAY);
    cv::normalize(grayImg2, grayImg2, 0, 255, cv::NORM_MINMAX);

    //SIFT
    //cv::SiftFeatureDetector detector;
    //cv::SiftDescriptorExtractor extractor;

    //SURF
    cv::SurfFeatureDetector detector(1000);
    cv::SurfDescriptorExtractor extractor;


    //------------ 処理時間計測 開始 --------------
    double ticFrequency;    // 1マイクロ秒あたりのTick数
    double processTime;     // 実行時間
    int    startTic;        // 開始
    int    stopTic;         // 終了時間   
    ticFrequency = cvGetTickFrequency();
    // 計測開始点でのTick数を得ます。
    startTic = (int)cvGetTickCount();
    //-------------------------------------------

    //画像から特徴点を検出
    std::vector<cv::KeyPoint> keypoints1;
    detector.detect(grayImg1, keypoints1);
    std::cout << "Detected " << (int) keypoints1.size() << " keypoints1" <<std::endl;   //特徴点算出
    std::vector<cv::KeyPoint> keypoints2;
    detector.detect(grayImg2, keypoints2);
    std::cout << "Detected " << (int) keypoints2.size() << " keypoints2" <<std::endl;   //特徴点算出

    //画像の特徴点における特徴量を抽出
    cv::Mat descriptors1;
    extractor.compute(grayImg1, keypoints1, descriptors1);
    cv::Mat descriptors2;
    extractor.compute(grayImg2, keypoints2, descriptors2);

    
    //特徴点の対応付け
    std::vector<cv::DMatch> matches;
    cv::BruteForceMatcher<cv::L2<float> > matcher;
    matcher.match(descriptors1, descriptors2, matches);
    std::cout << "Matching " << (int) matches.size() << " matching" <<std::endl;   //特徴点算出
    //ソートしたn番目までの対応線を表示させる。nth_elementは要素を基準要素よりも手前に移動させるある種のソート

    int N=50;
    nth_element(matches.begin(), matches.begin()+N-1, matches.end());
    matches.erase(matches.begin()+N, matches.end());

    //------------ 処理時間計測 終了 --------------
    // 計測終了点でのTick数を得ます。
    stopTic = (int)cvGetTickCount();
    // 実行時間を計算します。単位はマイクロ秒であることに注意してください。
    processTime = (stopTic-startTic)/ticFrequency;
    printf("%f",processTime);

    //-----------------------------------------
    //対応づけされた画像の用意
    cv::Mat matchedImg;
    cv::drawMatches(colorImg1, keypoints1, colorImg2, keypoints2, matches, matchedImg);
    
    /// 画像を表示するウィンドウの名前,プロパティ
    // CV_WINDOW_AUTOSIZE : ウィンドウサイズを画像サイズに合わせる
    // CV_WINDOW_FREERATIO : ウィンドウのアスペクト比を固定しない
    cv::namedWindow("SURF", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);

    // ウィンドウ名でウィンドウを指定して,そこに画像を描画
    cv::imshow("SURF", matchedImg);
    // キー入力を(無限に)待つ
    cv::waitKey(0);
    return 0;

}

参考サイト:http://kesin.hatenablog.com/entry/20120810/1344582180

実行結果
SIFT
f:id:junn511:20140711161634p:plain
SURF
f:id:junn511:20140711161710p:plain

SURFの方が計算処理は速かったです。
他にも局所勾配特徴点を抽出する方法はSIFT SURF FAST BRIEF RIFF DAISYがあるみたい。
でも特徴量を記述するのはSIFT SURFぐらいなのか。
次はFAST使って同じようなことができるか試してみよう。

SURFによる特徴点の抽出とそのオプティカルフローの描画で
PTAMみたいな映像を作ってみるのも面白いかも。