Edited at

iOS / OpenCV 3.0 で画像の特徴点を検出する(AKAZE, SIFT, SURF, ORB)

More than 3 years have passed since last update.


局所特徴量とは / SIFT, SURF 特徴量

下記スライドが超わかりやすかったです。

で、SIFT (Scale-invariant feature transform)、SURF (Speed-Upped Robust Feature) というのは、拡大縮小・回転・照明変化に強いロバストな特徴量、としてよく知られているようです。

SURF の方が軽量で、その代わり認識精度は SIFT の方が良い、とのこと。


特徴量の用途


複数写真からのパノラマ写真合成

(上述のスライドより)


AR のマーカー認識

下記画像はARのマーカー認識とは違いますが、そういう使い方ができそうだ、ということは汲んでいただけるかと。。

http://docs.opencv.org/3.0-rc1/d7/dff/tutorial_feature_homography.html より)


物体認識

(上述のスライドより)


ORB(Oriented-BRIEF)特徴量

SIFT, SURF 同様に回転や拡大縮小にロバストでありながら、高速(SURFの10倍、SIFTの100倍)、かつライセンス的にも使いやすい特徴量。

ちなみに下記記事のコメント欄で教えていただきました。


AKAZE 特徴量

OpenCV 3.0 に新たに組み込まれた特徴点抽出アルゴリズム。

AKAZE は Accelerated KAZE の略で、KAZE という SIFT や SURF の欠点を解決した手法をもとに、さらにそのロバスト性の向上と高速化を図ったもの、とのこと。

上記記事では他手法と比較したベンチマークもとっていて、


画像変化のロバスト性については、スケール・回転・輝度・Blur全てにおいて、AKAZEが最も良い数値を示していることが分かります。実際使ってみた感じでも、かなり正確にトラッキングしている感じがします。

スピードに関しても、SIFTやSURFに比べて同程度、もしくはそれ以上です。


とのことで、かなりおいしいとこ取りな感じです。

さらにいろんなところで言われてることですが、SIFT や SURF はライセンス的に商用利用しづらいものらしく、一方でこの AKAZE はライセンス的にも使いやすくなっているとのこと。(自分はまだ個人でお試し利用中なので詳細未確認)


AKAZE vs ORB

OpenCV 公式のこちらのページにて、AKAZE と ORB による planar tracking(平面トラッキング)の比較が行われています。

AKAZEの方がより強力にトラッキングしているようです。


iOSにおける実装

というわけでここからが本題ですが、iOS で SURF, SIFT, ORB, AKAZE を用いて特徴点検出を行ってみます。


contrib の利用

SIFT, SURF は(ライセンスの都合上?)contrib という別枠で管理されています。詳しくは下記記事にまとめたのでご参照ください。


コード

こんな感じで実装しました。

typedef NS_ENUM(NSUInteger, CVFeatureDetectorType) {

CVFeatureDetectorTypeSURF,
CVFeatureDetectorTypeSIFT,
CVFeatureDetectorTypeORB,
CVFeatureDetectorTypeAKAZE,
};

+ (UIImage *)detectKeypoints:(UIImage *)srcImage withFeatureDetector:(CVFeatureDetectorType)detectorType

{
cv::Mat srcMat = [OpenCVHelper cvMatFromUIImage:srcImage];

// FeatureDetector 生成
Ptr<Feature2D> detector;
switch (detectorType) {
case CVFeatureDetectorTypeSURF:
default:
detector = SURF::create();
break;
case CVFeatureDetectorTypeSIFT:
detector = SIFT::create();
break;
case CVFeatureDetectorTypeORB:
detector = ORB::create();
break;
case CVFeatureDetectorTypeAKAZE:
detector = AKAZE::create();
break;
}

// 特徴点抽出
std::vector<KeyPoint> keypoints;
detector->detect(srcMat, keypoints);

printf("%lu keypoints are detected.\n", keypoints.size());

// 特徴点を描画
cv::Mat dstMat;

dstMat = srcMat.clone();
for(int i = 0; i < keypoints.size(); i++) {

KeyPoint *point = &(keypoints[i]);
cv::Point center;
int radius;
center.x = cvRound(point->pt.x);
center.y = cvRound(point->pt.y);
radius = cvRound(point->size*0.25);

cv::circle(dstMat, center, radius, Scalar(255,255,0));
}

return [OpenCVHelper UIImageFromCVMat:dstMat];
}

呼び出し側はこんな感じ。

- (IBAction)segmentChanged:(UISegmentedControl *)sender {

UIImage *srcImage = [UIImage imageNamed:@"image_filename"];

self.imageView.image = [OpenCVHelper detectKeypoints:srcImage
withFeatureDetector:(CVFeatureDetectorType)sender.selectedSegmentIndex];
}


実行結果

実行時間は iPhone 6 で計測。(特徴点の描画も含む)


SURF


  • 特徴点数: 5127

  • 実行時間: 0.610362[s]


SIFT


  • 特徴点数: 3175

  • 実行時間: 2.116536[s]


ORB


  • 特徴点数: 500

  • 実行時間: 0.120371[s]


AKAZE


  • 特徴点数: 5651

  • 実行時間: 1.260507[s]


所感&今後の展望

あれ、AKAZEが意外と遅い。。処理時間の計測範囲には特徴点の描画まで含めたのでその影響かな、とも思いましたがSURFは同じぐらいの特徴点数なのに速いのでそこではないようです。

上でも参照したこちらの記事によると、


AKAZE/KAZEのコードはOpenMPでの並列化に対応しているのですが、このベンチマークではOpenMPを利用していません。Pablo氏からの指摘によれば、AKAZEのロジックは並列化に向いているため、OpenMPの利用により大幅なスピードアップが見込めるとのことです。OpenCVのSIFTとSURFのコードを見たところ、SIFTのコードは並列化していませんが、SURFのコードは並列化しています。上記ベンチマークのSURFの速さは、それも起因していると思われます。


とのこと。SURFの並列化がiOSでも効いているのかどうか、AKAZE の OpenCV の実装がどうなってるのかまでは理解してやっていないので、上記結果はほんの参考程度にどうぞ。。

また、処理速度以前に、検出された特徴点が手法によって全然違う、というのも上の結果から見て取れます。アルゴリズムの中身を理解して、用途に応じて適切なものを選ぶ必要がありそう。今回使用した画像はベクター的なオブジェクトの集合体ですが、写真的な画像に適用したらどうなのか、とか。

次ステップとしては DescriptorExtractor, DescriptorMatcher を使って特徴点のマッチングまでやってみたいと思っています。


おまけ:OpenCV 3.0 で使える FeatureDetector


  • FAST,ORB,BRISK,MSER,GFTT,HARRIS,SimpleBlob,KAZE,AKAZE


  • 要contrib: STAR,SIFT,SURF

(参考:OpenCV3.0.0-alphaの特徴抽出・マッチングまとめ


その他参考ページ


ブログ


こちらもどうぞ