читать изображения из файла параллельно - PullRequest
0 голосов
/ 29 мая 2018

У меня есть эта функция, считывающая негативные изображения из набора данных (около 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);
    }
}

, и для ее обработки требуется много времени, а иногда она блокируется.Как я могу оптимизировать это и сделать это параллельно?

Ответы [ 2 ]

0 голосов
/ 30 мая 2018

Я немного изменил ваш код, чтобы использовать OpenMP для распараллеливания загрузки - фактические изменения минимальны - я просто поместил OpenMP pragma перед циклом for и сериализовал доступ к вектору изображений, поскольку векторы не являются потоковымиsafe.

#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

Затем я решил, что, если вы делаете это достаточно часто, чтобы заботиться, вы, возможно, захотите заплатить небольшую цену заранее, чтобы еще больше улучшить время.Таким образом, вместо того, чтобы делать весь этот ресурсоемкий код для распаковки JPEG-файлов, вы можете преобразовать ваши изображения один раз в более простой для чтения формат, такой как PNM .Итак, я преобразовал все изображения JPEG в PNM, используя GNU Parallel , а затем вместо этого загрузил изображения PNM:

Так это выглядит так:

seq 122000 | parallel convert {}.jpg {}.pnm

И кодis:

...
...
#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

enter image description here


Для компиляциис OpenMP используйте:

g++ -fopenmp =O3 -march native ...
0 голосов
/ 30 мая 2018

Вы можете попробовать это

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

протестировал это кратко, но это должно работать, читая изображения с 4 потоками.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...