You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenCV Python中cv2.train函数空训练数据报错求助

解决OpenCV EigenFaceRecognizer训练时“空训练数据”错误

错误信息

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

问题分析

这个错误说明training_images或training_labels为空,或仅包含单个样本/类别,导致模型无法完成训练。结合你的.pgm图片和代码逻辑,核心原因集中在:

  • 训练数据路径配置错误,未读取到任何图片
  • 图片读取逻辑存在漏洞,所有.pgm文件被跳过
  • 目录结构不符合代码预期,未正确遍历到子目录中的图片

解决步骤

1. 修正训练数据路径

你的代码中注释了正确路径,但实际使用的是错误路径,直接修改为正确路径:

# 替换原错误路径
path_to_training_images = '/home/ace/OpenCV/cascades/'

确保目录结构符合要求:每个子目录对应一个人脸类别,子目录下存放该类别的.pgm图片,示例结构:

cascades/
├── Alice/
│   ├── face1.pgm
│   ├── face2.pgm
├── Bob/
│   ├── face1.pgm
│   ├── face2.pgm

2. 调试图片读取过程

在read_images函数中添加调试输出,确认图片是否被成功读取:

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)
            print(f"读取类别: {subdirname},路径: {subject_path}")
            file_count = 0
            for filename in os.listdir(subject_path):
                img_path = os.path.join(subject_path, filename)
                print(f"尝试读取文件: {img_path}")
                img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
                if img is None:
                    print(f"读取失败,跳过该文件")
                    continue
                file_count += 1
                img = cv2.resize(img, image_size)
                training_images.append(img)
                training_labels.append(label)
            print(f"该类别成功读取 {file_count} 张图片")
            label += 1
    training_images = np.asarray(training_images, np.uint8)
    training_labels = np.asarray(training_labels, np.int32)
    print(f"总计读取 {len(training_images)} 张训练图片")
    return names, training_images, training_labels

运行后查看输出,若所有.pgm文件读取失败,需检查文件是否损坏,或尝试转换为.png格式测试。

3. 优化训练数据读取逻辑

原代码的遍历逻辑依赖严格的目录结构,改用更鲁棒的方式,直接识别所有.pgm文件并按目录分类:

def read_images(path, image_size):
    names = []
    training_images, training_labels = [], []
    label_map = {}
    current_label = 0

    # 遍历所有文件,仅处理.pgm格式
    for root, _, files in os.walk(path):
        for file in files:
            if not file.lower().endswith('.pgm'):
                continue
            # 获取当前文件所属类别(目录名)
            class_name = os.path.basename(root)
            # 为新类别分配标签
            if class_name not in label_map:
                label_map[class_name] = current_label
                names.append(class_name)
                current_label += 1
            # 读取并处理图片
            img_path = os.path.join(root, file)
            img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
            if img is None:
                continue
            img = cv2.resize(img, image_size)
            training_images.append(img)
            training_labels.append(label_map[class_name])
    
    training_images = np.asarray(training_images, np.uint8)
    training_labels = np.asarray(training_labels, np.int32)
    return names, training_images, training_labels

4. 训练前添加数据校验

在调用model.train前,先检查数据是否符合训练要求:

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

# 检查训练数据是否为空
if len(training_images) == 0:
    raise ValueError("未读取到任何训练图片,请检查路径和文件")
# 检查是否至少包含两个类别
if len(np.unique(training_labels)) < 2:
    raise ValueError("训练数据仅含一个类别,模型需至少两个类别才能训练")

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

修改后的完整代码

import os

import cv2
import numpy as np


def read_images(path, image_size):
    names = []
    training_images, training_labels = [], []
    label_map = {}
    current_label = 0

    # 遍历所有文件,仅处理.pgm格式
    for root, _, files in os.walk(path):
        for file in files:
            if not file.lower().endswith('.pgm'):
                continue
            # 获取当前文件所属类别(目录名)
            class_name = os.path.basename(root)
            # 为新类别分配标签
            if class_name not in label_map:
                label_map[class_name] = current_label
                names.append(class_name)
                current_label += 1
            # 读取并处理图片
            img_path = os.path.join(root, file)
            img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
            if img is None:
                continue
            img = cv2.resize(img, image_size)
            training_images.append(img)
            training_labels.append(label_map[class_name])
    
    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/'
training_image_size = (200, 200)
names, training_images, training_labels = read_images(path_to_training_images, training_image_size)

# 数据校验
if len(training_images) == 0:
    raise ValueError("未读取到任何训练图片,请检查路径和文件")
if len(np.unique(training_labels)) < 2:
    raise ValueError("训练数据仅含一个类别,模型需至少两个类别才能训练")

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:
                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)

内容的提问来源于stack exchange,提问作者Jr Cord

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 16:21:01