在 C++ 中有效地保存许多连续记录的图像

Posted

技术标签:

【中文标题】在 C++ 中有效地保存许多连续记录的图像【英文标题】:Efficiently saving many consecutively recorded images in C++ 【发布时间】:2018-07-09 14:15:46 【问题描述】:

我面临以下问题: 我使用 C++ 程序来控制连接到我的 PC 的科学相机。它以尽可能快的快门时间拍摄照片(每张图像约 1 秒)。

在当前阶段,该程序会在每张照片制作完成后立即将其保存到硬盘中。看来,I/O 访问需要花费大量时间(每次保存大约 1/2 秒),这大大降低了图像速率。

我一直在考虑先存储许多图像(例如,存储在一个数组中),然后将它们全部保存在一批中。 那行得通吗?有什么好的选择吗?遇到这样的问题怎么办?

制作视频而不是图像不是一种选择。

非常感谢

编辑:这是我正在使用的代码:

    // capture loop: add up 'preint' images read out with 12 bit adc resolution
    // and save them as 16 bit image

    // read out current shutter register
    // read the 32-bit hex value into the unsigned long member of the above defined union
    cam.ReadRegister( 0x918, &curShutter.ulValue );
    fCurShutter = curShutter.fValue;

    cout << "Grab # " << ip.cnt << "; Serv: " << ip.servopos << "; Expt: " << ip.exptime << "; T: " << ip.temp  << "; prog " ;

    //inner capture loop
    for ( int imageCnt=0; imageCnt < ip.preint; imageCnt++ )
    
        error = cam.RetrieveBuffer( &monoImage );
        if (error != PGRERROR_OK)PrintError( error ); continue;

        cout << "." ;

        //convert to cv::Mat image
        unsigned int rowBytes = (double)monoImage.GetReceivedDataSize()/(double)monoImage.GetRows();
        cv_image = cv::Mat(monoImage.GetRows(), monoImage.GetCols(), CV_16UC1, monoImage.GetData(),rowBytes);

        cv_sum_image = cv_sum_image + cv_image/ip.preint;

        cv::imshow("image", cv_sum_image);
        cv::waitKey(1);
    

    //t=GetTickCount() - t;
    unsigned int shutterus = fCurShutter*1000000;

    
    //create filename and save co-added image
    ostringstream filename;
    filename << ip.mode <<"_"<< ip.cdt << "_"   << setfill('0') << setw(5) << ip.cnt << "_" << ip.servopos << "_" << setfill('0') << setw(6) << shutterus << "_" << ip.preint << "_" << ip.temp << "_" << ip.pres <<".pgm";
    //cv::string ss = filename.str();
    string ss = filename.str();
    cv::imwrite(ss,cv_sum_image);
    

    // Stop capturing images
    error = cam.StopCapture();
    if (error != PGRERROR_OK)PrintError( error ); return -1;

    // Disconnect the camera
    error = cam.Disconnect();
    if (error != PGRERROR_OK) PrintError( error ); return -1;

    return 0;

也许问题出在 opencv 例程中?

【问题讨论】:

图片有多大?是否可以选择更好的存储介质(例如 SSD、存储卡)? 您使用的是什么操作系统?默认情况下,Linux 将异步“写入”磁盘。 write 调用会将数据复制到缓冲区并很快将控制权返回给您的程序,然后内核将在稍后的某个时间将数据物理写入磁盘。 我会考虑在每个文件中放入多个图像——这可能有助于减少磁头跳动;还有 - 您需要记录多少张图像?如果你可以把它全部放在内存中,那么就这样做,然后在最后转储到磁盘。 一般来说,您希望查看数据速率(字节/秒)、硬件设置以及访问磁盘的其他内容。我很惊讶你报告的速度有多慢。我的猜测是,您可能有一个缓慢的 HDD 和/或其他程序大量访问磁盘和/或一个缓慢的 CPU 和/或 非常 大图像,可能在 Windows 上。修复将取决于您的情况是这些因素的哪种组合。 @JMAA Linux 将异步“写入”磁盘 Windows 也是如此。和 macOS。还有…… 【参考方案1】:

查看您的代码,最有可能的罪魁祸首是 openCV 的 imwrite 函数。 您应该知道 imwrite 还会根据提供的文件扩展名(在您的情况下为 .pgm)对您的输出进行编码。

PGM 格式在本质上非常简单,但是查看 openCV 代码时会进行一些处理,并且数据一次处理一个字节,这也许可以解释您所看到的缓慢。

首先,我会尝试使用更简单的文件格式,只是为了验证 imwrite 函数确实是问题所在。 Open CV 可以编写 .bmp 格式的文件,并且编码器看起来更简单,而且应该更快。

如果这个假设得到证实,你就有很多可能的行动方案。我的一些想法:

    与您的问题一样,延迟写入文件,直到您的时间敏感操作完成后。这通常是有道理的,但您很可能无法将所有图像都放入内存(每 1000 张图像大约需要 600mb)。

    为您的文件存储操作创建一个专用线程,并将工作卸载到这个其他线程。

    尽可能快地将图像存储在 HDD 上(以 .bmp 格式,或实现您自己的文件写入器,将对象从内存转储到 HDD),然后对它们进行后期处理到您需要的格式。

【讨论】:

您好,感谢您的回复。我认为将文件存储在 pgm 文件中的时间最少,因为它是一种“微不足道”的文件格式。我会试试你的建议!谢谢!【参考方案2】:

原来严重的延迟是由于硬件损坏造成的。我们使用的电缆无法提供足够的数据流。

【讨论】:

请添加更多描述。 电缆确实坏了,数据流减少了。我们通过简单地更换电缆就发现了这一点,并且没有费心进一步调查旧电缆的实际问题。

以上是关于在 C++ 中有效地保存许多连续记录的图像的主要内容,如果未能解决你的问题,请参考以下文章

通过网络连续传输图像的最有效方式

在 python 中,如何有效地找到列表中不一定相邻的最大连续数字集?

如何有效地删除列表列表中的连续重复项?

如何在 Windows 10 上使用 C++ 将连续的原始音频数据记录到循环缓冲区中?

如何有效地改变矩阵的连续部分?

列出连续记录范围的有效方法