C++ 并行地从文件中读取图像

C++ 并行地从文件中读取图像,c++,image,opencv,parallel-processing,C++,Image,Opencv,Parallel Processing,我有这个函数从数据集中读取负片图像(大约122000) 无效加载图像(常量字符串和目录名,向量和img lst,bool showImages=false) { 向量文件; glob(dirname,files); 对于(size_t i=0;i

我有这个函数从数据集中读取负片图像(大约122000)

无效加载图像(常量字符串和目录名,向量和img lst,bool showImages=false) { 向量文件; glob(dirname,files); 对于(size_t i=0;i
class parReader
{
public:
    parReader(std::string dirname, std::vector< cv::Mat > & lst);
private:
    size_t filesIdx;
    HANDLE hFilesMux,hImgListMux;
    std::vector<cv::String> files;
    std::vector<cv::Mat> img_lst;
    static void readImgs(parReader *nm);
    const char *getNext();
    void push_back(cv::Mat &img);
};
parReader::parReader(std::string dirname, std::vector<cv::Mat> & lst) :img_lst(lst), filesIdx(0),hFilesMux(NULL),hImgListMux(NULL)
{
    hFilesMux   = CreateMutex(NULL, 0, NULL);
    hImgListMux = CreateMutex(NULL, 0, NULL);
    cv::glob(dirname, files);
    std::thread pr1(readImgs, this);
    std::thread pr2(readImgs, this);
    std::thread pr3(readImgs, this);
    std::thread pr4(readImgs, this);
    pr1.join();
    pr2.join();
    pr3.join();
    pr4.join();
    CloseHandle(hFilesMux);
    CloseHandle(hImgListMux);
}
const char *parReader::getNext()
{
    const char *res = NULL;
    WaitForSingleObject(hFilesMux, INFINITE);
    if (filesIdx < files.size())
        res = files[filesIdx++].c_str();
    ReleaseMutex(hFilesMux);
    return res;
}
void parReader::push_back(cv::Mat &img)
{
    WaitForSingleObject(hImgListMux, INFINITE);
    img_lst.push_back(img);
    ReleaseMutex(hImgListMux);
}

void parReader::readImgs(parReader *nm)
{
    while (true)
    {
        const char *fn = nm->getNext();
        if (fn == NULL) break;
        cv::Mat img = cv::imread(fn); 
        if (img.empty())            // treci peste daca este imagine invalida
        {
            std::cout << fn << " is invalid!" << std::endl;
            continue;
        }
        nm->push_back(img);
    }
}



int main()
{
    std::vector<cv::Mat> imgList;

    parReader mgr("*.png",imgList);
}
类读取器
{
公众:
parReader(std::string dirname,std::vector&lst);
私人:
大小\u t文件IDX;
处理Hflesmux、hImgListMux;
std::矢量文件;
std::向量img_lst;
静态空隙读数(帕雷德尔*纳米);
常量char*getNext();
无效推回(cv::Mat和img);
};
parReader::parReader(std::string dirname,std::vector&lst):img_lst(lst),filesIdx(0),hFilesMux(NULL),hImgListMux(NULL)
{
hFilesMux=CreateMutex(NULL,0,NULL);
hImgListMux=CreateMutex(NULL,0,NULL);
cv::glob(目录名、文件);
std::线程pr1(readImgs,this);
std::线程pr2(readImgs,this);
std::线程pr3(readImgs,this);
std::线程pr4(readImgs,this);
pr1.join();
pr2.join();
pr3.join();
pr4.join();
闭合手柄(hFilesMux);
闭柄(hImgListMux);
}
常量char*parReader::getNext()
{
const char*res=NULL;
WaitForSingleObject(HFilesMax,无限);
if(filesIdxgetNext();
如果(fn==NULL)中断;
cv::Mat img=cv::imread(fn);
if(img.empty())//treci peste daca este imagine invalida
{
你可以试试这个

class parReader
{
public:
    parReader(std::string dirname, std::vector< cv::Mat > & lst);
private:
    size_t filesIdx;
    HANDLE hFilesMux,hImgListMux;
    std::vector<cv::String> files;
    std::vector<cv::Mat> img_lst;
    static void readImgs(parReader *nm);
    const char *getNext();
    void push_back(cv::Mat &img);
};
parReader::parReader(std::string dirname, std::vector<cv::Mat> & lst) :img_lst(lst), filesIdx(0),hFilesMux(NULL),hImgListMux(NULL)
{
    hFilesMux   = CreateMutex(NULL, 0, NULL);
    hImgListMux = CreateMutex(NULL, 0, NULL);
    cv::glob(dirname, files);
    std::thread pr1(readImgs, this);
    std::thread pr2(readImgs, this);
    std::thread pr3(readImgs, this);
    std::thread pr4(readImgs, this);
    pr1.join();
    pr2.join();
    pr3.join();
    pr4.join();
    CloseHandle(hFilesMux);
    CloseHandle(hImgListMux);
}
const char *parReader::getNext()
{
    const char *res = NULL;
    WaitForSingleObject(hFilesMux, INFINITE);
    if (filesIdx < files.size())
        res = files[filesIdx++].c_str();
    ReleaseMutex(hFilesMux);
    return res;
}
void parReader::push_back(cv::Mat &img)
{
    WaitForSingleObject(hImgListMux, INFINITE);
    img_lst.push_back(img);
    ReleaseMutex(hImgListMux);
}

void parReader::readImgs(parReader *nm)
{
    while (true)
    {
        const char *fn = nm->getNext();
        if (fn == NULL) break;
        cv::Mat img = cv::imread(fn); 
        if (img.empty())            // treci peste daca este imagine invalida
        {
            std::cout << fn << " is invalid!" << std::endl;
            continue;
        }
        nm->push_back(img);
    }
}



int main()
{
    std::vector<cv::Mat> imgList;

    parReader mgr("*.png",imgList);
}
类读取器
{
公众:
parReader(std::string dirname,std::vector&lst);
私人:
大小\u t文件IDX;
处理Hflesmux、hImgListMux;
std::矢量文件;
std::向量img_lst;
静态空隙读数(帕雷德尔*纳米);
常量char*getNext();
无效推回(cv::Mat和img);
};
parReader::parReader(std::string dirname,std::vector&lst):img_lst(lst),filesIdx(0),hFilesMux(NULL),hImgListMux(NULL)
{
hFilesMux=CreateMutex(NULL,0,NULL);
hImgListMux=CreateMutex(NULL,0,NULL);
cv::glob(目录名、文件);
std::线程pr1(readImgs,this);
std::线程pr2(readImgs,this);
std::线程pr3(readImgs,this);
std::线程pr4(readImgs,this);
pr1.join();
pr2.join();
pr3.join();
pr4.join();
闭合手柄(hFilesMux);
闭柄(hImgListMux);
}
常量char*parReader::getNext()
{
const char*res=NULL;
WaitForSingleObject(HFilesMax,无限);
if(filesIdxgetNext();
如果(fn==NULL)中断;
cv::Mat img=cv::imread(fn);
if(img.empty())//treci peste daca este imagine invalida
{

std::cout我稍微更改了您的代码,以使用OpenMP并行加载-实际更改最小-我只是在
for
循环之前放置一个OpenMP
pragma
,并序列化访问图像向量,因为向量不是线程安全的

#include <iostream>
#include <vector>
#include <mutex>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

void load_images(int start,int end){
   vector<Mat>img_lst;
   mutex mtx;

#pragma omp parallel for
   for(size_t i=start;i<=end;i++){
      char filename[16];
      sprintf(filename,"%d.jpg",i);
      Mat img = imread(filename);
      if (img.empty()){
         cerr << "ERROR: Failed to load " << filename << endl;
      }
      mtx.lock();
      img_lst.push_back(img);
      mtx.unlock();
   }
   mtx.lock();
   cout << "INFO: Loaded " << img_lst.size() << endl;
   mtx.unlock();
}

int
main(int argc,char*argv[])
{
    load_images(1,122000);
}
加载122000个图像的时间根据下表中我使用的线程数而变化:

Threads Time (s)
================
1       44
2       23
4       12.4
8       8.8

然后,我决定,如果你经常这么做,你可能会想提前付出一点代价来进一步提高时间。因此,与其用CPU密集型代码来解压JPEG,不如将图像转换一次,转换为更简单的读取格式,例如。因此,我将所有JPEG图像转换为pNM使用GNU并行,然后加载PNM图像:

这看起来像:

seq 122000 | parallel convert {}.jpg {}.pnm
代码是:

...
...
#pragma omp parallel for
   for(size_t i=start;i<=end;i++){
      char filename[16];
      sprintf(filename,"%d.pnm",i);        <--- ONLY LINE CHANGED
      Mat img = imread(filename);
...
...


要使用OpenMP进行编译,请使用:

g++ -fopenmp =O3 -march native ...

我稍微修改了您的代码,以使用OpenMP并行加载-实际更改最小-我只是在
for
循环之前放置了一个OpenMP
pragma
,并序列化了对图像向量的访问,因为向量不是线程安全的

#include <iostream>
#include <vector>
#include <mutex>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

void load_images(int start,int end){
   vector<Mat>img_lst;
   mutex mtx;

#pragma omp parallel for
   for(size_t i=start;i<=end;i++){
      char filename[16];
      sprintf(filename,"%d.jpg",i);
      Mat img = imread(filename);
      if (img.empty()){
         cerr << "ERROR: Failed to load " << filename << endl;
      }
      mtx.lock();
      img_lst.push_back(img);
      mtx.unlock();
   }
   mtx.lock();
   cout << "INFO: Loaded " << img_lst.size() << endl;
   mtx.unlock();
}

int
main(int argc,char*argv[])
{
    load_images(1,122000);
}
加载122000个图像的时间根据下表中我使用的线程数而变化:

Threads Time (s)
================
1       44
2       23
4       12.4
8       8.8

然后,我决定,如果你经常这么做,你可能会想提前付出一点代价来进一步提高时间。因此,与其用CPU密集型代码来解压JPEG,不如将图像转换一次,转换为更简单的读取格式,例如。因此,我将所有JPEG图像转换为pNM使用GNU并行,然后加载PNM图像:

这看起来像:

seq 122000 | parallel convert {}.jpg {}.pnm
代码是:

...
...
#pragma omp parallel for
   for(size_t i=start;i<=end;i++){
      char filename[16];
      sprintf(filename,"%d.pnm",i);        <--- ONLY LINE CHANGED
      Mat img = imread(filename);
...
...


要使用OpenMP进行编译,请使用:

g++ -fopenmp =O3 -march native ...

CUDA无法进行文件I/O,因此不可能不使用CUDAgood来了解,谢谢:)图像的尺寸以像素为单位是多少?以kB为单位是多少?你到底打算如何处理122000个图像,一次全部存储在内存中?你的磁盘速度是否很快,文件是否分布在多个文件系统和驱动器上?你使用的是什么操作系统?安装了多少RAMed?我在试着训练Hog,20kb*122000,96x120我想你可以试着并行启动4个线程看看是否有帮助…CUDA不能做文件I/O,所以不可能不用CUDAgood知道谢谢:)图像的像素尺寸是多少?以kB为单位?耳朵上是什么