较小的速度,具有多个流程的OPENCV

Small speedup with multiple processes for opencv

本文关键字:OPENCV 速度      更新时间:2023-10-16

在我分析电影文件的应用程序中(假设计算连续框架对的差异(。为此,我使用OpenCV(使用FFMPEG作为LIB/编解码器(。根据视频格式,有不同的CPU负载/用途。对于WMV3,似乎不超过1个核心。因此,让多个线程在电影的不同部分上工作是亲密接近的,由于数据是独立的(之后必须缝制零件(。代码(被圈参数剥离(非常简单:

int main(int argc, char *argv[])
{
    const string source = "move.wmv";
    VideoCapture capt(source);
    if (!capt.isOpened())
    {
        cout  << "Could not open file " << source << endl;
        return -1;
    }
    unsigned short nThreads (8);
    double *pDiffArray = new double [(size_t) (capt.get(CV_CAP_PROP_FRAME_COUNT)];
    capt.release();
    ComputeDifferences (source, pDiffArray, nThreads);
    return 0;
}
int ComputeDifferences (const string& source, double *pDiffArray, const unsigned short& nThreads)
{
    std::vector<std::thread *> threadVector;
    for (unsigned int i=0; i< nThreads; i++)
        threadVector.push_back (new std::thread (ComputePart, source, pDiffArray, nThreads, i));
    for (unsigned int i=0; i< nThreads; i++)
        threadVector.at (i)->join();
    // Stitching
    ;
    return 0;
};

void ComputePart (const string source, double *pDiffArray,
                  const unsigned int& nThreads, const unsigned int& nThreadNo)
{
    VideoCapture capt(source);
    if (!capt.isOpened())
    {
        cout  << "Could not open file " << source << endl;
    }
    size_t startPosDiffArray;
    startPosDiffArray = nThreadNo * (capt.get(CV_CAP_PROP_FRAME_COUNT) / nThreads);
    size_t sizePart (capt.get(CV_CAP_PROP_FRAME_COUNT) / nThreads);
    size_t startPosFrame;
    startPosFrame = capt.get(CV_CAP_PROP_FRAME_COUNT) / nThreads * nThreadNo;
    capt.set(CAP_PROP_POS_FRAMES, startPosFrame);
    Size refS = Size((int) capt.get(CAP_PROP_FRAME_WIDTH),
                     (int) capt.get(CAP_PROP_FRAME_HEIGHT));
    Mat frame, frameRes;
    std::array<Mat, 2> frameDuo;
    Scalar s;
    capt >> frameDuo [0];
    if (!frameDuo [0].data)
        return;
    for (size_t i = 1; i < sizePart; i++) {
        capt >> frameDuo [i%2];
        if (!frameDuo [i%2].data)
            break;
        absdiff (frameDuo [(i-1)%2], frameDuo [i%2], frameRes);
        s = sum (frameRes);
        pDiffArray [i-1+startPosDiffArray] = (s [0] + s [1] + s [2])/ (refS.height * refS.width);
    }
    capt.release();
}

如果我在WMV3视频中使用它,则为1280x720,abt。50,000帧,相对于单线线程(190秒(,我得到了这个加速度(在Intel I7上(。

  • MT2 1.8
  • MT4 2.6
  • MT8 3.0

除了非常失望之外,我不明白这里发生了什么。我确实知道Amdahl的定律等,但是在这种情况下,我希望加快得多。有人对我有提示(对此做新手(吗?它不是定位(capt.set(((,因为禁用什么都不会改变任何东西。是关于ffmpeg-lib,opencv,std-lib的线程开关,工作集问题吗?

[编辑:

从评论中提示,我发现80%的时间在

中使用
capt >> frameDuo [i%2];

这包括从文件中读取,解码和复制到OPENCV结构中。因此,只有文件的读数为"顺序类型"(从Amdahl的意义上(。由于HDD不会显示出大量的访问(即使在MT8时(也没有区别使用快速SSD时,我不明白为什么此顺序零件应该具有如此大的效果。8个核心如何完全工作,但只有3个核心?和:我该怎么做得更好?]

您数字的最大部分确实可以通过Amdahls Law来解释。如果我将您的结果用于两个线程,并尝试计算并行完成的分数,则将获得p = 0.88888的值。并将此值用于4/8线程,我得到

2   1.8 
4   2.99
8   4.48

这些数字不能准确地重现您的测量值,但是在Amdahls Law的基础上,您的每个线程开销,并且必须考虑更多的东西才能获得逼真的数字,因此它只是第一个近似值,从这个意义上讲,协议还可以。

作为结论:您获得的数字还不错。在考虑Amdahls Law时,其平行分数的期望为〜85%。