【发布时间】:2016-02-24 12:59:49
【问题描述】:
我目前正在使用 C++ 开发一个数据驱动的学习应用程序。我有大量数据,超过 300.000 张图像总共需要大约 3 GB。
关于我的工作环境:
- Windows 8.1,64 位
- Visual Studio 2013
- OpenCV
- OpenMP
我的硬件:
- i7-3770
- 8GB 内存
- SSD(系统和 Visual Studio)
- 硬盘
我的简而言之问题是,仅加载图像,因此 3 GB,需要 3 多个小时,我想改进。
实现如下:首先,我从一个文件中加载一些关于图像(不是图像本身)的信息。在内部,我使用一个标准向量,它包含 300.000 个指向我的类 Item 的指针。项目包含从文件和图像(OpenCV Mat)加载的信息,尚未加载。接下来是一些独立的中间步骤。之后,我将遍历我的向量 - 使用 OpenMP 并行化 - 并使用以下方法为每个项目加载图像:
imread(PATH_TO_FILE, CV_LOAD_IMAGE_UNCHANGED);
对我来说真正奇怪的是,增加图片的数量并不是图片加载时间的线性增加。使用 22000 张图片大约需要 22 秒,使用 44000 张图片大约需要 1 分 43 秒,66000 张图片大约需要 4 分钟,依此类推。
我不确定这个问题是由于硬件瓶颈(我最初假设的)还是由于我这边的实现缺陷造成的。我已经考虑过很多,比如:
- 将图像位深度减半并因此将内存大小减半并不会减少所用时间
- 我的应用程序的虚拟内存最大约为 4GB,因此不应该涉及太多交换
- 从我的系统 SSD 加载数据与从我的 HDD 加载数据没有区别
- 为进程赋予更高的优先级(我选择了最高的,即实时的)稍微改进了运行时间,但是,上面给出的运行时间确实已经使用了这种改进
- 即使我使用的是 OpenMP,RessourceManager 指出在加载我的图像期间,我的应用程序只使用了 15% 的 CPU。通过打印,我可以看出所有 8 名工人都在分担负载。
- 使用vector.shrink_to_fit() 缩小了向量大小
在我看来,这些事实不是硬件问题,而是存在实施缺陷。使用包含超过 300.000 个指针的巨大向量是否效率低下?或者我没有考虑过关于 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:我如何设置没有图像的矢量。请注意,我为此部分使用了增强多线程。另请注意,这部分执行时间随数据线性增加。
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 位。请注意,我将他的代码更改为只生成我的图像的灰度图像。在我的笔记本电脑上加载 300.000 张图像大约需要 10 分钟,这很好。
我尽可能简化了我的代码并删除了所有多线程。我已经更改了我的代码,将图像直接加载到项目中,因此在矢量创建期间。
查看资源监视器我注意到我的图像占用了大量内存。加载 10.000 张图像已经占用了 1 GB。使用 CV_LOAD_IMAGE_GRAYSCALE 而不是 CV_LOAD_IMAGE_UNCHANGED 将内存消耗减半。我不明白,我的图像肯定是 96x96x8 位,而且还是太多了。
使用我的完整代码但仅使用一个颜色通道加载由 SSteve 的代码创建的随机图像需要 100 MB 的内存来存储 10.000 个图像和一些额外的东西。单独的图像应该需要大约 90 MB,所以应该没问题。与我的图片相比,这只是一小部分。
简而言之:我的图片似乎导致了问题,但我不明白为什么。
我如何获得这些图像:我用于算法问题部分的图像是由我预处理的。这个预处理步骤是独立的,基本上按比例缩小图像。所以我要工作的图像确实有 240x320 的大小和 16 位深度。然后我将这些图像缩放为 96x96 和 8 位深度。
有没有可能由于某种原因,我缩小的图像以正确的尺寸存储,并且这个尺寸在 Windows 的图像属性中正确显示,但图像仍然包含一些应该“删除”的信息?所以他们占用了比他们应该更多的内存?这对我来说没有任何意义。
感谢到目前为止的所有帮助。
【问题讨论】:
-
可能是硬件问题。尝试使用其他 API 加载图像以进行比较。让测试应用程序变得简单:只加载图像,仅此而已。
-
您的图像是 3GB 硬盘还是内存?如果它们是硬 JPEG,它们将作为位图加载到内存中。这意味着它们的内存远远超过 3GB
-
我不知道 OpenCV,但我们是在谈论 30,000 个压缩图像,在文件系统上占用大约 3GB 空间吗?也就是说,也许它们正在被加载和未压缩占用更多的空间导致内存交换?
-
文件 I/O 不是很可并行化。 15% 的 CPU 大约是一个线程在工作,一个在做 I/O,剩下的六个在等待一个在做 I/O。
-
我对您将图像加载到矢量中的方式有一点疑问。你能给我们看看那部分吗?或者只是确保没有发生重新分配(您在推送之前保留了正确数量的项目)
标签: c++ windows image opencv vector