17

現在、OpenCV API ( C++) を使用していくつかのアプリケーションを開発しています。このアプリケーションは、ビデオで処理を行います。

PC では、すべてが非常に高速に動作します。そして今日、このアプリケーションを Android に移植することにしました (カメラをビデオ入力として使用するため)。幸いなことに、Android 用の OpenCV があるので、サンプルの Android アプリケーションにネイティブ コードを追加しました。パフォーマンス以外はすべて正常に動作します。アプリケーションのベンチマークを行ったところ、アプリケーションは 4 ~ 5 fps で動作することがわかりましたが、これは実際には受け入れられません (私のデバイスにはシングルコア 1 GHz プロセッサが搭載されています)。約 10 fps で動作させたいのです。

でアプリケーションを完全に書き直すことは理にかなっていますCか? そのようなものを使用することが開発者にとって非常に快適であることは知っていstd::vectorますが、私はそれを気にしません。

インターフェイスには、OpenCV's Cインターフェイスと同じ機能/メソッドがあるようC++です。

この質問をグーグルで検索しましたが、何も見つかりませんでした。

アドバイスをありがとう。

4

7 に答える 7

56

私は Android と最適化 (フレームを 4 ミリ秒で処理するビデオ処理アプリを作成しました) にかなり取り組んできたので、適切な回答を提供できることを願っています。

OpenCV では、C と C++ のインターフェイスに大きな違いはありません。コードの一部は C で書かれており、C++ ラッパーを持っています。この 2 つの大きな違い (Shervin Emami によって測定) は、リグレッション、バグ修正、または品質の向上のいずれかです。最新の OpenCV バージョンを使用する必要があります。

なぜ書き直さない?

かなりの時間を費やすことになりますが、その時間をもっと有効に使うことができます。C インターフェイスは扱いにくく、バグやメモリ リークが発生する可能性が高くなります。私の意見では、あなたはそれを避けるべきです。

最適化のアドバイス

A.最適化をオンにします。

コンパイラの最適化とデバッグ アサーションの欠如の両方が、実行時間に大きな違いをもたらす可能性があります。

B.アプリをプロファイリングします。

はるかに簡単なので、最初にコンピューターで実行してください。Visual Studio プロファイラーを使用して、遅い部分を特定します。それらを最適化します。遅いと思うからではなく、測定するから最適化しないでください。最も遅い関数から始めて、可能な限り最適化してから、2 番目に遅い関数を使用します。変更を測定して、実際に高速であることを確認します。

C.アルゴリズムに焦点を当てる。

より高速なアルゴリズムは、桁違い (100 倍) にパフォーマンスを向上させることができます。C++ のトリックを使用すると、おそらく 2 倍のパフォーマンスが向上します。

古典的なテクニック:

  • ビデオ フレームのサイズを小さくします。多くの場合、1024x768 の代わりに 200x300px の画像から情報を抽出できます。最初のものの面積は 10 分の 1 です。

  • 複雑な操作ではなく、より単純な操作を使用してください。浮動小数点の代わりに整数を使用してください。また、何千回も実行doubleされる行列やループでは決して使用しないでください。for

  • できるだけ少ない計算を行います。すべてのフレームですべてのオブジェクトを処理するのではなく、画像の特定の領域でのみオブジェクトを追跡できますか? 非常に小さな画像で大まかな/おおよその検出を行い、フル フレームの ROI でそれを調整できますか?

D.必要に応じて C を使用する

ループでは、C++ の代わりに C スタイルを使用することが理にかなっている場合があります。データ行列または float 配列へのポインターは、mat.at または std::vector<> よりもはるかに高速です。多くの場合、ボトルネックはネストされたループです。それに集中してください。vector<> を至る所で置き換えて、コードをスパゲッティ化するのは意味がありません。

E.隠れたコストを回避する

一部の OpenCV 関数は、データを double に変換し、処理してから、入力形式に変換します。それらに注意してください。モバイル デバイスのパフォーマンスが低下します。例: ワーピング、スケーリング、型変換。また、色空間の変換は遅延することが知られています。ネイティブ YUV から直接取得したグレースケールを優先します。

F.ベクトル化を使用する

ARM プロセッサは、NEON と呼ばれるテクノロジを使用してベクトル化を実装します。それを使用することを学びます。パワフルです!

小さな例:

float* a, *b, *c;
// init a and b to 1000001 elements
for(int i=0;i<1000001;i++)
    c[i] = a[i]*b[i];

は次のように書き直すことができます。より冗長ですが、はるかに高速です。

float* a, *b, *c;
// init a and b to 1000001 elements
float32x4_t _a, _b, _c;
int i;
for(i=0;i<1000001;i+=4)
{  
    a_ = vld1q_f32( &a[i] ); // load 4 floats from a in a NEON register
    b_ = vld1q_f32( &b[i] );
    c_ = vmulq_f32(a_, b_); // perform 4 float multiplies in parrallel
    vst1q_f32( &c[i], c_); // store the four results in c
}
// the vector size is not always multiple of 4 or 8 or 16. 
// Process the remaining elements
for(;i<1000001;i++)
    c[i] = a[i]*b[i];

純粋主義者は、アセンブラーで書かなければならないと言いますが、通常のプログラマーにとっては少し気が遠くなります。上記の例のように、gcc 組み込み関数を使用して良い結果が得られました。

すぐに開始する別の方法は、OpenCV でハンドコーディングされた SSE 最適化コードを NEON に変換することです。SSE は Intel プロセッサの NEON に相当するものであり、ここのように多くの OpenCV 関数で使用されています。これは、uchar 行列 (通常の画像形式) の画像フィルタリング コードです。盲目的に命令を 1 つずつ変換する必要はありませんが、最初は例として取り上げてください。

NEON の詳細については、このブログと次の投稿をご覧ください。

G.画像のキャプチャに注意する

モバイルデバイスでは驚くほど遅くなる可能性があります。それを最適化することは、デバイスと OS 固有です。

于 2012-07-07T16:46:10.573 に答える
6

このような決定を下す前に、コードをプロファイリングして、コード内のホットスポットを特定する必要があります。この情報がなければ、処理を高速化するために行った変更は当て推量になります。このAndroid NDK プロファイラーを試しましたか?

于 2012-07-07T15:51:03.277 に答える
4

shervin imami が彼の Web サイトで行ったいくつかのパフォーマンス テストがあります。それをチェックして、いくつかのアイデアを得ることができます。

http://www.shervinemami.info/timingTests.html

それが役に立てば幸い。

(また、パフォーマンスを向上させる方法があれば、どこかで独自の調査結果を共有していただければ幸いです。)

于 2012-07-07T15:48:31.687 に答える
3

複数のテストで次のことに気付きました。

  1. C インターフェイス (IplImage) は、Mat.at(x,y) メソッドを使用する代わりにピクセルに直接アクセスする場合、何倍も高速です。C++ アプリケーションを C に変換すると、ブロブ検出ルーチンのパフォーマンスが 3 倍向上しました。

  2. 外部アプリケーション (LabView など) から呼び出すと、特定のルーチンで C++ インターフェイスがクラッシュしますが、C で同じルーチンを呼び出すと機能します。この例は、FindContours と cvFindContours です。

  3. C は、組み込みデバイスとの互換性がはるかに優れています。しかし、私はまだこの分野で何もしていません。

于 2013-03-13T20:06:46.500 に答える
3

C は C++ よりも高速ですか? 答えはノーです。どちらもネイティブの機械語にコンパイルされ、C++ は C と同じくらい高速になるように設計されており、STL (特に ISO 標準) も設計されており、ポインターと同じくらい高速であり、柔軟性を提供するように注意が払われています。C を使用する唯一の理由は、お使いのプラットフォームが C++ をサポートしていないということです。率直に申し上げると、すべてを C に変換しないでください。おそらくほとんど同じパフォーマンスが得られるからです。代わりに、コードを改善するか、opencv の他の機能を使用して、必要なことを実行してください。

納得できませんか?それでは、単純な関数を C で 1 回、C++ で 1 回作成し、それを 1 億回のループで実行して、自分で時間を測定します。多分これはあなたが正しい決定を下すのに役立ちます

于 2012-07-07T15:53:51.003 に答える
3

Android で C や C++ を使用したことはありません。しかし、PC では、C++ を C コードと同じくらい高速に (場合によってはさらに高速に) 実行できます。ほとんどの C++ は、より多くの機能を使用できるように特別に設計されていますが、速度を犠牲にすることはありません (テンプレートはコンパイル時に解決されます)。ほとんどのコンパイラはコードの最適化に優れており、std::vector 呼び出しはインライン化され、コードはネイティブ C 配列を使用する場合とほぼ同じになります。

パフォーマンスを向上させる別の方法を探すことをお勧めします。Android には、アクセスしてコードを最適化するために使用できるマルチメディア ハードウェア拡張機能がいくつかあるかもしれません。

于 2012-07-07T15:55:53.953 に答える
1

IOS デバイスで同様の問題があり、IOS/iPad/iPhone からの最大速度についての議論には、他のモバイル プラットフォームにも適用できるヒントが含まれています。

于 2012-08-13T05:00:36.607 に答える