如何遍歷文件夾下的所有圖片(Pyhton&C++)

前言

雖然本文說的是遍歷圖片,但是遍歷其他文件也是可以的。

在進行圖像處理的時候,大部分時候只需要處理單張圖片。但是一旦把圖像處理和機器學習相結合,或者做一些稍大一些的任務的時候,常常需要處理好多圖片。而這裏面,一個最基本的問題就是如何遍歷這些圖片。

用opencv做過人臉識別的人應該知道,那個項目中並沒有進行圖片的遍歷,而是用了一種輔助方案,生成了一個包含所有圖片路徑的文件at.txt,然後通過這個路徑來讀取所有圖片。而且這個輔助文件不僅包含了圖片的路徑,還包含了圖片對應的標籤。所以在進行訓練的時候直接通過這個輔助文件來讀取訓練用的圖片和標籤。

其實如果去看看教程,會發現這個at.txt的生成是通過Python代碼來實現。所以今天就來看一下如何用C++來實現文件夾下所有圖片的遍歷。

當然在此之前還是先給出Python遍歷的代碼,以備後用。

Python遍歷

在之前的數獨項目中,進行圖像處理的時候用到了遍歷文件夾下所有的圖片。主要是利用glob模塊。glob是python自己帶的一個文件操作相關模塊,內容不多,可以用它查找符合自己目的的文件。

# encoding: UTF-8
import glob as gb
import cv2

#Returns a list of all folders with participant numbers
img_path = gb.glob("numbers\\*.jpg") 
for path in img_path:
    img  = cv2.imread(path) 
    cv2.imshow('img',img)
    cv2.waitKey(1000)

C++遍歷

1. opencv自帶函數glob()遍歷

OpenCV自帶一個函數glob()可以遍歷文件,如果用這個函數的話,遍歷文件也是非常簡單的。這個函數非常強大,人臉識別的時候用這個函數應該會比用at.txt更加方便。一個參考示例如下。

#include<opencv2\opencv.hpp>
#include<iostream>

using namespace std;
using namespace cv;

vector<Mat> read_images_in_folder(cv::String pattern);

int main()
{
    cv::String pattern = "G:/temp_picture/*.jpg";
    vector<Mat> images = read_images_in_folder(pattern);

    return 0;   
}

vector<Mat> read_images_in_folder(cv::String pattern)
{
    vector<cv::String> fn;
    glob(pattern, fn, false);

    vector<Mat> images;
    size_t count = fn.size(); //number of png files in images folder
    for (size_t i = 0; i < count; i++)
    {
        images.push_back(imread(fn[i]));
        imshow("img", imread(fn[i]));
        waitKey(1000);
    }
    return images;
}

需要注意的是,這裏的路徑和模式都用的是cv::String

2. 自己寫一個遍歷文件夾的函數

在windows下,沒有dirent.h可用,但是可以根據windows.h自己寫一個遍歷函數。這就有點像是上面的glob的原理和實現了。

#include<opencv2\opencv.hpp>
#include<iostream>
#include <windows.h> // for windows systems

using namespace std;
using namespace cv;

void read_files(std::vector<string> &filepaths,std::vector<string> &filenames, const string &directory);

int main()
{
    string folder = "G:/temp_picture/";
    vector<string> filepaths,filenames;
    read_files(filepaths,filenames, folder);
    for (size_t i = 0; i < filepaths.size(); ++i)
    {
        //Mat src = imread(filepaths[i]);
        Mat src = imread(folder + filenames[i]);
        if (!src.data)
            cerr << "Problem loading image!!!" << endl;
        imshow(filenames[i], src);
        waitKey(1000);
    }
    return 0;

}

void read_files(std::vector<string> &filepaths, std::vector<string> &filenames, const string &directory)
{
    HANDLE dir;
    WIN32_FIND_DATA file_data;

    if ((dir = FindFirstFile((directory + "/*").c_str(), &file_data)) == INVALID_HANDLE_VALUE)
        return; /* No files found */

    do {
        const string file_name = file_data.cFileName;
        const string file_path = directory + "/" + file_name;
        const bool is_directory = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;

        if (file_name[0] == '.')
            continue;

        if (is_directory)
            continue;

        filepaths.push_back(file_path);
        filenames.push_back(file_name);
    } while (FindNextFile(dir, &file_data));

    FindClose(dir);
} 

3. 基於Boost

如果電腦上配置了boost庫,用boost庫來實現這一功能也是比較簡潔的。爲了用這個我還專門完全編譯了Boost。

然而只用到了filesystem。

#include <boost/filesystem.hpp>
#include<iostream>
#include<opencv2\opencv.hpp>

using namespace cv;
using namespace std;
using namespace boost::filesystem;

void readFilenamesBoost(vector<string> &filenames, const string &folder);

int main()
{
    string folder = "G:/temp_picture/";
    vector<string> filenames;
    readFilenamesBoost(filenames, folder);
    for (size_t i = 0; i < filenames.size(); ++i)
    {
        Mat src = imread(folder + filenames[i]);

        if (!src.data)
            cerr << "Problem loading image!!!" << endl;
        imshow("img", src);
        waitKey(1000);
    }
    return 0;
}

void readFilenamesBoost(vector<string> &filenames, const string &folder)
{
    path directory(folder);
    directory_iterator itr(directory), end_itr;
    string current_file = itr->path().string();

    for (; itr != end_itr; ++itr)
    {
        if (is_regular_file(itr->path()))
        {
            string filename = itr->path().filename().string(); // returns just filename
            filenames.push_back(filename);
        }
    }
}

各種方法都記錄在這裏,以便以後用的時候查找。


公衆號CVPy,分享OpenCV和Python的實戰內容。每一篇都會放出完整的代碼。歡迎關注。

公衆號CVPy

發佈了83 篇原創文章 · 獲贊 354 · 訪問量 79萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章