連載
» 2015年11月10日 05時00分 公開

OpenCV入門【3.0対応】:第2回 OpenCV 3.0の新機能(+ 次バージョンのロードマップ) (1/2)

2015年6月に大望のOpenCVのメジャーバージョンアップ「3.0」が登場した。この新バージョンの新機能をモジュールごとに説明し、次バージョン3.1のロードマップを簡単に紹介する。

[@dandelion1124,著]
「OpenCV入門【3.0対応】」のインデックス

連載目次

ご注意:本記事は、@IT/Deep Insider編集部(デジタルアドバンテージ社)が「www.buildinsider.net」というサイトから、内容を改変することなく、そのまま「@IT」へと転載したものです。このため用字用語の統一ルールなどは@ITのそれとは一致しません。あらかじめご了承ください。

1. OpenCV 3.0のロードマップ

1.1 OpenCV 3.0

 OpenCVは、2015年6月にメジャーバージョンアップが実施され、3.0がリリースされました。また、前回の記事でも述べたようにOpenCV 3.0ではさまざまな機能が追加されています。今回の記事では追加された機能をピックアップして使用例を交えながら紹介します。

1.2 OpenCV 3.1

 ここでは、次バージョン(OpenCV 3.1)のロードマップについても触れておきたいと思います。

 公式の開発進捗(しんちょく)議事録であるOpenCV Meeting notes(2015/10/6)に、

OpenCV 3.1 release is planned for end of November-beginning of December

という記述があり、(少なくとも2015/10/6時点では)2015年末にOpenCV 3.1がリリースされる予定となっているようです。

 さらに、

  • Will include all of the summer of code work
  • Will take better advantage of Intel's IPP ICV
  • Better HAL (Hardware Acceleration Layer) support.
    • Intrinsics to better support SSE and Neon (same code, 2 deployments).

という記述もあることから、OpenCV Google Summer of Code 2015の成果物取り込みによる機能追加だけでなく、IPPICVのさらなる活用やHALの改善によるパフォーマンス向上なども取り組まれるようです。

2. OpenCV 3.0の新機能紹介

 この章ではOpenCV 3.0の新機能紹介をモジュールごとに紹介します。今回紹介するモジュールは以下の通りです。

 また、ユーザーから寄贈された追加機能がまとめられているリポジトリopencv_contribに導入された新機能については別の記事で紹介予定です。


2.1. coreモジュール

CPU/GPU実装のカプセル化: UMat

 OpenCV 3.0よりCPU/GPU実装のカプセル化を行うための仕組みであるT-API(transparent API)が導入されました。そのため、OpenCVユーザーは、T-APIで提供されるUMatと呼ばれるデータ構造を用いて実装することで、CPU/GPUどちらでも動作する処理を同一コードで記述できます。

 図1にUMatを用いた場合の内部処理の概要を示します。

  1. OpenCLが使える環境かどうかをチェックする
  2. OpenCLが使える環境であればOpenCVで用意しているOpenCL実装を用い、そうでなければMat(=CPU版の、画像データの入れもの)の実装を用いる

 ただし、図1の青で囲んだ内部処理はOpenCV内部に隠ぺいされているため、OpenCVユーザーがこれらの処理を記述する必要はありません。

UMatの内部処理 図1 UMatの内部処理

 また、図2は、「CVPR 2015チュートリアル資料」(英語)で紹介されているT-APIの計測結果です。この結果よりT-API(OpenCL)を用いることで、Matを用いた場合に比べて高速化できていることが分かります。ただし、計測環境によって効果は異なるので参考程度とした方がよいでしょう。

T-APIによる高速化(CVPR 2015チュートリアル資料) 図2 T-APIによる高速化(CVPR 2015チュートリアル資料から引用)

●サンプルコード(CPU/GPU実装のカプセル化: UMat)

 UMatを使ってグレースケール化を行うサンプルコードを以下に示します。

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>

#include <iostream>

int main(int argc, char *argv[])
{
  // (1)画像データをファイル(この例では「lena.jpg」)から読み込む
  cv::Mat img = cv::imread("lena.jpg", cv::IMREAD_COLOR);

  // 画像の読み込みに失敗したらエラー終了する
  if (img.empty())
  {
    std::cerr << "Failed to open image file." << std::endl;
    return -1;
  }

  // (2)UMatのインスタンスを定義する
  cv::UMat u_img, u_gray;

  // (3)MatのデータをUMatにコピーする
  img.copyTo(u_img);

  // (4)UMatのインスタンスを用いてグレースケール化を行う
  cv::cvtColor(u_img, u_gray, cv::COLOR_BGR2GRAY);

  return 0;
}

サンプルコード(CPU/GPU実装のカプセル化: UMat)

●参考URL


2.2. shapeモジュール

2D shape matching

 OpenCV 3.0より形状に関する処理を行うためのshapeモジュールが追加されています。このモジュールでは、輪郭線(contour)の形状の距離(距離が短いほど形状が近い)を算出するメソッドShapeDistanceExtractor::computeDistanceが提供されています。このメソッドを用いることで形状のマッチングを行うことができます。

●サンプルコード(2D shape matching)

 shapeモジュールのShapeDistanceExtractor::computeDistanceメソッドを用いて形状のマッチングを行うサンプルコードを以下に示します。

#include <opencv2/core.hpp>
#include <opencv2/shape.hpp>
#include <opencv2/imgcodecs.hpp>

#include <iostream>

static std::vector<cv::Point> simpleContour(const cv::Mat& src)
{
  std::vector<std::vector<cv::Point>> contours;
  std::vector<cv::Point> contour_points;
  cv::findContours(src, contours, cv::RETR_LIST, cv::CHAIN_APPROX_NONE);
  size_t contours_size = contours.size();

  for (size_t border = 0; border < contours_size; border++)
  {
    size_t contour_size = contours[border].size();
    for (size_t p = 0; p < contour_size; p++)
    {
      contour_points.push_back(contours[border][p]);
    }
  }
  return contour_points;
}

int main(int argc, char** argv)
{
  if (argc < 3)
  {
    std::cerr << "Usage: " << argv[0] << " <filename1> <filename2>" << std::endl;
    return -1;
  }

  // (1)画像データをファイルから読み込む
  cv::Mat img1 = cv::imread(argv[1], cv::IMREAD_GRAYSCALE);
  cv::Mat img2 = cv::imread(argv[2], cv::IMREAD_GRAYSCALE);

  // 画像の読み込みに失敗したらエラー終了する
  if (img1.empty() || img2.empty())
  {
    std::cerr << "Failed to open image file." << std::endl;
    return -1;
  }

  // (2)画像データから輪郭線(contour)データを生成する
  std::vector<cv::Point> contour1 = simpleContour(img1);
  std::vector<cv::Point> contour2 = simpleContour(img2);

  // (3)輪郭線同士の距離を算出する
  cv::Ptr<cv::ShapeContextDistanceExtractor> mysc = 
    cv::createShapeContextDistanceExtractor();
  float distance = mysc->computeDistance(contour1, contour2);

  std::cout << "Distance between " << argv[1] << " and " << 
    argv[2] << " is: " << distance << std::endl;

  return 0;
}

サンプルコード(2D shape matching)

●実行結果

 前述のサンプルコードの実行結果は以下の通りです。形状が近いものについてdistanceの値が小さくなっていることが分かります。

サンプルコードの実行結果


2.3 features2dモジュール

KAZE/AKAZE特徴量

 OpenCV 3.0よりfeatures2dモジュールにKAZE特徴量、AKAZE特徴量の実装が追加されました。KAZE特徴量、AKAZE特徴量については作者のホームページ(英語)を参照してください。

●サンプルコード(AKAZE特徴量)

 AKAZE特徴量を用いたサンプルコードを以下に示します。

#include <opencv2/core.hpp>
#include <opencv2/features2d.hpp>
#include <opencv2/imgcodecs.hpp>

#include <iostream>
#include <vector>

int main(int argc, const char** argv)
{
  // (1)画像データをファイル(この例では「lena.jpg」)から読み込む
  cv::Mat img = cv::imread("lena.jpg", cv::IMREAD_COLOR);

  // 画像の読み込みに失敗したらエラー終了する
  if (img.empty())
  {
    std::cerr << "Failed to open image file." << std::endl;
    return -1;
  }

  cv::Mat dst, descriptors;
  std::vector<cv::KeyPoint> keyPoints;

  // (2)検出器(AKAZE)を初期化する
  cv::Ptr<cv::AKAZE> detector = cv::AKAZE::create();

  // (3)キーポイント検出およびディスクリプター計算を行う
  detector->detectAndCompute(img, cv::noArray(), keyPoints, descriptors);

  // (4)キーポイントを描画する
  cv::drawKeypoints(img, keyPoints, dst, 
    cv::Scalar::all(-1), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);

  return 0;
}

サンプルコード(AKAZE特徴量)

●実行結果(AKAZE特徴量)

図3 入力画像図4 キーポイント描画結果

●参考URL

       1|2 次のページへ

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。