在Windows 8.1上使用OpenCV在C++中加载图像需要很长时间

Loading images takes very long in C++ using OpenCV on Windows 8.1

本文关键字:图像 加载 长时间 OpenCV Windows C++      更新时间:2023-10-16

我目前正在C++中开发一个数据驱动的学习应用程序。我有大量的数据,超过300000个图像总共需要大约3 GB。

关于我的工作环境

  • Windows 8.1,64位
  • Visual Studio 2013
  • OpenCV
  • OpenMP

我的硬件

  • i7-3770
  • 8GB内存
  • SSD(系统和Visual Studio)
  • HDD

简而言之,我的问题是,仅加载图像(因此为3 GB)需要3个多小时,我希望对此进行改进。

实现如下:首先,我从文件中加载一些关于图像(而不是图像本身)的信息。在内部,我使用一个标准向量,它包含指向我的类Item的300000个指针。Item包含从文件加载的信息和尚未加载的图像(OpenCV Mat)。接下来是一些独立的中间步骤。之后,我迭代我的矢量-使用OpenMP并行化-并使用加载每个项目的图像

imread(PATH_TO_FILE, CV_LOAD_IMAGE_UNCHANGED);

对我来说,真正奇怪的是,增加图像数量并不是图像加载时间的线性增加。使用22.000张图像大约需要22秒,使用44.000张图像需要1分43秒,66.000张图像花费大约4分钟,依此类推

我不确定这个问题是由于硬件瓶颈(我一开始认为是这样)还是由于我这边的实现缺陷。我已经考虑了很多,比如:

  • 将图像位深度减半并因此将内存大小减半不会减少所花费的时间
  • 我的应用程序的虚拟内存最大为4GB左右,所以不应该有太多的交换
  • 从系统SSD加载数据和从HDD加载数据没有区别
  • 给进程一个更高的优先级(我选择了最高的,这是实时的)稍微改善了运行时间,然而,上面给出的运行时间已经使用了这种改进
  • 尽管我使用的是OpenMP,但RessourceManager表示,在加载图像的过程中,我的应用程序只使用了我CPU的15%。通过打印,我可以看出有8名工人在分担装载
  • 使用vector.shrink_to_fit()缩小矢量大小

在我看来,这些事实不是硬件问题,而是实现缺陷。使用一个包含超过300000个指针的巨大向量是否效率低下?或者关于OpenCV Mat的任何我没有考虑过的事情?关于我如何进一步查明问题,有什么提示吗?我很感激任何关于导致这种行为的原因以及我如何避免这种行为的建议。

提前感谢!

编辑:如何将图像加载到矢量中。请注意,我重命名了一些东西,所以可能会有拼写错误。

void LoadAllImages()
{
for (int i = 0; i < data->size(); i++)
{
Item* cur_item = data->at(i);
cur_item->setImage(cur_item->loadImage());
}
}

Mat Item::loadImage()
{
return imread(IMAGES_PATH + image_name_, CV_LOAD_IMAGE_UNCHANGED);
}

void Item::setImage(Mat img)
{
img_ = img;
}

EDIT2:如何在没有图像的情况下设置矢量。注意,我在这部分使用了boosts多线程。还要注意的是,这个部件的执行时间随着数据的线性增加。

void foo(vector<Item*>* data, const string file_path, const string file_name)
{
//open file
string image_name;
boost::mutex data_mutex;
boost::thread_group thread_group;
while (file >> image_name)
{
//reading other data regarding the current image
thread_group.add_thread(new boost::thread(addDataToVectorThread, data, image_name, other_data_read, &data_mutex));
}
thread_group.join_all();
}

void FileHandler::addDataToVectorThread(vector<Item*>* data, string image_name, vector<float> other_data, boost::mutex* data_mutex)
{
Item* item = new Item(other_data, image_name);
data_mutex->lock();
data->push_back(item);
data_mutex->unlock();
}

EDIT3:我尝试了SSteve提供的代码,能够缩小问题范围。这个代码生成与我的大小相同的随机图像,所以是96x96,颜色深度为8位。请注意,我更改了他的代码,只生成灰度图像作为我的图像。在我的笔记本电脑上加载300000张图片花了大约10分钟,这很好。

我尽可能简化了我的代码,并删除了所有多线程。我已经更改了我的代码,使图像直接加载到Items中,因此在矢量创建过程中也是如此。

在观看资源监视器时,我注意到我的图像占用了大量内存。加载10000个图像已占用1 GB。使用CV_LOAD_IMAGE_GRAYSCALE而不是CV_LOAD_IMAGE_UNCHANGED可将内存消耗减半。我不明白,我的图像肯定是96x96x8位,而且还是太多了。

使用我的完整代码,但只使用一个颜色通道加载SSteve代码创建的随机图像,需要100 MB的内存来存储10000个图像和一些额外的东西。仅图像就应该占用~90 MB,所以应该没问题。与我的照片相比,这只是一小部分。

简而言之:我的图片似乎造成了问题,但我不明白为什么。

如何获取这些图像:我对算法中有问题的部分使用的图像进行预处理。这个预处理步骤是独立的,基本上是按比例缩小图像。所以我要处理的图像尺寸是240x320,深度是16位。然后我将这些图像缩放到96x96和8位深度。

是否有可能由于某种原因,我缩小的图像以正确的大小存储,并且Windows在图像属性中正确显示了该大小,但图像中仍然包含一些应该"删除"的信息?以至于它们占用了比应该占用的更多的内存?这对我来说毫无意义。

到目前为止,谢谢你的帮助。

我不认为OpenCV是您的瓶颈。我在2009年的2.8 GHz酷睿2 Duo MacBook Pro上做了一个测试,它有8 GB RAM,运行OS X 10.11.3。我能够在3.3分钟内加载300000张图像。150000张图片耗时1.5分钟。

这是我用来创建300000张图片的程序。它们占用了我硬盘上大约8.6 GB的空间。

#include "opencv2/core.hpp"
#include "opencv2/imgcodecs.hpp"
using namespace cv;
class Item;
int main(int argc, char *argv[]) {
Mat image(Size(96,96), CV_8UC3);
RNG rng;
char fname[256];
for (int i = 0; i < 300000; i++) {
rng.fill(image, RNG::UNIFORM, 0, 256);
sprintf(fname, "img%06d.png", i);
imwrite(fname, image);
if (0 == i % 500) {
printf("%dn", i);
}
}
return 0;
}

这是我用来创建Items矢量并加载图像的程序。我认为它与你问题中的代码片段足够相似,可以重复这个问题。

#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
using namespace std;
using namespace cv;
#define CV_LOAD_IMAGE_UNCHANGED -1
String IMAGES_PATH = "/Users/steve/Development/tests/so35602911/images/";
class Item {
public:
String image_name;
Mat img_;
Mat loadImage();
void setImage(Mat img);
};
Mat Item::loadImage() {
return imread(IMAGES_PATH + image_name, CV_LOAD_IMAGE_UNCHANGED);
}
void Item::setImage(Mat img) {
img_ = img;
}
int main(int argc, char *argv[]) {
int imagesToProcess = 300000;
vector<Item*> items;
char filename[256];
for (int i = 0; i < imagesToProcess; i++) {
Item *theItem = new Item;
sprintf(filename, "img%06d.png", i);
theItem->image_name = filename;
items.push_back(theItem);
}
printf("Set up %lu items.n", items.size());
time_t startTime = time(0);
for (int i = 0; i < items.size(); i++) {
Item* cur_item = items[i];
cur_item->setImage(cur_item->loadImage());
}
time_t endTime = time(0);
printf("%lu images. Finished in %.1f minutes.n", items.size(), (endTime - startTime) / 60.0);
//Show the last image just to prove they got loaded
//imshow("last", items[items.size() - 1]->img_);
//waitKey(0);
return 0;
}

我建议删除代码以并行加载图像。正如评论中指出的,文件I/O的并行性不好。

如果这没有帮助,你应该试着在Unix或OSX上运行你的程序(或找人帮你运行),看看Windows是否是罪魁祸首。