从/在一个目录中加载/保存多个图像 - opencv c++

Posted

技术标签:

【中文标题】从/在一个目录中加载/保存多个图像 - opencv c++【英文标题】:load/save multiple images from/in a directory - opencv c++ 【发布时间】:2018-07-30 11:05:06 【问题描述】:

我想从一个目录加载很多图像(虽然不是顺序名称)。编辑它们,然后尽可能将它们保存在具有原始名称的不同目录中。 我这样加载它们:

glob("/photos/field_new/*.jpg", fn, false);
size_t count = fn.size(); //number of jpg files in images folder
for (size_t i=0; i<count; i++)
    images.push_back(imread(fn[i]));

有什么想法可以将它们保存在目录 /photos/results/ 中吗? 如果可能的话,用他们原来的名字?

【问题讨论】:

如果可以使用,我会推荐filesytem library,特别是path class。唯一的问题是它是 c++17 我会使用 dirent.h 文件和函数 使用了增强。工作正常! 【参考方案1】:

如果你有 C++17,这会很容易,因为标准中有文件系统库(std::filesystem)。否则,我会建议您获得非常相似的 boost::filesystem(您应该很好地将所有 std::filesystem 替换为 boost::filesystem)。

要从某个文件夹加载所有图像,有 2 个辅助函数:

#include <filesystem> //for boost change this to #include <boost/filesystem> and all std:: to boost::
#include <opencv2/opencv.hpp> 

bool isSupportedFileType(const std::filesystem::path& pathToFile, 
                         const std::vector<std::string>& extensions)

    auto extension = pathToFile.extension().string();
    std::transform(extension.begin(), extension.end(), extension.begin(), [](char c)
                   
                       return static_cast<char>(std::tolower(c));
                   );

    return std::find(extensions.begin(), extensions.end(), extension) != extensions.end();


std::tuple<std::vector<cv::Mat>, std::vector<std::filesystem::path>> loadImages(const std::filesystem::path& path,
                                                                                const std::vector<std::string>& extensions)

    std::vector<cv::Mat> images;
    std::vector<std::filesystem::path> names;
    for (const auto& dirIt : filesystem::DirectoryIterator(path))
    
        if (std::filesystem::is_regular_file(dirIt.path()) && isSupportedFileType(dirIt.path(), extensions))
        
            auto mask = cv::imread(dirIt.path().string(), cv::IMREAD_UNCHANGED);
            if (mask.data != nullptr) //there can be problem and image is not loaded
            
                images.emplace_back(std::move(mask));
                names.emplace_back(dirIt.path().stem());
            
        
    
    return images, names;

你可以这样使用它(假设 C++17):

auto [images, names] = loadImages("/photos/field_new/", ".jpg", ".jpeg");

或 (C++11)

auto tupleImageName = loadImages("/photos/field_new/", ".jpg", ".jpeg");
auto images = std::get<0>(tupleImageName);
auto names = std::get<1>(tupleImageName);

要保存你可以使用这个功能:

void saveImages(const std::filesystem::path& path,
                const std::vector<cv::Mat>& images, 
                const std::vector<std::filesystem::path>& names)

    for(auto i = 0u; i < images.size(); ++i)
    
        cv::imwrite((path / names[i]).string(), images[i]);
    

像这样:

saveImages("pathToResults",images,names);

在此保存功能中,如果图像数量与名称相同,最好执行一些验证,否则可能会出现超出矢量边界的问题。

【讨论】:

我认为我正在使用 c++11,所以我将使用 boost::filesystem。我现在将尝试代码。但要正确:我将这两个函数粘贴到我的程序中,然后调用类似“auto [images, names] = loadImages("/photos/field_new/", ".jpg", ".jpeg") 之类的函数;"在我的主要?然后我有两个数组,一个带有图像,一个带有名称? 如果你使用的是 c++11 会有区别。我会更新帖子。但是,是的,如果您在 main 中调用此函数,它将加载所有内容。 我收到此错误:致命错误:文件系统:没有此类文件或目录编译终止。 --- 当我删除我定义文件系统的行时,我得到这个错误:'boost'没有命名类型 bool isSupportedFileType(const boost::filesystem::path& pathToFile, 因为#include 适用于std::filesystem,如果你有boost,那么它将类似于#include 。 isSupportedFileType 是我发布的函数。您确定链接器可以看到它吗?看来您在 loadImages 函数之前没有定义。 boost 仍然有问题...我尝试链接库但没有运气...我在 cmdl 中使用它:g++ -g -Wall -O4 prg.cpp -o prg @ 987654326@ -std=c++11 -L/usr/local/lib/ -lboost_system -lboost_filesystem 我在这里做错了什么...?我得到的错误是:致命错误:boost/filesystem:没有这样的文件或目录编译终止。

以上是关于从/在一个目录中加载/保存多个图像 - opencv c++的主要内容,如果未能解决你的问题,请参考以下文章

ScrollView:如何从文档中加载图像

在 UIwebview 中加载本地图像

当我在我的 android 应用程序中从图库中加载图像时,为啥位图返回较小的图像?

在 webview 中加载保存在 sdcard 中的图像

在同一个 UIImageView 中加载多个图像会在显示新图像之前闪烁最后一个图像

在 tableView 中加载 iPhone 磁盘图像(像照片应用程序)