web-dev-qa-db-ja.com

PythonまたはOpenCVのC ++コーディングの間でパフォーマンスは異なりますか?

私は少しずつopencvを起動することを目指していますが、最初にOpenCVのどのAPIがより有用かを判断する必要があります。 Python実装は短くなりますが、実行時間はネイティブC++実装に比べて密度が高く、遅くなります。これら2つの観点のパフォーマンスとコーディングの違いについてコメントできる人はいますか?

59
erogol

前の回答で述べたように、PythonはC++やCと比較して低速です。Pythonは、プログラミングのトラブルではなく、アルゴリズムのみを心配する必要がある単純さ、移植性、さらに創造性のために構築されています。

しかし、ここOpenCVでは、何か違うことがあります。 Python-OpenCVは、元のC/C++コードの単なるラッパーです。通常、両方の言語の最高の機能、C/C++のパフォーマンスとPythonのシンプルさの組み合わせに使用されます。

したがって、PythonからOpenCVの関数を呼び出すと、実際に実行されるのはC/C++ソースの基礎となります。そのため、パフォーマンスに大きな違いはありません。(パフォーマンスのペナルティは1%未満であるということをどこかで読んだことを覚えています。OpenCVのいくつかの基本的な関数の概算ではworst-case<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)で利用可能な配列操作機能を使用してください。 C = A+Bを使用して2つのnumpy配列を単純に追加することは、二重ループを使用するよりもはるかに高速です。

たとえば、次の記事を確認できます。

  1. Pythonでの高速配列操作
  2. OpenCV-Pythonインターフェイス、cvおよびcv2のパフォーマンス比較
134
Abid Rahman K

OpenCVのGoogleの結果はすべて同じです。つまり、pythonは少しだけ遅くなります。しかし、プロファイリングは一度も見たことがありません。

単純なプログラムであっても、Pythonはopencvを使用したC++よりも大幅に低速です。

私が考えることができる最も簡単な例は、ウェブカメラの出力を画面に表示し、1秒あたりのフレーム数を表示することでした。 pythonを使用して、50FPSを達成しました(Intelアトムで)。 C++を使用すると、65FPS、25%増加しました。どちらの場合も、CPU使用率は単一のコアを使用しており、私の知る限り、CPUのパフォーマンスに制約されていました。さらに、このテストケースは、過去に1つのプロジェクトから別のプロジェクトに移植したプロジェクトで見たものと一致しています。

この違いはどこから来たのですか? pythonでは、すべてのopenCV関数は画像行列の新しいコピーを返します。画像をキャプチャするたびに、またはサイズを変更する場合は、C++で既存のメモリを再利用できます。 In pythonできません。他の人が言ったように、メモリの割り当てに費やした時間は大きな違いだと思います。openCVの基礎となるコードはC++です。

投げる前にpython out of the window: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;
        }
    }
}

考えられるベンチマークの制限:

  • カメラのフレームレート
  • タイマー測定精度
  • 印刷フォーマットに費やした時間
8
sdfgeoff

sdfgeoffからの回答 には、Pythonで配列を再利用するcanという事実がありません。それらを事前に割り当てて渡すと、使用されます。そう:

    image = numpy.zeros(shape=(height, width, 3), dtype=numpy.uint8)
    #....
    retval, _ = cv.VideoCapture.read(image)
3
Paul Rensing

あなたは正しい、PythonはC++が必要としないインタープリターを必要とするため、ほとんどの場合C++よりも大幅に遅くなります。ただし、C++は強く型付けされ、エラーのマージン:厳密にコーディングすることを好む人もいれば、Python固有の寛大さを享受する人もいます。

Pythonコーディングスタイルvs. C++コーディングスタイルについての完全な説明が必要な場合、これは最適な場所ではありません。記事を見つけてください。

編集:Pythonはインタープリター型言語であり、C++はマシンコードにコンパイルされるため、一般的に言えば、C++を使用するとパフォーマンス上の利点が得られますが、OpenCVの使用に関しては、コアOpenCVライブラリは既にマシンコードにコンパイルされているため、OpenCVライブラリのラッパーPython言い換えると、Pythonから計算コストの高いOpenCVアルゴリズムを実行する場合、作業している特定のアーキテクチャ用にコンパイルされているため、パフォーマンスに大きな影響はありません。

3
Callum McLean