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

多视图分类:自定义NumPy加载器调图像至224x224适配VGG16

解决纯NumPy下64x64图像缩放至224x224适配VGG16的问题

问题原因分析

关于Try(1)的报错

  • x_batch[i,j]是x_batch的数组视图,而非拥有独立内存的数组,调用.resize()方法时,由于视图不具备数据所有权,无法直接修改形状,因此抛出cannot resize this array: it does not own its data错误。
  • 单张图像的目标形状应为(224,224,3),而非(1,224,224,3),多了一个不必要的batch维度。

关于Try(2)的图像失真

np.resize()的逻辑是通过重复或截断数组元素来匹配目标形状,完全忽略图像的空间结构,本质是对数组元素的重新排列,而非图像的插值缩放,因此必然导致图像严重失真。

纯NumPy实现图像双线性插值缩放

要实现符合视觉效果的图像缩放,需采用双线性插值(VGG16预训练时默认使用的缩放方式),以下是纯NumPy实现的双线性插值函数:

def bilinear_resize(image, target_size):
    # image: (H, W, 3) 输入图像数组
    # target_size: (new_H, new_W) 目标尺寸
    h, w, c = image.shape
    new_h, new_w = target_size

    # 计算坐标缩放比例
    x_scale = (w - 1) / (new_w - 1) if new_w > 1 else 0
    y_scale = (h - 1) / (new_h - 1) if new_h > 1 else 0

    # 生成目标坐标网格
    new_x = np.linspace(0, w-1, new_w)
    new_y = np.linspace(0, h-1, new_h)
    x_grid, y_grid = np.meshgrid(new_x, new_y)

    # 计算四个邻点的坐标
    x0 = np.floor(x_grid).astype(int)
    x1 = np.minimum(x0 + 1, w - 1)
    y0 = np.floor(y_grid).astype(int)
    y1 = np.minimum(y0 + 1, h - 1)

    # 提取邻点的像素值
    pixel00 = image[y0, x0, :]
    pixel01 = image[y0, x1, :]
    pixel10 = image[y1, x0, :]
    pixel11 = image[y1, x1, :]

    # 计算插值权重
    dx = x_grid - x0
    dy = y_grid - y0

    # 执行双线性插值计算
    interpolated = (1 - dx) * (1 - dy) * pixel00 + dx * (1 - dy) * pixel01 + \
                   (1 - dx) * dy * pixel10 + dx * dy * pixel11

    return interpolated.astype(image.dtype)

修改数据加载器的正确方式

调整数据加载器逻辑,在读取图像后直接用双线性插值缩放至224x224,同时初始化对应尺寸的x_batch:

def data_loader(dataframe, classDict, basePath, batch_size=16): 
    target_size = (224, 224)
    while True:
        # 初始化目标尺寸的batch数组
        x_batch = np.zeros((batch_size, 4, *target_size, 3))    
        y_batch = np.zeros((batch_size, 20))              
        
        for i in range(batch_size):
            rndNumber = np.random.randint(len(dataframe))        
            *images, class_id = dataframe.iloc[rndNumber]
                               
            for j in range(4):
                # 读取图像并归一化
                img = plt.imread(os.path.join(basePath, images[j])) / 255.
                # 双线性插值缩放至目标尺寸
                resized_img = bilinear_resize(img, target_size)
                x_batch[i,j] = resized_img
                
            class_id = classDict[class_id]
            y_batch[i, class_id] = 1.0                             
    
        yield {
            'image1': x_batch[:, 0], 
            'image2': x_batch[:, 1], 
            'image3': x_batch[:, 2], 
            'image4': x_batch[:, 3]
        }, {'class_out': y_batch}

# 测试数据加载器
example, lbl= next(data_loader(df_train, classDictTrain, basePath))
print(example['image1'].shape)  # 预期输出:(16, 224, 224, 3)
print(lbl['class_out'].shape)   # 预期输出:(16, 20)

关键说明

  • 双线性插值会保留图像的空间结构,缩放后的图像不会失真,符合VGG16预训练时的输入要求。
  • 提前初始化目标尺寸的x_batch,避免后续形状调整的额外性能开销。
  • 所有操作均基于纯NumPy实现,未使用keras或OpenCV的内置图像加载/缩放方法,满足需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 16:09:14