OpenCV GPU Farneback Optical Flow funktioniert beim Multithreading schlecht

Meine Anwendung verwendet die OpenCV GPU-Klassegpu::FarnebackOpticalFlow, um den optischen Fluss zwischen zwei aufeinanderfolgenden Bildern eines Eingangsvideos zu berechnen. Um den Prozess zu beschleunigen, habe ich die TBB-Unterstützung von OpenCV ausgenutzt, um die Methode in Multithreading auszuführen. Die Multi-Threading-Leistung verhält sich jedoch nicht wie die Single-Threading-Leistung. Um Ihnen einen Überblick über das unterschiedliche Verhalten zu geben, finden Sie hier zwei Schnappschüsse der Single-Threaded- und der Multi-Threaded-Implementierung.

Die Multithread-Implementierung setzt voraus, dass das Bild in 8 verschiedene Streifen aufgeteilt wird (die Anzahl der Kerne auf meinem PC), und auf jeden Streifen wird die GPU-Methode für die Farneback-Implementierung des optischen Flusses angewendet. Hier sind die entsprechenden Codezeilen für beide Methoden:

Single-Thread-Implementierung

/* main.cpp */
//prevImg and img are the input Mat images extracted from the input video
...
GpuMat gpuImg8U(img);
GpuMat gpuPrevImg8U(prevImg);   
GpuMat u_flow, v_flow;
gpu::FarnebackOpticalFlow farneback_flow;
farneback_flow.numLevels = maxLayer;
farneback_flow.pyrScale = 0.5;
farneback_flow.winSize = windows_size;
farneback_flow.numIters = of_iterations;
farneback_flow(gpuPrevImg8U,gpuImg8U,u_flow,v_flow);
getFlowField(Mat(u_flow),Mat(v_flow),optical_flow);

...
}

void getFlowField(const Mat& u, const Mat& v, Mat& flowField){    
    for (int i = 0; i < flowField.rows; ++i){
        const float* ptr_u = u.ptr<float>(i);
        const float* ptr_v = v.ptr<float>(i);
        Point2f* row = flowField.ptr<Point2f>(i);

        for (int j = 0; j < flowField.cols; ++j){
            row[j].y = ptr_v[j];
            row[j].x = ptr_u[j];
        }
    }
}

Multi-Thread-Implementierung

/* parallel.h */
class ParallelOpticalFlow : public cv::ParallelLoopBody {

    private:
        int coreNum;
        cv::gpu::GpuMat img, img2;
        cv::gpu::FarnebackOpticalFlow& farneback_flow;
        const cv::gpu::GpuMat u_flow, v_flow;
        cv::Mat& optical_flow;

    public:
        ParallelOpticalFlow(int cores, cv::gpu::FarnebackOpticalFlow& flowHandler, cv::gpu::GpuMat img_, cv::gpu::GpuMat img2_, const cv::gpu::GpuMat u, const cv::gpu::GpuMat v, cv::Mat& of)
                    : coreNum(cores), farneback_flow(flowHandler), img(img_), img2(img2_), u_flow(u), v_flow(v), optical_flow(of){}

        virtual void operator()(const cv::Range& range) const;

};


/* parallel.cpp*/
void ParallelOpticalFlow::operator()(const cv::Range& range) const {

    for (int k = range.start ; k < range.end ; k ++){

        cv::gpu::GpuMat img_rect(img,cv::Rect(0,img.rows/coreNum*k,img.cols,img.rows/coreNum));
        cv::gpu::GpuMat img2_rect(img2,cv::Rect(0,img2.rows/coreNum*k,img2.cols,img2.rows/coreNum));
        cv::gpu::GpuMat u_rect(u_flow,cv::Rect(0,u_flow.rows/coreNum*k,u_flow.cols,u_flow.rows/coreNum));
        cv::gpu::GpuMat v_rect(v_flow,cv::Rect(0,v_flow.rows/coreNum*k,v_flow.cols,v_flow.rows/coreNum));
        cv::Mat of_rect(optical_flow,cv::Rect(0,optical_flow.rows/coreNum*k,optical_flow.cols,optical_flow.rows/coreNum));

        farneback_flow(img_rect,img2_rect,u_rect,v_rect);
        getFlowField(Mat(u_rect),Mat(v_rect),of_rect);
    }
}

/* main.cpp */

    parallel_for_(Range(0,cores_num),ParallelOpticalFlow(cores_num,farneback_flow,gpuPrevImg8U,gpuImg8U,u_flow,v_flow,optical_flow));

Die Codes sehen in beiden Fällen äquivalent aus. Kann mir jemand erklären, warum es diese unterschiedlichen Verhaltensweisen gibt? Oder wenn mein Code einige Fehler enthält? Vielen Dank im Voraus für Ihre Antworten

Antworten auf die Frage(2)

Ihre Antwort auf die Frage