在 Windows 8.1 上使用 OpenCV 在 C++ 中加载图像需要很长时间
Posted
技术标签:
【中文标题】在 Windows 8.1 上使用 OpenCV 在 C++ 中加载图像需要很长时间【英文标题】:Loading images takes very long in C++ using OpenCV on Windows 8.1 【发布时间】: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。 我对您将图像加载到矢量中的方式有一点疑问。你能给我们看看那部分吗?或者只是确保没有发生重新分配(您在推送之前保留了正确数量的项目) 【参考方案1】:我不认为 OpenCV 是您的瓶颈。我在运行 OS X 10.11.3 的 8 GB RAM 的 2009 年老式 2.8 GHz Core 2 Duo MacBook Pro 上进行了测试。我能够在 3.3 分钟内加载 300,000 张图像。 150,000 张图片耗时 1.5 分钟。
这是我用来创建 300,000 张图像的程序。它们在我的硬盘上占用了大约 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("%d\n", i);
return 0;
这是我用来创建Item
s 的向量并加载图像的程序。我认为它与您问题中的代码 sn-ps 足以重复该问题。
#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;
我建议删除代码以并行加载图像。正如 cmets 中所指出的,文件 I/O 不能很好地并行化。
如果这没有帮助,你应该尝试在 Unix 或 OS X 上运行你的程序(或让别人为你运行它),看看 Windows 是否是罪魁祸首。
【讨论】:
您好,感谢您的意见。我已经测试了您提供的简化代码。是的,它几乎捕捉到了我的完整应用程序的有问题的功能。我唯一改变的是颜色通道——我的图像是灰度的,所以我改用 CV_8UC1。在我的笔记本电脑(也是 Windows 8.1)上,加载 300.000 张图像大约需要 10 分钟,这对我来说完全没问题。我的应用程序使用了大约 2.7GB 的 RAM,其中 2.3GB 存在于物理 RAM 中。 与我的完整应用程序仅有的两个区别是:项目每个实例使用额外的 440 字节,对于所有 300.000,这只有 125MB。我的图像以几千个为一组位于不同的文件夹中。我不认为其中一个会导致瓶颈......:/我将尝试进一步调试它以最终找到解决方案。您还有什么建议吗? 你是说在 i7 机器上仍然需要几个小时,而现在在笔记本电脑上只需要 10 分钟? 没有。您的代码在我的笔记本电脑上花了 10 分钟,我相信它在我的塔上更快(现在无法测试)。我的代码肯定会在我的笔记本电脑和我的塔上花费数小时。我能够缩小我的问题范围,并将我的新见解作为编辑 3 添加到问题中。以上是关于在 Windows 8.1 上使用 OpenCV 在 C++ 中加载图像需要很长时间的主要内容,如果未能解决你的问题,请参考以下文章
Windows 8.1 中 Visual Studio 12 中的 OpenCV 错误。这是调试时显示一些错误的简单代码。我怎样才能解决这个问题?
Win32 应用程序是不是也可以在 Windows 7 和 Windows 8/8.1 上运行?
使用 Windows 8.1 在 localhost 上测试 PHP 的 mail() 函数 [关闭]