繁体   English   中英

OpenCV具有多个进程的小加速

[英]Small speedup with multiple processes for opencv

在一个应用程序中,我必须分析电影文件(假设计算连续帧对的差异)。 为此,我使用opencv(使用ffmpeg作为lib /编解码器)。 根据视频格式,有不同的CPU负载/用途。 对于wmv3,似乎使用的内核不超过1个。 因此,由于数据是独立的(因此随后必须缝合这些部分),因此让多个线程在影片的不同部分上工作非常容易。 代码(用lap参数剥离)非常简单:

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();
}

如果我在1280x720的wmv3视频上使用abt。 相对于单线程(190秒),我获得了50,000帧的加速(在Intel i7上)。

  • MT2 1.8
  • MT4 2.6
  • MT8 3.0

除了非常失望之外,我不明白这里发生了什么。 我确实知道阿姆达尔定律等,但是在这种情况下,我希望能有更快的速度。 有没有人对我有暗示(成为新手)? 不是定位(capt.set()),因为禁用不会改变任何内容。 关于ffmpeg-lib,opencv,std-lib的线程切换,工作集问题吗?

[编辑:

作为评论的暗示,我发现80%的时间用于

capt >> frameDuo [i%2];

这包括从文件读取,解码和复制到opencv结构中。 从这开始,只有从文件中读取的文件是“顺序类型”的(在阿姆达尔看来)。 由于HDD的访问量不大(即使在MT8上也是如此),并且使用快速SSD时也没有区别,我不明白为什么这个顺序的部分会产生如此大的影响。 8个核心怎么可能完全正常工作,但只能加速3个? 并且:我该如何做得更好?]

实际上,您的大部分数字可以由阿姆达尔定律解释。 如果我将您的结果用于两个线程,并尝试计算并行完成的分数,则得出p = 0.88888的值。 并将此值用于4/8线程

2   1.8 
4   2.99
8   4.48

这些数字不能精确地再现您所测量的结果,但是在阿姆达尔定律的基础上,每个线程都有开销,必须考虑更多的东西才能得出真实的数字,因此这只是一个近似值,因此在这种意义上,协议相当好。

结论是:您得到的数字还不错。 考虑到Amdahls定律,它的并行分数约为〜85%,这正是人们所期望的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM