2016-06-30 46 views
0

私はOpenCVとTBBで作業することを学んでいます。私はマルチコアCPUを持っているので、私のプログラムのmuticpuサポートを作成したいので、イメージのマルチプロセッシングを使う方法を学ぶ必要があります。OpenCVマルチコア画像処理用TBBタスクスケジューラの作成方法は? C++

私は彼らがfabonacci番号を使用して記事Intel®Technologyジャーナル紙の「インテル®スレッディング・ビルディング・ブロックでスケーラブルなマルチコアソフトウェアの基礎」(あなたがここhttp://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.71.8289&rep=rep1&type=pdf PDFでそれを見つけることができます)

を読んだことがありますマルチプロセッシングの例としての計算。 TBBパッケージのTBBの例にも同様のfabonacci番号の例があります(ParallelTask​​Fibを参照)。唯一の問題は計算が簡単でCPUがそれほど負担がかからないことです。少数でマルチタスキングを実行する場合、CutOffを低くするとオーバーヘッドが大きくなり効率的ではありません。ですから、TBBで作業することを学ぶためには、画像処理のより実用的な例が必要です。私の考えでは、TBBタスクスケジューラを使いたいと思っています。私はクラスFibTaskで始まり、名前を変更したParallelFib関数を使用して、引数ベクトルを画像ベクトルで動作するように変更しました。それがどのように設計されたかの基本原則はそのまま残すべきです。ファボナッチの例には、aとbという2つの子だけが含まれています。今問題は、私が1つの関数matTask(元々 '実行'と呼ばれていた)で2人以上の子供を使用できるかどうかわかりません。だから私は、より多くのポインタとより多くのポインタを追加しようとspawn_and_wait_for_all()を待って...この段階では、私はこのデザインが正しいか、パフォーマンスの問題がないかどうかを尋ねたいので、画像処理関数を作成しませんでした。それは終了していません。あなたの提案が私のコンセプトの間違いを修正するのを待つつもりです。

私の基本的な考えは、lena.jpgにガウスぼかしのようなフィルタ機能を使用することです。まず、いくつかのスレッドを渡します。私は8コアしかないので最大8スレッドしか渡すことができません。私はlenaイメージを同じサイズの8つのストリップに分割し、ピクセルをベクトル(8つの基本ベクトル)にコピーすることを計画しています。次に、それらをbluredする必要があります。次に、8つのセクションのマージンに重なる次の7-8イメージを作成する必要があるということです。私はbluringアクションだけを繰り返したい。最後に、画像の残りの部分(source_image.rows()/ 8から残っている部分)にもう1つのパスが必要です。

私が解決する必要がある主な事柄(私はやり方がわからない)は、無限ループを止めることです。 1)コーピングと2)ブラーリング3)クロッピング4)貼り付けのために、異なるクラスと異なるメソッドを作成する必要がありますか?または、1回の呼び出しですべてを渡すことができますか?これは、コードが同じことをしたので、fabonnaciの数字の例との違いですが、私はより多くのことをする必要があります...それでは、ロジック、関数の名前付け方法、

The basic idea of the strips; white areas should be overlayed 簡単な解決策は、同じサイズの8つのストリップを使用することです。次に7-8のオーバーレイ領域を使用します。

コードではエラーは表示されませんが、時間的な概念なので正しい結果を返すとは限りません。

#include "opencv2/imgproc/imgproc.hpp" 
#include "opencv2/highgui/highgui.hpp" 
#include <iostream> 
#include <stdlib.h> 
#include <stdio.h> 

#include "tbb/task.h" 
#include "tbb/task_scheduler_init.h" 

#define CutOff 12 

using namespace cv; 

void SerialAction(int n){}; 

/** 

**/ 
class matTask: public tbb::task { 
public: 
    int n; 
    const int offset; 
    std::vector<cv::Mat> main_layers; 
    std::vector<cv::Mat> overlay_layers; 

    matTask(std::vector<cv::Mat>main_layers_, std::vector<cv::Mat> overlay_layers_, int n_, const int offset_) : 
     main_layers(main_layers_), 
     overlay_layers(overlay_layers_), 
     n(n_), offset(offset_) 
     {} 

     task* execute() { 
     if(n<CutOff) { 
      SerialAction(n); 
      } 
     else { 
      // Main layers - copy regions 
      matTask& a = *new(allocate_child()) 
       matTask(main_layers,overlay_layers,n,0); 
      matTask& b = *new(allocate_child()) 
       matTask(main_layers,overlay_layers,n-1,0); 
      matTask& c = *new(allocate_child()) 
       matTask(main_layers,overlay_layers,n-2,0); 
      matTask& d = *new(allocate_child()) 
       matTask(main_layers,overlay_layers,n-3,0); 
      matTask& e = *new(allocate_child()) 
       matTask(main_layers,overlay_layers,n-4,0); 
      matTask& f = *new(allocate_child()) 
       matTask(main_layers,overlay_layers,n-5,0); 
      matTask& g = *new(allocate_child()) 
       matTask(main_layers,overlay_layers,n-6,0); 
      matTask& h = *new(allocate_child()) 
       matTask(main_layers,overlay_layers,n-7,0); 

      spawn_and_wait_for_all(a); 
      spawn_and_wait_for_all(b); 
      spawn_and_wait_for_all(c); 
      spawn_and_wait_for_all(d); 
      spawn_and_wait_for_all(e); 
      spawn_and_wait_for_all(f); 
      spawn_and_wait_for_all(g); 
      spawn_and_wait_for_all(h); 
      // In the case of effect: 
      // Overlay layers 

      matTask& ab = *new(allocate_child()) 
       matTask(main_layers,overlay_layers,n,offset); 
      matTask& bc = *new(allocate_child()) 
       matTask(main_layers,overlay_layers,n-1,offset); 
      matTask& cd = *new(allocate_child()) 
       matTask(main_layers,overlay_layers,n-2,offset); 
      matTask& de = *new(allocate_child()) 
       matTask(main_layers,overlay_layers,n-2,offset); 
      matTask& ef = *new(allocate_child()) 
       matTask(main_layers,overlay_layers,n-2,offset); 
      matTask& gh = *new(allocate_child()) 
       matTask(main_layers,overlay_layers,n-2,offset); 

      // ... + crop .. depends on size of kernel 

      set_ref_count(8); 
      spawn(b); 
      spawn_and_wait_for_all(a); 
     } 
    return NULL; 
    } 
}; 
void ParallelAction(std::vector<cv::Mat> main, std::vector<cv::Mat> overlays, int n, const int offset) { 
    matTask& a = *new(tbb::task::allocate_root()) 
    matTask(main, overlays, n,offset); 
    tbb::task::spawn_root_and_wait(a); 
} 

int main(int argc, char** argv) 
{  
    int threads = 8; 

    std::vector<cv::Mat> main_layers; 
    std::vector<cv::Mat> overlays; 

    cv:: Mat sourceImg; 
    sourceImg = imread("../../data/lena.jpg"); 
    if (sourceImg.empty()) 
     return -1; 

    const int offset = (int) sourceImg.rows/threads; 


    cv::setNumThreads(0); 
    ParallelAction(main_layers, overlays, threads, offset); 

    // GaussianBlur(src, dst, Size(3,3), 0, 0, BORDER_DEFAULT); 

    return 0; 
} 

編集:アントンの答えに 反応。 operator()オーバーロードを使用する場合、operator()が正確に適用されるのはいつですか?また、ApplyFooにいくつかのメソッドを追加することは可能ですか? WWは()がオーバーロードされていると、1つの方法しかないようです。

void Foo(float a){}; 

class ApplyFoo { 
    float *const my_a; 
public: 
    void operator()(const tbb::blocked_range<size_t>& r) const { 
     float *a = my_a; 
     for(size_t i=r.begin(); i!=r.end(); ++i) 
      Foo(a[i]); 
    } 
    ApplyFoo(float a[]) : 
     my_a(a) // initiate my_a 
    {} 
}; 
+1

OpenCVの 'ParallelLoopBody'をサブクラス化し、利用可能な場合はtbbを使用する' cv:parallel_for_'を使用することができます。グレースケール変換の例はこちら[http://stackoverflow.com/a/34315148/5008845]で見ることができます。おそらくあなたのニーズに適応することができます – Miki

+0

ありがとう、私は変更を試してみます。今私はTBBでそれをやろうとしています。 –

答えて

3

あなたが指摘している記事は2007年です! TBBはすべてのソース互換性を維持しているので、これはまだ古くなっています。 tbb::taskインターフェイスは低レベルとみなされ、アプリケーション開発にはそれほど便利ではありません。refer totbb::parallel_for,、特にキャンセルするための直接サポートを有するtbb::task_groupにお願いします。

+0

私は質問でコードを更新しました。それが呼び出されたときにoperator()オーバーロードを使用するとしますか? ApplyFooクラスでいくつかの追加機能を使用することは可能ですか? Foo関数をApplyFooクラスに移動することは可能ですか?これはoperator()のために競合を引き起こしますか?フーをメソッドとして別のクラスに移してもいいですか?その場合、Fooが配置されているオブジェクトへの参照をどのように渡すことができますか?どこにポインタを配置するのですか?私は唯一の解決策は、私はoperator()関数からアクセスできるようにconstuctorにクラスApplyFooに配置することだと思う。 –

+1

@JohnBoe 'operator()'でクラスを定義したり、 '[](const tbb :: blocked_range &r){do_it_inline();のようなラムダ式を使うことができます。 } '。これは、 'parallel_for'が終了する前、または' parallel_invoke'または 'task_group.wait()'がそれぞれのケースで終了する前のどこかで呼び出されます。 – Anton

+0

クラスの外に関数を保持したくない場合、2つのクラスを作成する必要がありますか?私はBlurAction_wrapperクラスを作成しました。このクラスは、コピー、ぼかし、トリミング、マージのようなすべてのアクションを作成する必要があります。BlurAction_wrapper * BlurAction = new BlurAction_wrapper(sourceImg、&targetImg、iArgs);公開部分をApplyFooからBlurActionクラス(名前を変更)に移動するか、それとも別の場所に移動する必要がありますか? –

関連する問題