Detectron2のModel Zooで物体検出、インスタンスセグメンテーション、姿勢推定

概要

Detectron2のModel Zooにある訓練済みを使って、物体検出やインスタンスセグメンテーション、姿勢推定等を行う。 多くのモデルに対して一括で処理できるコードを作った。便利。

Detectron2

FacebookのAI研究グループ(FAIR)が開発している物体検出アルゴリズムを実装のためのソフトウェア。

環境

インストール

詳細は省略。ほぼ公式の通りやった。Windowsでやろうとしたら公式対応してないから大変そうな雰囲気。

メモ代わりに大雑把な手順を載せるが公式を読んでやったほうがいい。

  • OS、cuda等:dockerコンテナ利用
    • nvidia/cuda:10.1-cudnn7-devel
  • Python環境
    • Anaconda 2019.10でpython3.7環境構築
  • pytorch
    • conda install pytorch torchvision cudatoolkit=10.1 -c pytorch
  • detectron2

      git clone https://github.com/facebookresearch/detectron2.git
      cd detectron2
      python setup.py build develop
    

Detectron2 Model Zoo

学習済みのモデルが置いてある。 以下のようなものがあるが、詳細はウェブサイト参照。

  • タスク
    • COCO Object Detection
    • COCO Instance Segmentation
    • COCO Person Keypoint Detection
    • COCO Panoptic Segmentation
    • LVIS Instance Segmentation
    • Cityscapes
    • Pascal VOC
  • アルゴリズム
    • Faster R-CNN、RetinaNet、Mask R-CNN、Cascade R-CNN等
    • backbone: FPN、ResNetベースのもの

確認用コード

Model Zooにある学習済みモデルをロードするモジュールと、予測して可視化するためのモジュールがあったのでそれを使った。

以下のコードを実行するとModel Zooにあるモデルの42個について予測を行える。

from detectron2.data.detection_utils import read_image
from detectron2.model_zoo.model_zoo import ModelZooUrls
from detectron2.config import get_cfg
from demo.predictor import VisualizationDemo

img_path = 'input.jpg'
img = read_image(img_path, format="BGR")

for i, config_path in enumerate(ModelZooUrls.CONFIG_PATH_TO_URL_SUFFIX.keys()):
    # rpnとfast_rcnnは可視化対応していないので飛ばす
    if 'rpn' in config_path or 'fast_rcnn' in config_path:
        continue
    # config設定
    cfg = get_cfg()
    cfg.merge_from_file(f'configs/{config_path}')
    cfg.MODEL.WEIGHTS = ModelZooUrls.get(config_path)
    score_thresh = 0.5
    cfg.MODEL.RETINANET.SCORE_THRESH_TEST = score_thresh
    cfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = score_thresh
    cfg.MODEL.PANOPTIC_FPN.COMBINE.INSTANCES_CONFIDENCE_THRESH = score_thresh
    cfg.freeze()
    # 検出&可視化
    demo = VisualizationDemo(cfg)
    predictions, visualized_output = demo.run_on_image(img)
    # ファイル出力
    dataset_name, algorithm = config_path.split("/")
    algorithm = algorithm.split('.')[0]
    visualized_output.save(f'out/{i:02d}-{dataset_name}-{algorithm}.jpg')

結果

f:id:whoopsidaisies:20191218181902j:plainf:id:whoopsidaisies:20191218181904j:plainf:id:whoopsidaisies:20191218181907j:plainf:id:whoopsidaisies:20191218181911j:plain
f:id:whoopsidaisies:20191218181914j:plainf:id:whoopsidaisies:20191218181916j:plainf:id:whoopsidaisies:20191218181921j:plainf:id:whoopsidaisies:20191218181926j:plain
f:id:whoopsidaisies:20191218181930j:plainf:id:whoopsidaisies:20191218181932j:plainf:id:whoopsidaisies:20191218181935j:plainf:id:whoopsidaisies:20191218181937j:plain
f:id:whoopsidaisies:20191218181940j:plainf:id:whoopsidaisies:20191218181943j:plainf:id:whoopsidaisies:20191218181945j:plainf:id:whoopsidaisies:20191218181947j:plain
f:id:whoopsidaisies:20191218181950j:plainf:id:whoopsidaisies:20191218181953j:plainf:id:whoopsidaisies:20191218181956j:plainf:id:whoopsidaisies:20191218181959j:plain
f:id:whoopsidaisies:20191218182001j:plainf:id:whoopsidaisies:20191218182004j:plainf:id:whoopsidaisies:20191218182007j:plainf:id:whoopsidaisies:20191218182010j:plain
f:id:whoopsidaisies:20191218182013j:plainf:id:whoopsidaisies:20191218182016j:plainf:id:whoopsidaisies:20191218182020j:plainf:id:whoopsidaisies:20191218182023j:plain
f:id:whoopsidaisies:20191218182026j:plainf:id:whoopsidaisies:20191218182029j:plainf:id:whoopsidaisies:20191218182031j:plainf:id:whoopsidaisies:20191218182035j:plain
f:id:whoopsidaisies:20191218182039j:plainf:id:whoopsidaisies:20191218182041j:plainf:id:whoopsidaisies:20191218182044j:plainf:id:whoopsidaisies:20191218182047j:plain
f:id:whoopsidaisies:20191218182051j:plainf:id:whoopsidaisies:20191218182055j:plainf:id:whoopsidaisies:20191218182059j:plainf:id:whoopsidaisies:20191218182101j:plain
f:id:whoopsidaisies:20191218182104j:plainf:id:whoopsidaisies:20191218182107j:plainf:id:whoopsidaisies:20191218181911j:plainf:id:whoopsidaisies:20191218181907j:plain

denseposeでU.S.A.

youtu.be

完全に出遅れたけど、DensePose使ってみたのでメモ。 Facebook等が発表した、2次元画像から人体の3Dサーフェスモデルを推定しちゃうすごい手法。

詳細とか使い方は下記のページあたりを参照。

shiropen.com github.com

環境

導入

偉い人がdockerhubでイメージ公開してくれていたので活用。 動画ファイルをffmpegとかで画像にばらしておいた。

# ubuntu 16.04の端末で
nvidia-docker run -it -d --name densepose garyfeng/densepose
docker exec -it densepose bash
# コンテナ内
#   実行時の引数でフォルダを指定するとフォルダ内の画像を一気に処理してくれる
tools/infer_simple.py \
   --cfg configs/DensePose_ResNet101_FPN_s1x-e2e.yaml \
   --output-dir /root/data/infer_out/  \
   --image-ext png \
   --wts https://s3.amazonaws.com/densepose/DensePose_ResNet101_FPN_s1x-e2e.pkl \
   /root/data/frame

以上、簡単にできてすごい。

OpenCV 3.4.1で背景差分

背景差分

f:id:whoopsidaisies:20180301131807p:plain

画像の前景と背景を分離する手法。2013年にOpenCV 2.4.7での背景差分の記事を書いたが、2018年になったいまOpenCV 3.4.1で背景差分を行おうとしたら使えるアルゴリズムが増えていたのでまとめておく。

アルゴリズム

MOG, MOG2, GMG

OpenCV 2.4.7でも使えた。以下のページに日本語でわかりやすい説明がある。

背景差分 — OpenCV-Python Tutorials

KNN

K近傍方に基づく背景差分。前景の画素数が少ない場合は効率が良いらしい。

Efficient adaptive density estimation per image pixel for the task of background subtraction - ScienceDirect

CNT

低スペックな計算機でもほかのアルゴリズムより高速に処理ができる。CNTという名前は「CouNT」の省略らしい。Raspberry Pi3でのベンチマークではMOG2が41秒に対し、CNTは18秒。

https://sagi-z.github.io/BackgroundSubtractorCNT/

LSBP

Local SVG Binary Pattern。注目画素とその周辺画素の大小関係を符号化するLBP(Local Binary Pattern)は、高速に計算可能な画像特徴量として知られている。局所的なノイズや隣接画素が類似しているような場合にもロバストにするようにSVD(特異値分解)を使った特徴量で背景差分を行っているそう。ちゃんと勉強してないのでよくわらからない。

https://www.cv-foundation.org/openaccess/content_cvpr_2016_workshops/w24/papers/Guo_Background_Subtraction_Using_CVPR_2016_paper.pdf

GSOC

LSBP特徴を使ってる。ノイズ除去とか穴埋めといった後処理をしているらしい。GSOC(Google Summer of Code)2017中で開発されたとかで元論文等はないらしいのでソースコードを読もう。

opencv_contrib/bgfg_gsoc.cpp at 6520dbaa224a661ca8105b1ab0b71451fd715f4c · opencv/opencv_contrib · GitHub

コード

実行にはopencv_contribが必要。

C++

opencv_contribをダウンロードし、opencvcmake時に例えば以下のようにOPENCV_EXTRA_MODULES_PATHオプションを指定してビルドする。

$ cmake -DOPENCV_EXTRA_MODULES_PATH=<opencv_contrib>/modules -DBUILD_opencv_legacy=OFF <opencv_source_directory>

ソースコード

#include <opencv2/opencv.hpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/bgsegm.hpp>

int main()
{
    // 動画ファイルの読み込み
    cv::VideoCapture cap = cv::VideoCapture("video.mp4");
    // 背景差分器の生成
    cv::Ptr<cv::BackgroundSubtractor> bgfs = cv::bgsegm::createBackgroundSubtractorGSOC();
    //cv::Ptr<cv::BackgroundSubtractor> bgfs = cv::bgsegm::createBackgroundSubtractorCNT();
    //cv::Ptr<cv::BackgroundSubtractor> bgfs = cv::bgsegm::createBackgroundSubtractorGMG();
    //cv::Ptr<cv::BackgroundSubtractor> bgfs = cv::bgsegm::createBackgroundSubtractorLSBP();
    //cv::Ptr<cv::BackgroundSubtractor> bgfs = cv::bgsegm::createBackgroundSubtractorMOG();
    //cv::Ptr<cv::BackgroundSubtractor> bgfs = cv::createBackgroundSubtractorMOG2();
    //cv::Ptr<cv::BackgroundSubtractor> bgfs = cv::createBackgroundSubtractorKNN();

    while (cv::waitKey(1) == -1)
    {
        cv::Mat frame, foreGroundMask, segm;

        cap >> frame;
        if (frame.empty())
            break;

        bgfs->apply(frame, foreGroundMask);
        frame.convertTo(segm, 0, 0.5);
        cv::add(frame, cv::Scalar(100, 100, 0), segm, foreGroundMask);
    
        cv::imshow("output", segm);
    }
    return 0;
}

Python

pipで管理している場合、以下のようにopencv-pythonをアンインストール後にopencv-contrib-pythonをインストールすればopencv_contribが使える。

pip uninstall opencv-python
pip install opencv-contrib-python

ソースコード

import cv2

cap = cv2.VideoCapture('video.mp4')
bgs = cv2.bgsegm.createBackgroundSubtractorLSBP()

while(cap.isOpened()):
    ret, frame = cap.read()
    mask = bgs.apply(frame)
    bg = bgs.getBackgroundImage()
    cv2.imshow('mask', mask)
    cv2.imshow('bg', bg)
    if cv2.waitKey(1) != -1:
        break

cap.release()
cv2.destroyAllWindows()

適用結果

比較のために各アルゴリズムを並べてみた。パラメータ調整もしてないから比較もくそもない気はするけど。GSOCが綺麗。LSBPはあんまり

www.youtube.com

あと、背景差分やるだけだったらたぶん以下のページで紹介されているBGSLibraryを使ったほうが良さそうではある。

blog.negativemind.com

tensorflowでMASK R-CNNによるSemantic Segmentation

セマンティックセグメンテーション

下の写真みたいに、入力画像を物体ごとに領域分割する技術。

f:id:whoopsidaisies:20180227180905p:plain https://wiki.tum.de/display/lfdv/Image+Semantic+Segmentation

Mask R-CNN

数あるセマンティックセグメンテーションを実現する手法の中で、2018年2月現在有力とされているものの一つ(たぶん)。

www.youtube.com

アルゴリズムの詳細についての説明は他に譲る。以下のページとかを参考にする。

TensorFlowのインストール

Google先生が公開している機械学習オープンソースライブラリ。インストール方法は巷にあふれているので適当にググってインストールする。

Tensorflow Object Detection APIのインストール

以下のGitHubのレポジトリで様々なTensorfFlowのモデルが公開されている。公式サポートではないが物体検出とセマンティックセグメンテーションのモデルも数多く公開されているので、今回はそれを使う。

github.com

インストールは公式の手順通りだが以下に適当にメモ。 models/installation.md at master · tensorflow/models · GitHub

  • 依存パッケージのインストール
apt install protobuf-compiler
pip install pillow lxml jupyter matplotlib
cd [PATH to models]/research
protoc object_detection/protos/*.proto --python_out=.
  • PYTHONPATHの追加
cd [PATH to models]/research
export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim

モデルファイルのダウンロード

Tensorflow detection model zooから物体検出やセマンティックセグメンテーションのトレーニング済みモデルをダウンロード出来る。とりあえず一番mAPの高いmask_rcnn_inception_resnet_v2_atrous_cocoというモデルを使う。

wget http://download.tensorflow.org/models/object_detection/mask_rcnn_inception_resnet_v2_atrous_coco_2018_01_28.tar.gz
tar -zxvf mask_rcnn_inception_resnet_v2_atrous_coco_2018_01_28.tar.gz

セマンティックセグメンテーションのpythonコード

import tensorflow as tf
import numpy as np
from PIL import Image
from object_detection.utils import ops as utils_ops

import sys
sys.path.append('[modelsのパス]/research/object_detection')
from utils import label_map_util
from utils import visualization_utils as vis_util

# 学習済モデルの読み込み
PATH_TO_CKPT = 'mask_rcnn_inception_resnet_v2_atrous_coco_2018_01_28/frozen_inference_graph.pb'

detection_graph = tf.Graph()
with detection_graph.as_default():
  od_graph_def = tf.GraphDef()
  with tf.gfile.GFile(PATH_TO_CKPT, 'rb') as fid:
    serialized_graph = fid.read()
    od_graph_def.ParseFromString(serialized_graph)
    tf.import_graph_def(od_graph_def, name='')

# ラベルの読み込み
PATH_TO_LABELS = '[modelsへのパス]/research/object_detection/data/mscoco_label_map.pbtxt'
NUM_CLASSES = 90

label_map = label_map_util.load_labelmap(PATH_TO_LABELS)
categories = label_map_util.convert_label_map_to_categories(label_map, max_num_classes=NUM_CLASSES, use_display_name=True)
category_index = label_map_util.create_category_index(categories)

# 画像の読み込みとnumpy配列への変換
def load_image_into_numpy_array(image):
  (im_width, im_height) = image.size
  return np.array(image.getdata()).reshape(
      (im_height, im_width, 3)).astype(np.uint8)

filename = '[画像ファイルのパス]'
image = Image.open(filename)
image_np = load_image_into_numpy_array(image)

# セマンティックセグメンテーションの処理
with detection_graph.as_default():
    with tf.Session() as sess:
        # 入出力用テンソルのハンドルを取得
        image_tensor = tf.get_default_graph().get_tensor_by_name('image_tensor:0')
        tensor_dict = {}
        tensor_dict['num_detections'] = tf.get_default_graph().get_tensor_by_name('num_detections:0')
        tensor_dict['detection_boxes'] = tf.get_default_graph().get_tensor_by_name('detection_boxes:0')
        tensor_dict['detection_scores'] = tf.get_default_graph().get_tensor_by_name('detection_scores:0')
        tensor_dict['detection_classes'] = tf.get_default_graph().get_tensor_by_name('detection_classes:0')
        tensor_dict['detection_masks'] = tf.get_default_graph().get_tensor_by_name('detection_masks:0')
        
        # バッチ内の最初の画像の結果を取り出す
        detection_boxes = tf.squeeze(tensor_dict['detection_boxes'], [0])
        detection_masks = tf.squeeze(tensor_dict['detection_masks'], [0])
        
        # 各検出ボックスのマスクを画像全体上のマスクへ変換
        real_num_detection = tf.cast(tensor_dict['num_detections'][0], tf.int32)
        detection_boxes = tf.slice(detection_boxes, [0, 0], [real_num_detection, -1])
        detection_masks = tf.slice(detection_masks, [0, 0, 0], [real_num_detection, -1, -1])
        detection_masks_reframed = utils_ops.reframe_box_masks_to_image_masks(
            detection_masks, detection_boxes, image_np.shape[0], image_np.shape[1])
        detection_masks_reframed = tf.cast(
            tf.greater(detection_masks_reframed, 0.5), tf.uint8)
        
        # バッチ分の次元を追加
        tensor_dict['detection_masks'] = tf.expand_dims(
            detection_masks_reframed, 0)
        
        # 実行
        output_dict = sess.run(tensor_dict,
                               feed_dict={image_tensor: np.expand_dims(image_np, 0)})
        
        # バッチ分の次元の削除と型変換
        output_dict['num_detections'] = int(output_dict['num_detections'][0])
        output_dict['detection_classes'] = output_dict[
            'detection_classes'][0].astype(np.uint8)
        output_dict['detection_boxes'] = output_dict['detection_boxes'][0]
        output_dict['detection_scores'] = output_dict['detection_scores'][0]
        output_dict['detection_masks'] = output_dict['detection_masks'][0]

# 画像にマスクとバウンディングボックスを書き込んで出力
vis_util.visualize_boxes_and_labels_on_image_array(
    image_np,
    output_dict['detection_boxes'],
    output_dict['detection_classes'],
    output_dict['detection_scores'],
    category_index,
    instance_masks=output_dict.get('detection_masks'),
    use_normalized_coordinates=True,
    line_thickness=8)
Image.fromarray(image_np).save('out.png')

結果

拾ってきたフリー写真に適用した結果が以下。手だけ写ってても人間って判断してくれるのね。

f:id:whoopsidaisies:20180227183425p:plain

nvidia-dockerインストール、コンテナ等メモ

基本的に公式サイトの説明とかの通りにやるだけなんだけど自分用にメモ。

ホストOS:ubuntu 16.04LTS

dockerのインストール

参考: Get Docker for Ubuntu - Docker

# https通信で公開鍵ダウンロードするため
apt-get update
apt-get install curl ca-certificates

# dockerレポジトリの公開鍵の登録
curl -fsSL https://yum.dockerproject.org/gpg | apt-key add -

# add-apt-repositoryコマンドのインストール
apt-get install software-properties-common

# dockerレポジトリ追加
add-apt-repository "deb https://apt.dockerproject.org/repo/ ubuntu-$(lsb_release -cs) main"

# aptでhttps通信するため
apt-get install apt-transport-https

# dockerのインストール
apt-get update
apt-get install docker-engine

NVIDIAドライバのインストール

これが一番ハマって大変な場合が多い気がするが、ここでは省略。どうにかうまいことインストールする。

NVIDIA Dockerのインストール

# debパッケージのダウンロード(2017/1/22現在で最新のもの)
curl -LO https://github.com/NVIDIA/nvidia-docker/releases/download/v1.0.0/nvidia-docker_1.0.0-1_amd64.deb
# インストール
dpkg -i nvidia-docker_1.0.0-1_amd64.deb
rm nvidia-docker_1.0.0-1_amd64.deb
# 動作確認(GPU情報が表示されると良い)
nvidia-docker run --rm nvidia/cuda nvidia-smi

バージョンについては下記ページでチェックして適宜ダウンロードするものを確認する。

Releases · NVIDIA/nvidia-docker · GitHub

NVIDIA Dockerコンテナメモ

便利なものがあれば随時追記予定。

C#で3次元グラフを表示する ILNumerics

ILNumericsは.NETで使用可能な数値計算等のライブラリである.グラフ表示機能も備わっているので,それを使ってC#のWindowsフォーム上に3次元グラフを表示する.

ILNumericsのインストール

現在最新バージョン(4.x系)のILNumericsは14日間のトライアル版以外は有償だが,Community Editionという無償版が提供されていた3.x系のバージョンNuGetでインストール可能なのでそれを使う.

まず,Visual StudioでWindowsフォームアプリケーションを作成する.

そして,プロジェクトを右クリックして「NuGetパッケージの管理」を選択する.オンラインから「ILNumerics」を検索・インストールする.

グラフ表示用コントロールの配置

フォームデザイナを開きツールボックスの適当なところで右クリックして「アイテムの選択(I)...」を選択する.

「.NET Framework コンポーネント」タブの「参照(B)...」ボタンを押して,「(ソリューションのパス)\packages\ILNumerics.3.3.3.0\lib\ILNumerics.dll」を選択したらOK.

するとツールボックスIL○○というコントロールが追加される.その中の,ILPanelコントロールをフォーム上に配置する.

f:id:whoopsidaisies:20141202163400p:plain

使ってみる

曲面

例として,以下の2変数関数を表示させてみる.
z=\frac{\sin(\sqrt{x^2+y^2})}{\sqrt{x^2+y^2}}

まず,コードの適当な場所に以下のusingを書いておく.

using ILNumerics.Drawing;
using ILNumerics.Drawing.Plotting;

そして,フォームロードイベントとかの適当なイベントに以下のコードを書く.

// グラフを格納するオブジェクトの生成
var scene = new ILScene
{
    // 3次元モードでプロット領域を生成
    new ILPlotCube(twoDMode: false)
    {
        // 曲面の生成
        new ILSurface(
            (x,y) => (float)(
                Math.Sin(Math.Sqrt(x*x + y*y))/Math.Sqrt(x*x + y*y)))
    }
};
// 描画用コントロールに生成したグラフをセット
ilPanel1.Scene = scene;

実行すると以下のように3次元グラフが表示される.マウスドラッグとかホイールとかで視点や拡大率を変えられる.

f:id:whoopsidaisies:20141202172655p:plain

等高線

サンプル用の地形データも用意されていて,以下のように使うことが出来る.

var scene = new ILScene
{
    new ILPlotCube(twoDMode: false){
        new ILSurface(ILNumerics.ILMath.tosingle(ILNumerics.ILSpecialData.terrain))
    }
};
ilPanel1.Scene = scene;

f:id:whoopsidaisies:20141202180125p:plain

ここまでは曲面表示のためILSurfaceクラスを使ってきたが,ILContourPlotクラスを使えば以下のように等高線表示も出来る.

var scene = new ILScene
{
    new ILPlotCube{
        new ILContourPlot(ILNumerics.ILMath.tosingle(ILNumerics.ILSpecialData.terrain))
    }
};
ilPanel1.Scene = scene;

f:id:whoopsidaisies:20141202180132p:plain

散布図

ILPointsクラスで散布図を表示させることも出来る.以下はランダムに点を打って対数軸にして表示した例.

ILNumerics.ILArray<float> p = ILNumerics.ILMath.tosingle(ILNumerics.ILMath.rand(3, 10000));
var scene = new ILScene{
    new ILPlotCube(twoDMode:false){
        new ILPoints
        {
            Positions = p,
            Color = null,
            Colors =  p,
            Size = 1,
        }
    }
};
var scaleModes = scene.First<ILPlotCube>().ScaleModes;
scaleModes.XAxisScale = AxisScale.Logarithmic;
scaleModes.YAxisScale = AxisScale.Logarithmic;
scaleModes.ZAxisScale = AxisScale.Logarithmic;

ilPanel1.Scene = scene;

f:id:whoopsidaisies:20141202182150p:plain

Python+OpenCVで特徴量記述・アルゴリズムまとめ

Python+OpenCVで画像の特徴点の特徴量を記述する.OpenCV2.4.9およびOpenCV3.0 alphaについて使用できるアルゴリズムをまとめる.

Python+OpenCVで特徴点抽出・使えるアルゴリズムまとめ OpenCV2.4.9と3.0 alpha - whoopsidaisies's diary
の続き.

環境

WindowsでOpenCV公式サイトのダウンロードページから2.4.9および3.0 alphaのビルド済みバイナリをダウンロードしてきて解凍したものを使う.

特徴量記述器の使い方

特徴点抽出のときのFeatureDetectorと同じように,特徴量記述についてもDescriptorExtractorという共通インターフェースが用意されている.

使い方は以下の通り.

# 引数でどの特徴量記述子を使うか指定 
extractor = cv2.DescriptorExtractor_create(extractor_name)
# 引数として画像と特徴点を渡す
# 戻り値は特徴点と特徴量
keypoints, descriptors = extractor.compute(img, keypoints)

DescriptorExtractor_createメソッドで指定出来る特徴量記述子を以下にまとめた.

OpenCVバージョン 実数ベクトル バイナリコード
2.4.9 SIFT, SURF BRIEF, BRISK, ORB, FREAK
3.0 alpha KAZE AKAZE, BRISK, ORB

(2.4.9でORBがなぜかランタイムエラーが出るので追々調査予定)

特徴量の中身

descriptorsの中身は2次元のarrayになっており,特徴点ごとに特徴量のベクトルが格納されている.

KAZEで記述した特徴量を表示してみるとこんな感じ(0番目の点).

>>descriptors[0]
array([ -7.38840317e-04,  -6.34267868e-04,   2.61819176e-03,
         3.50267510e-03,  -1.59906253e-04,  -4.56994586e-03,
         4.39605350e-03,   9.44076758e-03,  -1.75689301e-03,
         8.05667194e-04,   3.55383591e-03,   4.12554527e-03,
        -1.54193444e-03,   1.58668880e-03,   2.78847502e-03,
         3.14337271e-03,  -1.62520558e-02,   1.65848620e-02,
         3.65739577e-02,   2.07063138e-01,   2.64649391e-02,
        -6.13974873e-03,   9.64385048e-02,   2.91850477e-01,
         5.54781593e-02,   6.74537197e-03,   6.74520805e-02,
         8.45865980e-02,  -2.12559430e-03,   1.18403265e-03,
         5.09992335e-03,   4.04977519e-03,  -1.28035052e-02,
         6.93068025e-04,   3.93203236e-02,   4.54802722e-01,
        -2.96720478e-04,   6.83288351e-02,   8.15773308e-02,
         6.17026806e-01,  -1.08468741e-01,   5.95125668e-02,
         1.92962006e-01,   2.17324436e-01,  -1.21422755e-02,
         2.50244630e-03,   1.34693161e-02,   6.25377288e-03,
         2.55310140e-03,  -4.21544649e-02,   2.98030730e-02,
         1.50349155e-01,   4.27789390e-02,  -9.73087847e-02,
         1.63991615e-01,   1.90487400e-01,   3.39032081e-03,
        -2.32313443e-02,   1.98113456e-01,   6.58137947e-02,
        -1.16498368e-02,   2.66303378e-03,   1.25482017e-02,
         4.14769724e-03], dtype=float32)

グラフ表示だとこんな感じ.

import matplotlib.pyplot as plt
plt.plot(descriptors[0])

f:id:whoopsidaisies:20141201234637p:plain

KAZEは64次元の実数ベクトルで特徴量記述をするので以上のようになるが,記述子によってデータ量が違うため配列の長さや型が変わってくる.