OpenCVチュートリアル:iOSでMSERを使用したリアルタイムのオブジェクト検出

公開: 2022-03-11

過去数年間で、携帯電話の平均パフォーマンスは大幅に向上しました。 CPUの処理能力やRAMの容量が非常に大きい場合でも、モバイルハードウェアで計算量の多いタスクを実行するのが簡単になりました。 これらのモバイルテクノロジーは正しい方向に向かっていますが、特に拡張現実、仮想現実、人工知能の出現により、モバイルプラットフォームでやるべきことはまだたくさんあります。

コンピュータビジョンの主な課題は、画像内の関心のあるオブジェクトを検出することです。 人間の目と脳は並外れた仕事をしており、これを機械で複製することは今でも夢です。 ここ数十年にわたって、これを機械で模倣するためのアプローチが開発され、それはますます良くなっています。

このチュートリアルでは、画像内のブロブの検出に使用されるアルゴリズムについて説明します。 また、オープンソースライブラリであるOpenCVのアルゴリズムを使用して、リアカメラを使用して画像を取得し、その中のオブジェクトを検出するiPhoneのプロトタイプアプリケーションを実装します。

OpenCVチュートリアル

OpenCVは、主要なコンピュータービジョンと機械学習アルゴリズムの実装を提供するオープンソースライブラリです。 顔、ポーカーテーブルのトランプ、または任意の画像に効果を追加するための単純なアプリケーションを検出するアプリケーションを実装する場合は、OpenCVが最適です。

OpenCVはC/C ++で記述されており、すべての主要なプラットフォーム用のラッパーライブラリがあります。 これにより、iOS環境内で特に使いやすくなります。 Objective-C iOSアプリケーション内で使用するには、公式WebサイトからOpenCViOSFrameworkをダウンロードしてください。 最新バージョンの3.0では、ヘッダーファイルの編成方法に互換性を破るような変更が加えられているため、iOS用のOpenCVのバージョン2.4.11(この記事では使用していることを前提としています)を使用していることを確認してください。 インストール方法の詳細については、Webサイトに記載されています。

MSER

MSERは、Maximally Stable Extremal Regionsの略で、画像内のブロブ検出に使用できる多くの方法の1つです。 簡単に言うと、アルゴリズムは、外側の境界ピクセルの強度が内側の境界のピクセル強度よりも高い(指定されたしきい値だけ)連続したピクセルのセットを識別します。 このような領域は、さまざまな強度であまり変化しない場合、最大限に安定していると言われます。

他の多くのブロブ検出アルゴリズムが存在しますが、MSERは、実行時の複雑さがかなり軽いO(n log(log(n)))であるため、ここで選択されました。ここで、nは画像上のピクセルの総数です。 このアルゴリズムは、ぼかしや拡大縮小にも堅牢であり、携帯電話のカメラなどのリアルタイムソースから取得した画像を処理する場合に有利です。

このチュートリアルでは、Toptalのロゴを検出するアプリケーションを設計します。 シンボルには鋭い角があり、それは、Toptalのロゴを検出するのに角検出アルゴリズムがどれほど効果的であるかを考えるように導くかもしれません。 結局のところ、このようなアルゴリズムは使いやすく、理解しやすいものです。 コーナーベースの方法は、背景から明確に分離されたオブジェクト(白い背景上の黒いオブジェクトなど)の検出に関しては高い成功率を示す可能性がありますが、現実の世界でToptalのロゴをリアルタイムで検出することは困難です。画像。アルゴリズムは常に数百のコーナーを検出します。

ストラテジー

機械学習とopencv

アプリケーションがカメラを介して取得する画像のフレームごとに、最初にグレースケールに変換されます。 グレースケール画像の色のチャネルは1つだけですが、それでもロゴは表示されます。 これにより、アルゴリズムが画像を処理しやすくなり、アルゴリズムが処理する必要のあるデータの量が大幅に削減され、追加のゲインがほとんどまたはまったくなくなります。

次に、OpenCVの実装アルゴリズムを使用して、すべてのMSERを抽出します。 次に、各MSERは、最小の境界矩形を正方形に変換することによって正規化されます。 ロゴはさまざまな角度や距離から取得される可能性があり、これにより遠近法による歪みの許容度が高まるため、この手順は重要です。

さらに、MSERごとにいくつかのプロパティが計算されます。

  • 穴の数
  • 凸包の面積に対するMSERの面積の比率
  • 最小面積の長方形の面積に対するMSERの面積の比率
  • MSERの面積に対するMSERスケルトンの長さの比率
  • 最大輪郭の面積に対するMSERの面積の比率

iOSアプリケーションと機械学習

画像内のToptalのロゴを検出するために、すべてのMSERのプロパティが、すでに学習されているToptalのロゴプロパティと比較されます。 このチュートリアルの目的のために、各プロパティの最大許容差は経験的に選択されました。

最後に、最も類似した領域が結果として選択されます。

iOSアプリケーション

iOSからOpenCVを使用するのは簡単です。 まだ行っていない場合は、iOSアプリケーションを作成してOpenCVを使用するためのXcodeのセットアップに関連する手順の概要を以下に示します。

  1. 新しいプロジェクト名「SuperCoolLogoDetector」を作成します。 言語として、Objective-Cを選択したままにします。

  2. 新しいプリフィックスヘッダー(.pch)ファイルを追加し、PrefixHeader.pchという名前を付けます

  3. プロジェクト「SuperCoolLogoDetector」ビルドターゲットに移動し、「ビルド設定」タブで「プレフィックスヘッダー」設定を見つけます。 LLVM言語セクションで見つけるか、検索機能を使用できます。

  4. 「PrefixHeader.pch」をプレフィックスヘッダー設定に追加します

  5. この時点で、iOS 2.4.11用のOpenCVをインストールしていない場合は、ここでインストールしてください。

  6. ダウンロードしたフレームワークをプロジェクトにドラッグアンドドロップします。 ターゲット設定の「リンクされたフレームワークとライブラリ」をチェックします。 (自動的に追加する必要がありますが、安全のために追加することをお勧めします。)

  7. さらに、次のフレームワークをリンクします。

    • AVFoundation
    • AssetsLibrary
    • CoreMedia
  8. 「PrefixHeader.pch」を開き、次の3行を追加します。

     #ifdef __cplusplus #include <opencv2/opencv.hpp> #endif”
  9. 自動作成されたコードファイルの拡張子を「 .m」から「 .mm」に変更します。 OpenCVはC++で記述されており、*。mmを使用すると、Objective-C++を使用することになります。

  10. ViewController.hに「opencv2/highgui / cap_ios.h」をインポートし、プロトコルCvVideoCameraDelegateに準拠するようにViewControllerを変更します。

     #import <opencv2/highgui/cap_ios.h>
  11. Main.storyboardを開き、UIImageViewを最初のViewControllerに配置します。

  12. 「imageView」という名前のViewController.mmへのアウトレットを作成します

  13. 変数「CvVideoCamera*camera;」を作成します。 ViewController.hまたはViewController.mmで、リアカメラへの参照を使用して初期化します。

     camera = [[CvVideoCamera alloc] initWithParentView: _imageView]; camera.defaultAVCaptureDevicePosition = AVCaptureDevicePositionBack; camera.defaultAVCaptureSessionPreset = AVCaptureSessionPreset640x480; camera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait; camera.defaultFPS = 30; camera.grayscaleMode = NO; camera.delegate = self;
  14. 今すぐプロジェクトをビルドすると、XcodeはCvVideoCameraDelegateの「processImage」メソッドを実装していないことを警告します。 今のところ、簡単にするために、カメラから画像を取得し、簡単なテキストでオーバーレイします。

    • 「viewDidAppear」に1行追加します。
     [camera start];
    • これで、アプリケーションを実行すると、カメラにアクセスするための許可を求められます。 そして、あなたはカメラからのビデオを見るはずです。

    • 「processImage」メソッドに、次の2行を追加します。

     const char* str = [@"Toptal" cStringUsingEncoding: NSUTF8StringEncoding]; cv::putText(image, str, cv::Point(100, 100), CV_FONT_HERSHEY_PLAIN, 2.0, cv::Scalar(0, 0, 255));

それはほとんどそれです。 これで、カメラからの画像に「Toptal」というテキストを描画する非常にシンプルなアプリケーションができました。 これで、この単純なアプリケーションからターゲットロゴ検出アプリケーションを構築できます。 簡潔にするために、この記事では、アプリケーションが全体的にどのように機能するかを理解するために重要な、ほんの一握りのコードセグメントについてのみ説明します。 GitHubのコードには、各セグメントの機能を説明するためのかなりの量のコメントがあります。

アプリケーションの目的はToptalのロゴを検出することだけなので、起動するとすぐに、MSER機能が指定されたテンプレート画像から抽出され、値がメモリに保存されます。

 cv::Mat logo = [ImageUtils cvMatFromUIImage: templateImage]; //get gray image cv::Mat gray; cvtColor(logo, gray, CV_BGRA2GRAY); //mser with maximum area is std::vector<cv::Point> maxMser = [ImageUtils maxMser: &gray]; //get 4 vertices of the maxMSER minrect cv::RotatedRect rect = cv::minAreaRect(maxMser); cv::Point2f points[4]; rect.points(points); //normalize image cv::Mat M = [GeometryUtil getPerspectiveMatrix: points toSize: rect.size]; cv::Mat normalizedImage = [GeometryUtil normalizeImage: &gray withTranformationMatrix: &M withSize: rect.size.width]; //get maxMser from normalized image std::vector<cv::Point> normalizedMser = [ImageUtils maxMser: &normalizedImage]; //remember the template self.logoTemplate = [[MSERManager sharedInstance] extractFeature: &normalizedMser]; //store the feature [self storeTemplate];

アプリケーションには、開始/停止ボタンのある画面が1つだけあり、FPSや検出されたMSERの数など、必要なすべての情報が画像に自動的に描画されます。 アプリケーションが停止していない限り、カメラ内のすべての画像フレームに対して、次のprocessImageメソッドが呼び出されます。

 -(void)processImage:(cv::Mat &)image { cv::Mat gray; cvtColor(image, gray, CV_BGRA2GRAY); std::vector<std::vector<cv::Point>> msers; [[MSERManager sharedInstance] detectRegions: gray intoVector: msers]; if (msers.size() == 0) { return; }; std::vector<cv::Point> *bestMser = nil; double bestPoint = 10.0; std::for_each(msers.begin(), msers.end(), [&] (std::vector<cv::Point> &mser) { MSERFeature *feature = [[MSERManager sharedInstance] extractFeature: &mser]; if(feature != nil) { if([[MLManager sharedInstance] isToptalLogo: feature] ) { double tmp = [[MLManager sharedInstance] distance: feature ]; if ( bestPoint > tmp ) { bestPoint = tmp; bestMser = &mser; } } } }); if (bestMser) { NSLog(@"minDist: %f", bestPoint); cv::Rect bound = cv::boundingRect(*bestMser); cv::rectangle(image, bound, GREEN, 3); } else { cv::rectangle(image, cv::Rect(0, 0, W, H), RED, 3); } // Omitted debug code [FPS draw: image]; }

この方法は、本質的に、元の画像のグレースケールコピーを作成します。 すべてのMSERを識別し、それらに関連する機能を抽出し、テンプレートとの類似性について各MSERをスコアリングし、最適なものを選択します。 最後に、最適なMSERの周囲に緑色の境界線を描画し、画像にメタ情報をオーバーレイします。

以下は、このアプリケーションにおけるいくつかの重要なクラスの定義とそれらのメソッドです。 それらの目的はコメント内に記述されています。

GeometryUtil.h

 /* This static class provides perspective transformation function */ @interface GeometryUtil : NSObject /* Return perspective transformation matrix for given points to square with origin [0,0] and with size (size.width, size.width) */ + (cv::Mat) getPerspectiveMatrix: (cv::Point2f[]) points toSize: (cv::Size2f) size; /* Returns new perspecivly transformed image with given size */ + (cv::Mat) normalizeImage: (cv::Mat *) image withTranformationMatrix: (cv::Mat *) M withSize: (float) size; @end

MSERManager.h

 /* Singelton class providing function related to msers */ @interface MSERManager : NSObject + (MSERManager *) sharedInstance; /* Extracts all msers into provided vector */ - (void) detectRegions: (cv::Mat &) gray intoVector: (std::vector<std::vector<cv::Point>> &) vector; /* Extracts feature from the mser. For some MSERs feature can be NULL !!! */ - (MSERFeature *) extractFeature: (std::vector<cv::Point> *) mser; @end

MLManager.h

 /* This singleton class wraps object recognition function */ @interface MLManager : NSObject + (MLManager *) sharedInstance; /* Stores feature from the biggest MSER in the templateImage */ - (void) learn: (UIImage *) templateImage; /* Sum of the differences between logo feature and given feature */ - (double) distance: (MSERFeature *) feature; /* Returns true if the given feature is similar to the one learned from the template */ - (BOOL) isToptalLogo: (MSERFeature *) feature; @end

すべてが相互に接続された後、このアプリケーションを使用すると、iOSデバイスのカメラを使用して、さまざまな角度と方向からToptalのロゴを検出できるようになります。

画像(Toptalロゴ)を垂直方向に検出します。

シャツの画像(Toptalロゴ)を斜めに検出します。

拡張現実アプリは画像を理解することから始まります、そしてこれはあなたがそれをすることができる方法です。
つぶやき

結論

この記事では、OpenCVを使用して画像から単純なオブジェクトを検出することがいかに簡単であるかを示しました。 コード全体はGitHubで入手できます。 貢献は大歓迎ですので、気軽にフォークしてプッシュリクエストを送信してください。

機械学習の問題に当てはまるように、このアプリケーションでのロゴ検出の成功率は、オブジェクト分類に異なる機能セットと異なる方法を使用することで向上する可能性があります。 ただし、この記事が、MSERを使用したオブジェクト検出と、一般的なコンピュータービジョン技術のアプリケーションを開始するのに役立つことを願っています。

参考文献

  • J. Matas、O。Chum、M。Urban、およびT.Pajdla。 「最大限に安定した極限領域からのロバストなワイドベースラインステレオ。」
  • ノイマン、ルーカス; マタス、ジリ(2011)。 「実世界の画像におけるテキストのローカリゼーションと認識のための方法」
関連:ロボットプログラミング入門チュートリアル