解决Python图像预处理中数组形状不均的ValueError问题
修复猫狗分类数据预处理的ValueError问题
错误现象
执行prep_and_load_data()函数时触发如下错误:
ValueError: setting an array element with a sequence. The requested array has an inhomogeneous shape after 2 dimensions. The detected shape was (100, 2) + inhomogeneous part.
相关代码
data_prep.py
import math import os from random import shuffle import constants as CONST import cv2 import pickle import glob import numpy as np def get_size_statistics(): heights = [] widths = [] img_count = 0 DIR = CONST.TRAIN_DIR2 for img in os.listdir(CONST.TRAIN_DIR2): path = os.path.join(DIR, img) data = cv2.imread(path) heights.append(data.shape[0]) widths.append(data.shape[1]) img_count += 1 avg_height = sum(heights) / len(heights) avg_width = sum(widths) / len(widths) print("Average Height: " + str(avg_height)) print("Max Height: " + str(max(heights))) print("Min Height: " + str(min(heights))) print('\n') print("Average Width: " + str(avg_width)) print("Max Width: " + str(max(widths))) print("Min Width: " + str(min(widths))) def label_img(name): word_label = name.split('.')[0] label = CONST.LABEL_MAP[word_label] label_arr = np.zeros(2) label_arr[label] = 1 return label_arr def prep_and_load_data(): DIR2 = CONST.TRAIN_DIR2 data = [] image_paths = os.listdir(DIR2) shuffle(image_paths) count = 0 max_images = 100 for img_path in image_paths: if not img_path.endswith(('.jpg', '.jpeg', '.png')): print(f"Skipping non-image file or directory: {img_path}") continue label = label_img(img_path) path = os.path.join(DIR2, img_path) image = cv2.imread(path) image = cv2.resize(image, (CONST.IMG_SIZE, CONST.IMG_SIZE)) image = image.astype('float') / 255.0 data.append([image, label]) count += 1 if count == max_images: print(f"Reached the limit of {max_images} images.") break shuffle(data) print(len(data)) print('done') print(np.array(data)) return data if __name__ == "__main__": prep_and_load_data()
constants.py
TRAIN_DIR2 = 'Code\\dogs-vs-cats\\train\\train' TEST_DIR2 = 'Code\\dogs-vs-cats\\test1\\test1' CAT_LBL = 0 DOG_LBL = 1 CAT = 'cat' DOG = 'dog' LABEL_MAP = { CAT: CAT_LBL, DOG: DOG_LBL } DATA_SIZE = 18_000 IMG_SIZE = 110 SPLIT_RATIO = 0.8
错误原因
直接将包含[图像数组, 标签数组]的列表转换为numpy数组时,图像是三维数组((110,110,3)),标签是一维数组((2,)),numpy无法将这种嵌套的异构结构转换为规则的多维数组,从而触发形状不兼容的错误。
修复方法
1. 拆分特征与标签为独立数组
修改prep_and_load_data()函数的末尾逻辑,将图像和标签分别提取并转换为规则的numpy数组,替代直接转换整个列表的操作:
def prep_and_load_data(): DIR2 = CONST.TRAIN_DIR2 data = [] image_paths = os.listdir(DIR2) shuffle(image_paths) count = 0 max_images = 100 for img_path in image_paths: if not img_path.endswith(('.jpg', '.jpeg', '.png')): print(f"Skipping non-image file or directory: {img_path}") continue label = label_img(img_path) path = os.path.join(DIR2, img_path) image = cv2.imread(path) # 新增:检查图像是否读取成功 if image is None: print(f"无法读取图像文件: {path}") continue image = cv2.resize(image, (CONST.IMG_SIZE, CONST.IMG_SIZE)) image = image.astype('float') / 255.0 data.append([image, label]) count += 1 if count == max_images: print(f"Reached the limit of {max_images} images.") break shuffle(data) print(f"有效图像数量: {len(data)}") # 拆分图像和标签为独立数组 X = np.array([item[0] for item in data]) y = np.array([item[1] for item in data]) print(f"图像数据形状: {X.shape}") print(f"标签数据形状: {y.shape}") return X, y
2. 调用函数时的适配
如果后续代码依赖原函数返回的列表结构,需要调整调用逻辑,接收拆分后的两个数组:
if __name__ == "__main__": images, labels = prep_and_load_data()
额外说明
新增的图像读取检查可以避免因文件损坏、路径错误导致的cv2.imread返回None,进而引发后续resize操作的崩溃问题,提升代码健壮性。
内容的提问来源于stack exchange,提问作者Luis Cruz
相关产品推荐
相关产品推荐

