OpenCV, Python, cv2 error: (-5:Bad argument) Empty training data was given.You'll need more than one sample to learn a model. in function 'train'

Question:

This is my code. I have a learning problem. Gives the error

error: (-5:Bad argument) Empty training data was given. You’ll need more than one sample to learn a model. in function ‘train’.

I can’t solve this problem. I can’t find an explanation on how to fix it? Where can I read about the solution to this problem? My pictures have size 200×200, format .pgm.

import os

import cv2
import numpy as np


def read_images(path, image_size):
    names = []
    training_images, training_labels = [], []
    label = 0
    for dirname, subdirnames, filenames in os.walk(path):
        for subdirname in subdirnames:
            names.append(subdirname)
            subject_path = os.path.join(dirname, subdirname)
            for filename in os.listdir(subject_path):
                img = cv2.imread(os.path.join(subject_path, filename),
                                 cv2.IMREAD_GRAYSCALE)
                if img is None:
                    # The file cannot be loaded as an image.
                    # Skip it.
                    continue
                img = cv2.resize(img, image_size)
                training_images.append(img)
                training_labels.append(label)
            label += 1
    training_images = np.asarray(training_images, np.uint8)
    training_labels = np.asarray(training_labels, np.int32)
    return names, training_images, training_labels


path_to_training_images = '/home/ace/OpenCV/cascades/A_M'# not properly. This is  = '/home/ace/OpenCV/cascades/'

training_image_size = (200, 200)
names, training_images, training_labels = read_images(path_to_training_images, training_image_size)

model = cv2.face.EigenFaceRecognizer_create()
model.train(training_images, training_labels)

face_cascade = cv2.CascadeClassifier('/haarcascade_frontalface_default.xml')

camera = cv2.VideoCapture(2)
while (cv2.waitKey(1) == -1):
    success, frame = camera.read()
    if success:
        faces = face_cascade.detectMultiScale(frame, 1.3, 5)
        for (x, y, w, h) in faces:
            cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
            gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
            roi_gray = gray[x:x+w, y:y+h]
            if roi_gray.size == 0:
                # The ROI is empty. Maybe the face is at the image edge.
                # Skip it.
                continue
            roi_gray = cv2.resize(roi_gray, training_image_size)
            label, confidence = model.predict(roi_gray)
            text = '%s, confidence=%.2f' % (names[label], confidence)
            cv2.putText(frame, text, (x, y - 20),
                        cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
        cv2.imshow('Face Recognition', frame)
Asked By: Jr Cord

||

Answers:

Although it seems a little bit odd that you use recursive walk-function and then seperately list the subdirectories, your read_images function works for me if I create a folder structure like this:

images/
  - sub1/
    - img1.png
    - img2.png
  - sub2/
    - img3.png
    - img4.png

The files are found and the return values are filled. Probably your folder structure differs from what your code expects.

You can try to debug your setup with some further print-statements like this:

def read_images(path, image_size):
    names = []
    training_images, training_labels = [], []
    label = 0
    for dirname, subdirnames, filenames in os.walk(path):
        print(f"dirname={dirname}")
        for subdirname in subdirnames:
            print(f"- subdirname={subdirname}")
            names.append(subdirname)
            subject_path = os.path.join(dirname, subdirname)
            for filename in os.listdir(subject_path):
                print(f"  - filename={filename}")
                img = cv2.imread(os.path.join(subject_path, filename),
                                 cv2.IMREAD_GRAYSCALE)
                if img is None:
                    # The file cannot be loaded as an image.
                    # Skip it.
                    continue
                img = cv2.resize(img, image_size)
                training_images.append(img)
                training_labels.append(label)
            label += 1
    training_images = np.asarray(training_images, np.uint8)
    training_labels = np.asarray(training_labels, np.int32)
    return names, training_images, training_labels

Please check the output of those prints and compare it with your folder structure. If this doesn’t help, please share the debug output and your folder structure with us. Please don’t share it as comment but by updating your question!

Answered By: Markus
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.