1

This code is the trainer code for facial recognition using OpenCV. It crops and equalizes images to include only the face. The only error that is occurring is that the stat() function returns a value -1 and the files under D:\Project\Original are not accessed.

The output of the following is:

-1 Cannot access Folder1

Please help me understand why this is happening. This error did not occur when the same code(with minor changes) was compiled on CodeBlocks 16.01 with OpenCV 2.4.9

#include <iostream>
#include <fcntl.h>
#include <sys/stat.h>
#include <string>
#include <string.h>
#include <fstream>
#include <string.h>
#include <direct.h>
#include <dirent.h>
#include <opencv/cv.h>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/objdetect.hpp>

using namespace std;
using namespace cv;

char* IMG_SEP = "_";
int MAX_IMAGE_NAME_SIZE = 100;
int IM_HEIGHT = 200;
int IM_WIDTH = 200;
String face_cascade_name = "haarcascade_frontalface_alt.xml";
String eyes_cascade_name = "haarcascade_eye_tree_eyeglasses.xml";
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;
vector<string> fileNames;
vector<string> outputLabel;
vector<string> outputPath;
char* srcDirName = "D:/Project/Original";
char* dstDirName = "D:/Project/Cropped";
char* CSV_PATH = "D:/Project/Cropped/myCSV.csv";

void getFileNames(char* path) {
    DIR *dir;
    struct stat info;
    struct dirent *ent;
    if ((dir = opendir(path)) != NULL) {
        while ((ent = readdir(dir)) != NULL) {
            if ((!strcmp(ent->d_name, ".") == 0) && (!strcmp(ent->d_name, "..") == 0)) {

                char* temp = (char*)malloc(256);
                sprintf_s(temp, 100, "%s%s", path, ent->d_name);

                // THIS IS WHERE THE DEBUGGER GOES. STAT RETURNS -1
                if (stat(temp, &info) != 0) {
                    cout << stat(temp, &info) << " ";
                    cout << "Cannot access " << ent->d_name << "\n";
                }


                if (info.st_mode & S_IFREG) {
                    string temp1 = ent->d_name;
                    temp1 = temp1.substr(0, temp1.rfind(IMG_SEP));
                    temp1 = dstDirName + temp1;
                    _mkdir(temp1.c_str());
                    fileNames.push_back(temp);
                }

                else if (info.st_mode & S_IFDIR) {
                    char* temp1 = (char*)malloc(256);
                    sprintf_s(temp1, 100,  "%s/%s", dstDirName, ent->d_name);
                    _mkdir(temp1);
                    strcat_s(temp, sizeof temp, "/");
                    getFileNames(temp);
                }
            }
        }
        closedir(dir);
    }
    else {
        cout << "Could not open the required image directory";
    }
}

void printVector(vector<string> images) {
    for (int i = 0; i < images.size(); i++) {
    cout << images[i] << "\n";
    }
}

void initializeDetector() {
    if (!face_cascade.load(face_cascade_name)) {
        cout << "Error while loading the face detection cascade classifier";
    }

    if (!eyes_cascade.load(eyes_cascade_name)) {
        cout << "Error while loading the eye detection cascade classifier";
    }
}

void detectAndStore(Mat image, String imageName) {
    vector<Rect> faces;
    vector<Rect> eyes;
    Mat frame_grey;
    cvtColor(image, frame_grey, CV_BGR2GRAY);
    equalizeHist(frame_grey, frame_grey);
    face_cascade.detectMultiScale(frame_grey, faces, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30));
    //if(faces.size() == 1){
    for (size_t i = 0; i < faces.size(); i++) {
        Mat faceROI = frame_grey(faces[i]);
        eyes_cascade.detectMultiScale(faceROI, eyes, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30));
        if (eyes.size() < 1) {
            continue;
        }
        resize(faceROI, faceROI, Size(IM_WIDTH, IM_HEIGHT), 1.0, 1.0, INTER_CUBIC);
        String fileName = imageName;
        int posBeg = fileName.rfind('/') + 1;
        String label = fileName.substr(posBeg, MAX_IMAGE_NAME_SIZE);
        int posEnd = label.rfind('.');
        String labelNameWithNum = label.substr(0, posEnd);
        cout << "Cropping and storing " << labelNameWithNum << "\n";
        int pos = labelNameWithNum.rfind(IMG_SEP);
        String labelNameWithoutNum = labelNameWithNum.substr(0, pos);
        String destination = dstDirName + labelNameWithoutNum + "/" + label;
        outputPath.push_back(destination);
        outputLabel.push_back(labelNameWithoutNum);
        equalizeHist(faceROI, faceROI);
        imwrite(destination, faceROI);
        break;
    }
}

void processImages() {
    initializeDetector();
    for (int i = 0; i < fileNames.size(); i++) {
        Mat image = imread(fileNames[i], CV_LOAD_IMAGE_COLOR);
        detectAndStore(image, fileNames[i]);
    }
}

void createCSV() {
    ofstream myFile;
    myFile.open(CSV_PATH, ios_base::out);
    for (int i = 0; i < outputPath.size(); i++) {
        myFile << outputPath[i] << ";" << outputLabel[i] << "\n";
    }
    myFile.close();

}

int main() {
    getFileNames(srcDirName);
    processImages();
    createCSV();
    return 0;
}

2 Answers2

2

Since you're using OpenCV 3.1, you can use glob. This avoids convoluted code like yours, along with its bug.

Your getFileNames reduces basically to:

vector<cv::String> fileNames; // This must be a cv::String now

...

void getFileNames(std::string path)
{
    cv::glob(path,fileNames,false);
}

You can see glob used in many other answers, e.g. here.

Community
  • 1
  • 1
Miki
  • 40,887
  • 13
  • 123
  • 202
1

sprintf_s(temp, 100, "%s%s", path, ent->d_name); -> sprintf_s(temp, 100, "%s/%s", path, ent->d_name);

(add slash)

This was trivially debugged by inspecting "temp" at the point of the failing stat.

Since dirent doesn't come with MSVC, maybe it's a bug in the dirent.h you pasted in.. but you do a %s/%s later with ent->d_name, and "path" comes from your hardcoded constant, so I think you made an error in porting from "code blocks"

zeromus
  • 1,648
  • 13
  • 14
  • I get the error: Debug Assertion failed! Expression : L "String not null terminated" after adding the slash. – Shrawan Sapre Mar 18 '16 at 18:20
  • Because you wrote "sizeof temp" which is 4. you meant to write 256. For people in your situation, I recommend you stop using C strings immediately and learn how to use std::strings. Look at miki's answer unless you have more specific needs. – zeromus Mar 18 '16 at 23:52
  • Thanks a lot for your help :) After including the slash and changing size of temp, I added slashes at the end of srcDirName and dstDirName. Then my display driver started crashing everytime I debugged. I uninstalled the driver and it works perfectly :) – Shrawan Sapre Mar 22 '16 at 04:28