在 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 中,如何有效地找到列表中不一定相邻的最大连续数字集?