私はopencvを少しずつ始めることを目指していますが、最初にOpenCVのどのAPIがより有用であるかを決定する必要があります。Pythonの実装は短いと予測していますが、ネイティブのC ++実装と比較すると、実行時間はより高密度で低速になります。これら2つの観点のパフォーマンスとコーディングの違いについてコメントできる知識はありますか?
5 に答える
以前の回答で述べたように、PythonはC ++やCに比べて低速です。Pythonは、そのシンプルさ、移植性、さらに、ユーザーがプログラミングの問題ではなくアルゴリズムについてのみ心配する必要がある創造性のために構築されています。
しかし、ここOpenCVには、何か違うものがあります。Python-OpenCVは、元のC /C++コードの単なるラッパーです。これは通常、C /C++のパフォーマンスとPythonのシンプルさの両方の言語の最高の機能を組み合わせるために使用されます。
したがって、PythonからOpenCVで関数を呼び出すと、実際に実行されるのは基盤となるC /C++ソースです。したがって、パフォーマンスに大きな違いはありません(パフォーマンスペナルティが1%未満であることをどこかで読んだことを覚えていますが、どこを覚えていません。OpenCVのいくつかの基本関数を使用した概算では、最悪の場合のペナルティが示され<4%
ます。つまりpenalty = [maximum time taken in Python - minimum time taken in C++]/minimum time taken in C++
) 。
コードに多くのネイティブPythonコードが含まれている場合、問題が発生します。たとえば、OpenCVで使用できない独自の関数を作成している場合、状況はさらに悪化します。このようなコードはPythonでネイティブに実行されるため、パフォーマンスが大幅に低下します。
しかし、新しいOpenCV-PythonインターフェースはNumpyを完全にサポートしています。Numpyは、Pythonの科学計算用のパッケージです。また、ネイティブCコードのラッパーでもあります。高度に最適化されたライブラリであり、さまざまな行列演算をサポートし、画像処理に非常に適しています。したがって、OpenCV関数とNumpy関数の両方を正しく組み合わせることができれば、非常に高速なコードが得られます。
覚えておくべきことは、Pythonでは常にループや反復を避けるようにすることです。代わりに、Numpy(およびOpenCV)で利用可能な配列操作機能を使用してください。を使用して2つのnumpy配列を追加するだけC = A+B
で、ダブルループを使用するよりもはるかに高速です。
たとえば、次の記事を確認できます。
openCVのすべてのグーグルの結果は同じです:そのPythonはわずかに遅くなるだけです。しかし、そのプロファイリングを見たことがありません。だから私はいくつかを行うことにし、発見しました:
Pythonは、些細なプログラムであっても、opencvを使用したC++よりも大幅に低速です。
私が考えることができる最も簡単な例は、Webカメラの出力を画面に表示し、1秒あたりのフレーム数を表示することでした。Pythonで、私は50FPS(Intelアトム上)を達成しました。C ++では、25%増加して65FPSを取得しました。どちらの場合も、CPU使用率は単一のコアを使用しており、私の知る限り、CPUのパフォーマンスによって制限されていました。さらに、このテストケースは、過去に移植したプロジェクトで見たものと一致しています。
この違いはどこから来るのですか?Pythonでは、すべてのopenCV関数が画像行列の新しいコピーを返します。画像をキャプチャするとき、または画像のサイズを変更するときはいつでも、C++では既存のメモリを再利用できます。Pythonではできません。他の人が言っているように、openCVの基礎となるコードはC ++であるため、このメモリの割り当てに費やされた時間が大きな違いだと思います。
Pythonをウィンドウから外す前に:Pythonは開発がはるかに高速であり、ハードウェアの制約に直面していない場合、または開発速度がパフォーマンスよりも重要である場合は、Pythonを使用します。私がopenCVで行った多くのアプリケーションでは、Pythonで開始し、後でコンピュータービジョンコンポーネントのみをC ++に変換しました(たとえば、Pythonのctypeモジュールを使用してCVコードを共有ライブラリにコンパイルします)。
Pythonコード:
import cv2
import time
FPS_SMOOTHING = 0.9
cap = cv2.VideoCapture(2)
fps = 0.0
prev = time.time()
while True:
now = time.time()
fps = (fps*FPS_SMOOTHING + (1/(now - prev))*(1.0 - FPS_SMOOTHING))
prev = now
print("fps: {:.1f}".format(fps))
got, frame = cap.read()
if got:
cv2.imshow("asdf", frame)
if (cv2.waitKey(2) == 27):
break
C ++コード:
#include <opencv2/opencv.hpp>
#include <stdint.h>
using namespace std;
using namespace cv;
#define FPS_SMOOTHING 0.9
int main(int argc, char** argv){
VideoCapture cap(2);
Mat frame;
float fps = 0.0;
double prev = clock();
while (true){
double now = (clock()/(double)CLOCKS_PER_SEC);
fps = (fps*FPS_SMOOTHING + (1/(now - prev))*(1.0 - FPS_SMOOTHING));
prev = now;
printf("fps: %.1f\n", fps);
if (cap.isOpened()){
cap.read(frame);
}
imshow("asdf", frame);
if (waitKey(2) == 27){
break;
}
}
}
考えられるベンチマークの制限:
- カメラのフレームレート
- タイマー測定精度
- 印刷フォーマットに費やされた時間
そうです、Pythonはインタプリタを必要とするため、ほとんどの場合C++よりも大幅に低速ですがC++は必要ありません。ただし、これにはC ++を強く型付けする必要があるため、エラーの許容範囲ははるかに小さくなります。厳密にコーディングすることを好む人もいれば、Python固有の寛大さを楽しむ人もいます。
PythonコーディングスタイルとC++コーディングスタイルについて完全に話し合いたい場合は、これが最適な場所ではありません。記事を見つけてみてください。
編集:Pythonはインタプリタ言語であるため、C ++はマシンコードにコンパイルされますが、一般的に言えば、C++を使用するとパフォーマンス上の利点を得ることができます。ただし、OpenCVの使用に関しては、コアOpenCVライブラリはすでにマシンコードにコンパイルされているため、OpenCVライブラリのPythonラッパーはコンパイルされたコードを実行しています。言い換えると、Pythonから計算コストの高いOpenCVアルゴリズムを実行する場合、使用している特定のアーキテクチャ用に既にコンパイルされているため、パフォーマンスに大きな影響はありません。
sdfgeoffからの答えには、Pythonで配列を再利用できるという事実が欠けています。それらを事前に割り当てて渡すと、それらは使用されます。それで:
image = numpy.zeros(shape=(height, width, 3), dtype=numpy.uint8)
#....
retval, _ = cv.VideoCapture.read(image)
なぜ選ぶのですか?Python
との両方を知っている場合はC++
、を使用Python
して調査に使用しJupyter Notebooks
、次にC++
実装に使用します。のPython
スタックJupyter
、OpenCV (cv2)
およびNumpy
ラピッドプロトタイピングを提供します。コードの移植C++
は通常、非常に簡単です。