提问者:小点点

用C++将OpenCV帧写入磁盘:单线程写入速度是否受到磁盘吞吐量以外的任何限制?


当将OpenCV帧写入磁盘时,我正面临着一个我认为相当奇怪的行为:如果我在SSD或HDD上单独写入,我无法以20 fps的速度写入磁盘。 但是,事情是这样的:如果我用一个线程写数据的前半部分,用另一个线程写数据的后半部分,那么我可以以双倍的速度(大约40 fps)写数据。

我正在使用下面的代码进行测试:两个std::向量用我的网络摄像头中的1920x1080帧填充,然后发送到两个不同的线程以写入磁盘。 例如,如果我将2个大小为50的向量写入磁盘,我可以以大约40 fps的总体速度执行。 但是如果我只使用一个大小为100的向量,那就会下降到一半。 怎么可能呢? 我以为我会受到磁盘吞吐量的限制,那足以写入至少30 fps,但我遗漏了一些东西,我不知道是什么。 有没有其他限制(除了cpu),我没有考虑?

#include "opencv2/opencv.hpp"
#include "iostream"
#include "thread"
#include <unistd.h>
#include <chrono>
#include <ctime>

cv::VideoCapture camera(0);

void writeFrames(std::vector<cv::Mat> &frames, std::vector<int> &compression_params, std::string dir)
{
    for(size_t i=0; i<frames.size(); i++)
    {
        cv::imwrite(dir + std::to_string(i) + ".jpg",
                    frames[i], compression_params);
    }
}

int main(int argc, char* argv[])
{
    camera.set(cv::CAP_PROP_FRAME_WIDTH, 1920);
    camera.set(cv::CAP_PROP_FRAME_HEIGHT, 1080);
    camera.set(cv::CAP_PROP_FPS, 30);

    std::vector<int> compression_params;
    compression_params.push_back(cv::IMWRITE_JPEG_QUALITY);
    compression_params.push_back(95); // [0 - 100] (100 better), default 95

    size_t vecSizeA = 50;
    size_t vecSizeB = 50;

    std::vector<cv::Mat> framesA, framesB;
    cv::Mat frame;

    std::chrono::system_clock::time_point t0 = std::chrono::system_clock::now();

    for(unsigned int i=0; i<vecSizeA; i++)
    {
        camera >> frame;
        framesA.push_back(frame);
    }

    for(unsigned int i=0; i<vecSizeB; i++)
    {
        camera >> frame;
        framesB.push_back(frame);
    }

    std::chrono::system_clock::time_point t1 = std::chrono::system_clock::now();

    std::thread trA(writeFrames, std::ref(framesA), std::ref(compression_params), "/tmp/frames/A/");
    std::thread trB(writeFrames, std::ref(framesB), std::ref(compression_params), "/tmp/frames/B/");

    trA.join();
    trB.join();

    std::chrono::system_clock::time_point t2 = std::chrono::system_clock::now();

    double tr = std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0).count() / 1000.0;
    double tw = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count() / 1000.0;

    std::cout << "Read fps: " << (vecSizeA + vecSizeB) / tr << std::endl;
    std::cout << "Write fps: " << (vecSizeA + vecSizeB) / tw << std::endl;

    return 0;
}

共1个答案

匿名用户

因为两个线程同时达到相同的功能,看起来比一个线程快。 线程的连接在同一个地方。 如果你这样使用它们,你会得到和一个线程一样的fps:

    std::thread trA(writeFrames, std::ref(framesA), std::ref(compression_params), "/tmp/frames/A/");

    trA.join();

    std::thread trB(writeFrames, std::ref(framesB), std::ref(compression_params), "/tmp/frames/A/");

    trB.join();

你也可以查看这里有更多的想法。

相关问题


MySQL Query : SELECT * FROM v9_ask_question WHERE 1=1 AND question regexp '(c++|opencv|帧|写入|磁盘|单线程|写入|速度|磁盘|吞吐量)' ORDER BY qid DESC LIMIT 20
MySQL Error : Got error 'repetition-operator operand invalid' from regexp
MySQL Errno : 1139
Message : Got error 'repetition-operator operand invalid' from regexp
Need Help?