欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

OpenCV 利用Directory类实现文件夹遍历

程序员文章站 2022-06-12 10:14:26
...

最近,我在进行新的工作中,需要对多张图片进行测试,一一测试太慢了,于是想到将需要处理的图片放到一个文件夹中,对文件夹中所有图像进行遍历,这样可以省时省力.

参考博客https://blog.csdn.net/watkinsong/article/details/9227439中的内容,我在VS2010中实践了一番:

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	std::string dirPath = "E:\\test";	//文件夹路径
	cv::Directory dir;			//文件夹类对象
	std::vector<std::string> fileNames = dir.GetListFiles(dirPath, "*.bmp", false);	//获取文件夹下文件名序列
	for(size_t i = 0; i < fileNames.size(); i++)
	{
		std::string fileName = fileNames[i];			//取出当前文件名
		std::string fileFullPath = dirPath + fileName;	//获取当前文件完整路径
		std::cout << "file name: " << fileName << endl;	//打印当前文件名
		std::cout << "file paht: " << fileFullPath << endl;	//打印当前文件路径
	}
	system("pause");
	return 0;
}

控制台输出如下:

OpenCV 利用Directory类实现文件夹遍历

查看一下我测试用的文件夹

OpenCV 利用Directory类实现文件夹遍历

结果正确.

虽然得到我想要的结果了,但是觉得有必要大致了解一下用到的类和函数.上述实现主要用到了Directory类的成员函数GetListFiles,

下面简单学习一下,便于以后遇到可以快速使用.

OpenCV 利用Directory类实现文件夹遍历

可以看到Directory类存在于opencv中的contrib模块,含有三个成员函数:

(1)static std::vector<std::string> GetListFiles  ( const std::string& path, const std::string & exten = "*", bool addPath = true );

(2)static std::vector<std::string> GetListFilesR ( const std::string& path, const std::string & exten = "*", bool addPath = true );

(3)static std::vector<std::string> GetListFolders( const std::string& path, const std::string & exten = "*", bool addPath = true );

可以看到三个成员函数的返回值都是std::vector<std::string>,输入参数都是const std::string& path, const std::string & exten = "*", bool addPath = true.关于返回值和输入参数,需要结合函数实现加以理解.

在D:\opencv\opencv2410\opencv\sources\modules\contrib\src\inputoutput.cpp中可以看到函数实现

首先看一下GetListFiles函数实现

    std::vector<std::string> Directory::GetListFiles( const std::string& path, const std::string & exten, bool addPath )
    {
        std::vector<std::string> list;
        list.clear();
        std::string path_f = path + "/" + exten;
        #ifdef WIN32
        #ifdef HAVE_WINRT
            WIN32_FIND_DATAW FindFileData;
        #else
            WIN32_FIND_DATAA FindFileData;
        #endif
        HANDLE hFind;

        #ifdef HAVE_WINRT
            wchar_t wpath[MAX_PATH];
            size_t copied = mbstowcs(wpath, path_f.c_str(), MAX_PATH);
            CV_Assert((copied != MAX_PATH) && (copied != (size_t)-1));
            hFind = FindFirstFileExW(wpath, FindExInfoStandard, &FindFileData, FindExSearchNameMatch, NULL, 0);
        #else
            hFind = FindFirstFileA((LPCSTR)path_f.c_str(), &FindFileData);
        #endif
            if (hFind == INVALID_HANDLE_VALUE)
            {
                return list;
            }
            else
            {
                do
                {
                    if (FindFileData.dwFileAttributes == FILE_ATTRIBUTE_NORMAL  ||
                        FindFileData.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE ||
                        FindFileData.dwFileAttributes == FILE_ATTRIBUTE_HIDDEN  ||
                        FindFileData.dwFileAttributes == FILE_ATTRIBUTE_SYSTEM  ||
                        FindFileData.dwFileAttributes == FILE_ATTRIBUTE_READONLY)
                    {
                        char* fname;
                    #ifdef HAVE_WINRT
                        char fname_tmp[MAX_PATH] = {0};
                        size_t copied = wcstombs(fname_tmp, FindFileData.cFileName, MAX_PATH);
                        CV_Assert((copied != MAX_PATH) && (copied != (size_t)-1));
                        fname = fname_tmp;
                    #else
                        fname = FindFileData.cFileName;
                    #endif
                        if (addPath)
                            list.push_back(path + "/" + std::string(fname));
                        else
                            list.push_back(std::string(fname));
                    }
                }
            #ifdef HAVE_WINRT
                while(FindNextFileW(hFind, &FindFileData));
            #else
                while(FindNextFileA(hFind, &FindFileData));
            #endif
                FindClose(hFind);
            }
        #else
            (void)addPath;
            DIR *dp;
            struct dirent *dirp;
            if((dp = opendir(path.c_str())) == NULL)
            {
                return list;
            }

            while ((dirp = readdir(dp)) != NULL)
            {
                if (dirp->d_type == DT_REG)
                {
                    if (exten.compare("*") == 0)
                        list.push_back(static_cast<std::string>(dirp->d_name));
                    else
                        if (std::string(dirp->d_name).find(exten) != std::string::npos)
                            list.push_back(static_cast<std::string>(dirp->d_name));
                }
            }
            closedir(dp);
        #endif

        return list;
    }

虽然我不能完全看懂代码,但是可以大概了解返回值和输入参数代表什么.

std::string path_f = path + "/" + exten;这句话可以说明path是输入待遍历的文件夹路径,extern是待遍历的文件的扩展名

if (addPath) 

    list.push_back(path + "/" + std::string(fname));

else

    list.push_back(std::string(fname));

这句if-else判断是根据addPath的值决定返回的list中存放的是文件名还是文件的完整路径

如果addPath是false,则返回的是文件名

如果addPath是True,则返回的是文件完整路径

这一点也就解释了上述实现中使用false所以得到的只是文件的名,得到完整路径还需要自己连接一下.如果改成true,是否真的可以直接得到路径呢?验证一下吧:

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	std::string dirPath = "E:\\test";	//文件夹路径
	cv::Directory dir;			//文件夹类对象
	std::vector<std::string> fileNames = dir.GetListFiles(dirPath, "*.bmp", true);	//获取文件夹下文件名序列
	for(size_t i = 0; i < fileNames.size(); i++)
	{
		std::string fileName = fileNames[i];			//取出当前文件名
		//std::string fileFullPath = dirPath + fileName;	//获取当前文件完整路径
		std::cout << "file name: " << fileName << endl;	//打印当前文件名
		//std::cout << "file paht: " << fileFullPath << endl;	//打印当前文件路径
	}
	system("pause");
	return 0;
}

OpenCV 利用Directory类实现文件夹遍历

这个路径有点奇怪,前面是\后面是/,然后自习看函数实现,里面用的都是/,因此我也改成/就可以了,改成

std::string dirPath = "E:/test";    //文件夹路径

在运行一下

OpenCV 利用Directory类实现文件夹遍历

这样就可以直接返回正常的路径了.

本来还想把函数GetListFolders和函数GetListFilesR好好研究一下,但是时间有点太晚了,得睡觉了,明天还得上班.简单粘贴一下别人博客中的话:

(1)、GetListFiles:遍历指定文件夹下的所有文件,不包括指定文件夹内的文件夹;

(2)、GetListFolders:遍历指定文件夹下的所有文件夹,不包括指定文件夹下的文件;

(3)、GetListFilesR:遍历指定文件夹下的所有文件,包括指定文件夹内的文件夹。

也就是说GetListFilesR是集合了GetListFiles函数和GetListFolders函数的功能,我看了一眼实现,确实如此.这个实现基本一下就能看懂,先遍历文件夹下所有文件(不包括指定文件夹内的文件夹),然后遍历文件夹下所有文件夹(不包括指定文件夹下的文件),最后遍历上一部得到的文件夹下所有文件,这样返回的就是文件夹下所有的文件(包括指定文件夹内的文件夹).

    std::vector<std::string> Directory::GetListFilesR ( const std::string& path, const std::string & exten, bool addPath )
    {
        std::vector<std::string> list = Directory::GetListFiles(path, exten, addPath);

        std::vector<std::string> dirs = Directory::GetListFolders(path, exten, addPath);

        std::vector<std::string>::const_iterator it;
        for (it = dirs.begin(); it != dirs.end(); ++it)
        {
            std::vector<std::string> cl = Directory::GetListFiles(*it, exten, addPath);
            list.insert(list.end(), cl.begin(), cl.end());
        }

        return list;
    }

}

有时间利用这三个函数完成一下文件夹对比功能的实现,之前在github上下了一个python版的实现,看到这三个函数我觉得也可以用opencv实现一下文件夹比对.

 

参考博客:

https://blog.csdn.net/watkinsong/article/details/9227439

https://blog.csdn.net/fengbingchun/article/details/42435901

相关标签: 文件遍历