0

OpenCV Mat イメージを処理するために、並行してスレッドを処理するプログラムを作成する必要があります。すべてのスレッドは、キューから画像を取得して処理し、結果を別のキューに入れます。Mat イメージのスレッド セーフなテンプレート キュー (コードでわかるように) を使用します。

しかし、スレッドの奇妙な動作は次のとおりです。プログラムを複数回起動すると、シングルスレッドの精緻化の数で異なる結果が得られるたびに(シングルスレッドで処理される画像の数を監視するために挿入したカウンター「追加」) .

最初のスレッド (ゼロ) は常にすべての詳細 (この例では 10) を実行しますが、残りのスレッドは実行しません。すべてのスレッドが 10 回の精緻化を行う場合もあれば、3 回、場合によっては 5...2 回の場合もあります。新しい変更 (CONDITION VARIABLES および CRITICAL SECTION) により、スレッドは 1 つの操作のみを実行します。

どこに問題があるのか​​ わかりません...なぜこれが起こったのですか。

私はここに私のコードを渡しました。それをチェックして、何が問題なのかあなたの意見を教えてください...私は絶望的です。

これはコードです:

#include <opencv\cv.h>
#include <opencv\highgui.h>
#include <opencv2\highgui\highgui.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <process.h>
#include <queue>

using namespace std;
using namespace cv;

/*thread safe queue*/

template<typename T>
class coda_concorr
{
private:
    std::queue<T> la_coda;
    HANDLE mutex;

public: 
    bool elemento;
    coda_concorr()
    {
        mutex = CreateMutex(NULL,FALSE,NULL);
        }
    ~coda_concorr()
    {}
    void push(T& data)
    {
        WaitForSingleObject(mutex,INFINITE);
        la_coda.push(data);
        ReleaseMutex(mutex);
        }
    bool vuota() const
    {
        WaitForSingleObject(mutex,INFINITE);
        bool RetCode = la_coda.empty();
        ReleaseMutex(mutex);
        return RetCode;
    }
    bool try_pop(T& popped)
    {
        WaitForSingleObject(mutex,INFINITE);
        while (la_coda.empty()){
            ReleaseMutex(mutex);
            return false;
        }
        WaitForSingleObject(mutex,INFINITE);
        popped = la_coda.front();
        la_coda.pop();
        ReleaseMutex(mutex);
        return true;
    }
};


struct Args
{
    coda_concorr<cv::Mat> in;
    coda_concorr<cv::Mat> *out; //puntatore a coda successiva
};


CONDITION_VARIABLE NonVuoto1;
CONDITION_VARIABLE NonVuoto2;
CONDITION_VARIABLE NonVuoto3;
CONDITION_VARIABLE NonVuoto4;
CRITICAL_SECTION  Lock1;
CRITICAL_SECTION  Lock2;
CRITICAL_SECTION  Lock3;
CRITICAL_SECTION  Lock4;

bool stop;

//initial populating queue
void puts (void* param){
    Args* arg = (Args*)param;
    int i=0;
    Mat image;

    while(!arg->in.vuota()){
        arg->in.try_pop(image);
        arg->out->push(image);
        i++;        
        WakeConditionVariable(&NonVuoto1);
        }
    //fine  
    cout<<endl<<"Thread (PUSH) terminato con "<<i<<" elaborazioni."<<endl;
    WakeConditionVariable(&NonVuoto1);
    _endthread();
}

//grey funct
void grey (void *param){
    Mat temp1,temp2;
    int add = 0;
    Args* arg = (Args*)param;
    while(true){
        EnterCriticalSection(&Lock1);
        //se vuoto
        while(arg->in.vuota() && !stop){
             SleepConditionVariableCS(&NonVuoto1,&Lock1,INFINITE);
            }
            if(stop==true){
            LeaveCriticalSection(&Lock1);
            break;
            }
        arg->in.try_pop(temp1);
        cvtColor(temp1,temp2,CV_BGR2GRAY);
        arg->out->push(temp2);
        add++;
        cout<<endl<<"grey ha fatto: "<<add<<endl;
        LeaveCriticalSection(&Lock1);
        WakeConditionVariable(&NonVuoto2);
        }
    //fine  
    cout<<endl<<"Thread (GREY) terminato con "<<add<<" elaborazioni."<<endl;
    _endthread();
}

//threshold funct
void soglia(void *param){
    Mat temp1a,temp2a;
    int add=0;
    Args* arg = (Args*)param;
    while(true){
        EnterCriticalSection(&Lock2);
        while(arg->in.vuota() && stop == false){
             SleepConditionVariableCS(&NonVuoto2,&Lock2,INFINITE);
            }
        if(stop==true){
            LeaveCriticalSection(&Lock2);
            break;
            }
        arg->in.try_pop(temp1a);
        threshold(temp1a,temp2a,128,255,THRESH_BINARY);
        arg->out->push(temp2a);
        add++;
        LeaveCriticalSection(&Lock2);
        WakeConditionVariable(&NonVuoto3);
        cout<<endl<<"soglia ha fatto: "<<add<<endl;
        }
        //fine 
     cout<<endl<<"Thread (SOGLIA) terminato con "<<add<<" elaborazioni."<<endl;
     _endthread();
}

//erode/dilate funct
void finitura(void *param){
    Mat temp1b,temp2b,temp2c;
    int add = 0;
    Args* arg = (Args*)param;
    //come consumatore
    while(true){
        EnterCriticalSection(&Lock3);
        while(arg->in.vuota() && stop == false){
             SleepConditionVariableCS(&NonVuoto3,&Lock3,INFINITE);
            }
        if(stop==TRUE){
            LeaveCriticalSection(&Lock3);
            break;
            }   
        arg->in.try_pop(temp1b);
        erode(temp1b,temp2b,cv::Mat());
        dilate(temp2b,temp2c,Mat());
        arg->out->push(temp2c);
        add++;
        LeaveCriticalSection(&Lock3);
        WakeConditionVariable(&NonVuoto4);
        cout<<endl<<"erode ha fatto: "<<add<<endl;
        }
     //fine 
     cout<<endl<<"Thread (ERODE) terminato con "<<add<<" elaborazioni."<<endl;
    _endthread();
}

//contour funct
void contorno (void *param){
    Mat temp;
    int add=0;
    Args* arg = (Args*)param;
    //come consumatore
    while(true){
        EnterCriticalSection(&Lock4);
        while(arg->in.vuota() && stop == false){
             SleepConditionVariableCS(&NonVuoto4,&Lock4,INFINITE);
            }
        if(stop==TRUE){
            LeaveCriticalSection(&Lock4);
            break;
            }   
    //esegue pop
    arg->in.try_pop(temp);
    //trova i contorni
    vector<vector<Point>> contorni;
    findContours(temp,contorni,CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
    //disegna i contoni in un'immagine
    Mat dst(temp.size(), CV_8UC3, Scalar(0,0,0));
    Scalar colors[3];
    colors[0] = Scalar(255,0,0);
    colors[1] = Scalar(0,255,0);
    colors[2] = Scalar(0,0,255);
    for (size_t idx = 0; idx < contorni.size(); idx++){
        drawContours(dst,contorni,idx,colors[idx %3]);
        }

    //come produttore
    arg->out->push(dst);
    add++;
    cout<<endl<<"cont ha fatto: "<<add<<endl;
    LeaveCriticalSection(&Lock4);
    }
    cout<<endl<<"Thread (CONTOUR) terminato con "<<add<<" elaborazioni."<<endl;
   _endthread();
}

//main
int main()
{

    coda_concorr<cv::Mat> ingresso;
    coda_concorr<cv::Mat> uscita;

    InitializeConditionVariable(&NonVuoto1);
    InitializeConditionVariable(&NonVuoto2);
    InitializeConditionVariable(&NonVuoto3);
    InitializeConditionVariable(&NonVuoto4);
    InitializeCriticalSection(&Lock1);
    InitializeCriticalSection(&Lock2);
    InitializeCriticalSection(&Lock3);
    InitializeCriticalSection(&Lock4);


    LARGE_INTEGER count1, count2, freq;
    double elapsed;


    Mat temp[10];
    Mat out;

    //dichiarazione code
    Args dati0,dati1,dati2,dati3,dati4;


    //avvio contatori
    QueryPerformanceFrequency(&freq);   
    QueryPerformanceCounter (&count1);

    for(int i=0;i<10;i++){
        temp[i] = imread("C:/OPENCV/Test/imgtest/bird1.jpg",1);
        ingresso.push(temp[i]);
    }

    //next queue pointer
    dati0.in=ingresso;
    dati0.out=&dati1.in;
    dati1.out=&dati2.in;
    dati2.out=&dati3.in;
    dati3.out=&dati4.in;
    dati4.out=&uscita;



    //handle
    HANDLE handle0,handle1,handle2,handle3,handle4;

    //start threads
    handle0 = (HANDLE) _beginthread(puts,0,&dati0);
    handle1 = (HANDLE) _beginthread(grey,0,&dati1);
    handle2 = (HANDLE) _beginthread(soglia,0,&dati2);
    handle3 = (HANDLE) _beginthread(finitura,0,&dati3);
    handle4 = (HANDLE) _beginthread(contorno,0,&dati4);

    cout<<endl<<"..Join dei threads..."<<endl;

    //join
    WaitForSingleObject(handle0,INFINITE);
    WaitForSingleObject(handle1,INFINITE);
    WaitForSingleObject(handle2,INFINITE);
    WaitForSingleObject(handle3,INFINITE);
    WaitForSingleObject(handle4,INFINITE);



    //chiusura contatori
    QueryPerformanceCounter (&count2);

    CloseHandle(handle0);
    CloseHandle(handle1);
    CloseHandle(handle2);
    CloseHandle(handle3);
    CloseHandle(handle4);

    elapsed = (count2.QuadPart - count1.QuadPart) * 1000.0 / freq.QuadPart;


    cout <<endl<<"Tempo di esecuzione approssimativo: " <<elapsed<<" ms."<<endl;
        system("PAUSE");
    return 0;
}

前のスレッドがすべての画像をキューに入れた場合、次のスレッドが同じことをしないのはなぜですか?

私はVisual C++ 2010 OpenCV 2.4.4を搭載したWindows 7 64ビットを使用しています

問題がどこにあるかを見つけるのを手伝ってください...

4

1 に答える 1

2

あなたが実装したいのは、全員が自分の仕事をし、すべての作業が完了するまで次の労働者に投げる工場の組立ライン作業に似ているようです。間違っている場合は修正してください。各スレッド関数のイディオムは

void dowork(){
    while(noinput()){
        sleep(0.01);
    }
    while(getSomeInput()){
        processInput();
        queueResult();
    }
    displayAmountOfWorkDone();
}

ミューテックスで相互排除を提供することに成功しました。設計の問題は、スレッドが入力キューが空でないことを確認すると、すべての作業を消費してから終了することです。スレッドのスケジューリングと処理時間processInput()により、ワーカーは生成する前にワーカーよりも高い速度で入力を消費する可能性があります。たとえば、init と datit の間でキューを取得すると、次のことが可能になります。

datit: see 0, sleep
init : see 10 - add 1 
datit: see 1, process
datit: see 0, exit and outputs 1
init : add 2
init : add 3
init : add 4
....
init : add 10

デザインを変更する必要があります。作業が終了したことを知らせる別のメカニズムが必要です。現在、スレッドが観察できる量の入力を使用しています。迅速かつ汚い修正は、各スレッドが処理することが期待される入力の量を各スレッドに与え、アルゴリズムを次のように書き直すことです。

void dowork(){
    while(workIsnotDone()){//local test, no lock
        if(getSomeInput()){
             processInput();
             queueResult();
             updateWorkProgress();//local operation
        }
        else{
             sleep(0.01);
        }
    }
    displayAmountOfWorkDone();
}

coda_concorrより良い代替手段は、クラスをプロデューサー/コンシューマー メカニズムとして設定することです。そのために、条件変数を追加できます。各スレッドは、あるキューではコンシューマーであり、別のキューではプロデューサーです。フィールドを追加して、これ以上入力しないなどを明示的に指定することもできます。SOに関するこの他の質問を見てください

于 2013-06-18T08:51:38.473 に答える