具有opencv

时间:2017-06-27 11:08:37

标签: c++ multithreading opencv ffmpeg

在一个应用程序中我要分析电影文件 (假设计算连续帧对的差异)。 为此,我使用opencv(使用ffmpeg作为lib / codecs)。 根据视频格式,有不同的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();
}

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

  • MT2 1.8
  • MT4 2.6
  • MT8 3.0

除了非常失望之外,我不明白这里发生了什么。 我确实知道阿姆达尔的法律等,但在这种情况下,我预计会有更好的加速。 有没有人给我一个提示(作为新手)? 这不是定位(capt.set()),因为禁用不会改变任何东西。 是关于ffmpeg-lib,opencv,std-lib的线程切换,工作集问题?

[编辑:

根据评论中的暗示,我发现80%的时间用于

capt >> frameDuo [i%2];

这包括从文件读取,解码和复制到opencv结构。 从这一点来看,只有从文件中读取的是“顺序类型”(在Amdahl的意义上)。 由于HDD没有显示重型访问(即使在MT8时),也没有区别 当使用快速SSD时,我不明白为什么这个顺序部分应该产生如此大的影响。 8个内核如何完全正常工作但速度只有3? 而且:我怎么能做得更好?]

1 个答案:

答案 0 :(得分:0)

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

2   1.8 
4   2.99
8   4.48

这些数字并不能准确地再现你所测量的数字,但除了Amdahls定律之外,每个线程还有一些开销和更多必须考虑获得实际数字的东西,因此它只是第一个近似值,在这个意义上协议很好。

作为结论:你得到的数字并不是那么糟糕。当考虑Amdahls定律时,它正是人们所期望的平行分数约为85%。