首页 > 解决方案 > 从文件中并行读取图像

问题描述

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

void load_images(const String & dirname, vector< Mat > & img_lst, bool showImages = false)
{
    vector< String > files;
    glob(dirname, files);

    for (size_t i = 0; i < files.size(); ++i)
    {
        Mat img = imread(files[i]); // preia imagine
        if (img.empty())            // treci peste daca este imagine invalida
        {
            cout << files[i] << " is invalid!" << endl;
            continue;
        }

        if (showImages)
        {
            imshow("image", img);
            waitKey(1);
        }
        img_lst.push_back(img);
    }
}

并且需要大量时间来处理,有时它会被阻止。如何优化它并使其并行?

标签: c++imageopencvparallel-processing

解决方案


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

#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);
}

您可以像这样控制线程数:

export OMP_NUM_THREADS=2
time ./main

加载 122,000 张图像的时间根据我使用的线程数而有所不同,如下表所示:

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

然后我决定,如果您经常这样做以关心,您可能希望预先支付一小笔费用以进一步改善时间。因此,您可能希望将图像一次转换为更简单的读取格式,而不是执行所有 CPU 密集型代码来解压缩 JPEG,例如PNM因此,我使用GNU Parallel将所有 JPEG 图像转换为 PNM ,然后加载 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);
...
...

你可以看到时间要短得多:

Nthreads Time(s)
================
1        7
2        4
4        2.5
8        3.2

在此处输入图像描述


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

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

推荐阅读