C++ 在OpenCV中加速将图像写入硬盘

C++ 在OpenCV中加速将图像写入硬盘,c++,qt,opencv,qthread,qtcore,C++,Qt,Opencv,Qthread,Qtcore,我使用的是一个每秒50帧的摄像头(在Ubuntu环境和Qt框架中),每20毫秒我就有一帧要处理 我编写了一个代码,从相机中读取图像,然后将它们存储在硬盘中 while(3.14) { cv::Mat Camera_Image = Capture_Image(); double T1 = (double)cv::getTickCount(); cv::imwrite (STORE_ADDRESS,Camera_Image); T1 = (((double)cv::getTickCount(

我使用的是一个每秒50帧的摄像头(在Ubuntu环境和Qt框架中),每20毫秒我就有一帧要处理

我编写了一个代码,从相机中读取图像,然后将它们存储在硬盘中

while(3.14)
{
 cv::Mat Camera_Image = Capture_Image();
 double T1 = (double)cv::getTickCount();
 cv::imwrite (STORE_ADDRESS,Camera_Image);
 T1 = (((double)cv::getTickCount() -T1)*1000)/cv::getTickFrequency();
 print(T1);
}
当我看到输出时,对于2048*1080图像大小,将单个图像写入硬盘的时间约为30毫秒。每个图像都是单通道(灰度)的,但我用.jpg格式写在硬盘上。硬盘中每个映像的大小约为500KB

因为我在大约20毫秒内捕获了一帧,所以我无法将它们全部实时写入硬盘。我已经使用Qthread编写了代码,并创建了一个队列,以查看是否有任何改进,但结果是相同的,这只是内存开销

是否有可能改变这种情况,或者使用其他库将这些图像更快地写入硬盘?如果可用,我也更喜欢Qt解决方案

另外,我需要将每一帧写入硬盘,所以请不要建议使用运动压缩算法,因为它们不适用于我的情况

代码: Mainwindow.cpp

 Qlist<cv::Mat> FINAL_IM_VEC;
MainWindow::MainWindow(QWidget *parent) :
  QMainWindow(parent),
  ui(new Ui::MainWindow)
{
  ui->setupUi(this);

  IMREAD *IMR = new IMREAD(this);   // an instance of IMREAD Class which reads camera frames
  IMWRITE *IMW = new IMWRITE(this);  // an instance of IMWRITE Class which Writes camera frames into hard disk
  QThread *IMAGE_READ_Thread = new QThread(this);
  QThread *Image_Store_Thread = new QThread(this);
  connect(IMAGE_READ_Thread,SIGNAL(started()),IMR,SLOT(IMREAD_Process()));
  connect(Image_Store_Thread,SIGNAL(started()),IMW,SLOT(IMWrite_Process()));
  IMR.moveToThread(IMAGE_READ_Thread);
  IMW.moveToThread(Image_Store_Thread);
  IMAGE_READ_Thread->start();
  Image_Store_Thread->start();
}
imread.cpp

IMREAD::IMREAD(QObject *parent) :
    QObject(parent)
{
  this->Stop = false;
}

void IMREAD::IMREAD_Process()
{

  while(!Stop)
    {
          cv::Mat Image = CAM::Campture_F(25);//wait a maximum of 25 milisecond to grab a new frame
          if(Image.data())
            {
          FINAL_IM_VEC.push_back(Image);
            }
      }
    }

}
imwrite.hpp

#ifndef IMWRITE_H
#define IMWRITE_H
#pragma once
#include <QObject>
class IMWRITE : public QObject
{
    Q_OBJECT
public:
    explicit IMWRITE(QObject *parent = 0);
signals:

public slots:
    void IMWrite_Process();
private:
    bool Stop;
};
\ifndef IMWRITE\H
#定义IMWRITE_H
#布拉格语一次
#包括
类IMWRITE:公共QObject
{
Q_对象
公众:
显式IMWRITE(QObject*parent=0);
信号:
公众时段:
无效IMWrite_进程();
私人:
布尔停止;
};
imwrite.cpp

IMWRITE::IMWRITE(QObject *parent) :
    QObject(parent)
{
  this->Stop =false;
}
void IMWRITE::IMWrite_Process()
{
    static int counter = 0;
    while(!Stop)
      {
        for(int i = 0 ; i < FINAL_IM_VEC.size() ; i++)
            {
                QString address = "/home/Provisioner/ThreadT/Results/" + QString::number(counter++) + ".jpg";
                cv::imwrite(address.toUtf8().constData(),FINAL_IM_VEC[i]);
                FINAL_IM_VEC.erase(FINAL_IM_VEC.begin() + i);
                i--;
            }
      }

}
IMWRITE::IMWRITE(QObject*父对象):
QObject(父对象)
{
此->停止=错误;
}
void IMWRITE::IMWRITE_进程()
{
静态整数计数器=0;
当(!停止)
{
对于(int i=0;i
由于这只是整个项目的一部分,我删除了一些不相关的部分…但它展示了我是如何在一个大画面中编写多线程代码的。。。所以如果有什么问题,请告诉我


提前感谢。

您应该有一个要处理的图像队列。您应该有一个捕获线程来捕获图像并将其放置在队列中。您应该有几个压缩/写入线程,这些线程将图像从队列中取出并压缩/写入它们

现在CPU有不止一个核心是有原因的——所以你不必在开始下一件事情之前完成一件事情

如果您认为这就是您正在做的,并且仍然看到相同的问题,请向我们展示您的代码。您很可能做得不正确

更新:正如我所怀疑的,您使用线程的方式并没有实现使用线程的最初目标。整个要点是一次压缩多个图像,因为我们知道压缩一个图像需要30毫秒,而且我们知道每30毫秒压缩一个图像是不够的。按照使用线程的方式,您仍然一次只压缩一个图像。因此,30毫秒压缩/写入图像仍然太长。队列没有任何用途,因为只有一个线程从队列中读取数据。

让我们看看:2048*1080*3(通道数)*50 fps~=316MB/s,如果您是以原始格式写入图像的话。如果您使用JPEG,根据压缩参数,您可能会得到大幅降低,但如果是1/5,您仍然会向硬盘写入大量数据,特别是在笔记本电脑上使用5400rpm时

你可以做的事情:

  • 正如David Schwartz所建议的,您应该使用队列和多线程
  • 如果您正在有效地编写图像序列,请保存视频。数据被压缩得更多,写入磁盘的速度更快
  • 检查当前设备的斑点,并估计可以写入的图像的最大大小。选择压缩参数以适应该大小约束

  • 我建议您查看一下
    QtMultimedia
    模块,如果您处理的是流而不是图像,请尝试将代码转换为MPEG

    这将避免始终处理每个像素,因为只处理像素差异。这可能会提高处理的性能


    当然,你也可以看看heftier压缩算法,但这超出了Qt的范围,Qt交易可能只是与算法交互。

    通常有多种解决方案,但你需要指定图像的格式-灰度什么?8位?12位?16位?

    大多数其他答案完全没有抓住要点,因为它们忽略了您试图做的事情的物理现实:带宽,无论是在I/O还是在处理方面,都是最重要的

    您是否在实际情况下验证了系统上可用的存储带宽?将此流存储在操作系统所在的同一驱动器上通常不是一个好主意,因为其他应用程序的要求会消耗您的带宽。请记住,在具有5ms寻道的现代50+Mbyte/s硬盘上,一次寻道需要0.25MBytes的带宽,这是相当乐观的,因为现代“普通”硬盘平均读取速度更快,寻道速度较慢。我想说,对于去年的消费类硬盘,每次搜索丢失1字节是一个保守的估计

  • 如果您需要写入原始帧,并且不想以无损方式压缩它们,那么您需要一个能够支持所需带宽的存储系统。假设为8位灰度,则每帧转储2字节,50Hz为100字节/秒。由两个当代现成驱动器组成的分条RAID 0阵列应该能够毫无问题地处理它。

    <
    IMWRITE::IMWRITE(QObject *parent) :
        QObject(parent)
    {
      this->Stop =false;
    }
    void IMWRITE::IMWrite_Process()
    {
        static int counter = 0;
        while(!Stop)
          {
            for(int i = 0 ; i < FINAL_IM_VEC.size() ; i++)
                {
                    QString address = "/home/Provisioner/ThreadT/Results/" + QString::number(counter++) + ".jpg";
                    cv::imwrite(address.toUtf8().constData(),FINAL_IM_VEC[i]);
                    FINAL_IM_VEC.erase(FINAL_IM_VEC.begin() + i);
                    i--;
                }
          }
    
    }