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

如何在Matplotlib/Python中显示或保存多幅含多子图的图像

嘿,这事儿我熟!在Jupyter里处理这个需求特别顺手,我给你捋个清晰的流程,再附上可直接用的代码片段,你照着改改就能用啦~

首先咱们把整个流程拆成几块:预处理图像并存入units、提取指定卷积层的激活值、为每幅图像生成子图并展示/保存。

第一步:预处理图像并存储到units

先写个预处理函数,把你的图像做裁剪、归一化这些操作,然后把处理好的图像(还有方便后续处理的辅助信息)存到units里——units可以是个列表,每个元素用字典封装图像数据、文件名,这样后续操作更清晰。

import cv2
import numpy as np
from tensorflow.keras.applications import VGG16
from tensorflow.keras.models import Model
import matplotlib.pyplot as plt
import math
import os

# 示例:初始化模型(你可以换成自己的模型)
base_model = VGG16(weights='imagenet', include_top=False)
target_layer = base_model.get_layer('block3_conv1')  # 指定你要查看的卷积层
activation_model = Model(inputs=base_model.input, outputs=target_layer.output)

# 预处理函数(按需修改裁剪、归一化逻辑)
def preprocess_image(img_path, crop_size=(224, 224)):
    # 读取并转RGB
    img = cv2.imread(img_path)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    # 中心裁剪(换成你需要的裁剪方式即可)
    h, w = img.shape[:2]
    start_x = (w - crop_size[0]) // 2
    start_y = (h - crop_size[1]) // 2
    cropped_img = img[start_y:start_y+crop_size[1], start_x:start_x+crop_size[0]]
    # 归一化(适配VGG16,换成你模型的要求)
    preprocessed = cropped_img.astype('float32')
    preprocessed = np.expand_dims(preprocessed, axis=0)
    preprocessed /= 255.0
    return cropped_img, preprocessed

# 把图像存入units
units = []
# 替换成你的图像路径列表
image_paths = ['img1.jpg', 'img2.jpg', 'img3.jpg']
for path in image_paths:
    cropped, preprocessed = preprocess_image(path)
    units.append({
        'cropped_img': cropped,
        'preprocessed_input': preprocessed,
        'filename': path.split('/')[-1].split('.')[0]  # 提取文件名用于保存
    })

第二步:为每幅图像生成激活子图并处理

接下来遍历units里的每一个图像,提取激活值,动态计算子图布局(不管激活通道有多少,都能自动排版),然后在Jupyter里显示,或者批量保存到指定目录。

# 配置参数
save_images = True
save_dir = './activation_plots/'
os.makedirs(save_dir, exist_ok=True)  # 自动创建保存目录

# 遍历处理每幅图像
for unit in units:
    # 提取激活值(去掉batch维度)
    activations = activation_model.predict(unit['preprocessed_input'])[0]
    num_channels = activations.shape[-1]
    
    # 计算子图网格大小:尽量排成方正的网格
    grid_size = math.ceil(math.sqrt(num_channels))
    fig, axes = plt.subplots(grid_size, grid_size, figsize=(15, 15))
    fig.suptitle(f'Activations for {unit["filename"]} - Layer: {target_layer.name}', fontsize=16)
    
    # 逐个绘制通道激活图
    for i in range(num_channels):
        row = i // grid_size
        col = i % grid_size
        ax = axes[row, col]
        ax.imshow(activations[:, :, i], cmap='viridis')
        ax.axis('off')
        ax.set_title(f'Channel {i+1}')
    
    # 隐藏多余的空白子图
    for i in range(num_channels, grid_size*grid_size):
        row = i // grid_size
        col = i % grid_size
        axes[row, col].axis('off')
    
    # Jupyter内显示图像
    plt.tight_layout()
    plt.show()
    
    # 保存图像到指定目录
    if save_images:
        save_path = os.path.join(save_dir, f'{unit["filename"]}_activations.png')
        fig.savefig(save_path, bbox_inches='tight', dpi=100)
    plt.close(fig)  # 关闭画布释放内存,处理大量图像时必加

关键细节说明

  • 动态布局适配:用math.ceil(math.sqrt(num_channels))自动计算网格大小,不管你有多少个激活通道,都能生成整齐的子图布局。
  • Jupyter显示优化:先运行%matplotlib inline(经典Notebook)或%matplotlib widget(交互式),图像会直接显示在单元格里。
  • 内存管理:处理完每幅图像后用plt.close(fig)关闭画布,避免处理大量图像时内存溢出。
  • 自定义调整:你可以随意替换预处理逻辑、模型、目标层,还有子图的颜色映射(cmap参数)、画布大小这些,完全适配你的需求。

这样一来,不管你输入多少幅图像,都能自动为每幅生成对应的激活子图,既可以实时查看,也能批量保存到指定目录~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:41:38