CNN简单的图像操作

1该实践代码设计思路

  • 加载一张真实的图片。
  • 将其转换为 NumPy 数组以进行处理。
  • 对每个像素及其颜色通道执行一些操作(例如增加亮度)。
  • 使用 Pillow 显示原始图像和处理后的图像。

1.1相关代码

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt


def increase_brightness(image_array, factor=1.5):
    """
    增加图像亮度

    :param image_array: 输入的图像数组 (numpy array)
    :param factor: 增加亮度的因子,默认为1.5
    :return: 处理后的图像数组
    """
    # 确保所有像素值在 [0, 255] 范围内
    processed_array = np.clip(image_array * factor, 0, 255).astype(np.uint8)
    return processed_array


def display_images(original, processed):
    """
    并排显示原始图像和处理后的图像

    :param original: 原始图像 (PIL Image)
    :param processed: 处理后的图像 (PIL Image)
    """
    fig, ax = plt.subplots(1, 2, figsize=(12, 6))

    ax[0].imshow(original)
    ax[0].set_title('Original Image')
    ax[0].axis('off')

    ax[1].imshow(processed)
    ax[1].set_title('Processed Image')
    ax[1].axis('off')

    plt.show()


# 加载图像
input_image_path = '../static/star.png'  # 替换为你的图片路径
original_image = Image.open(input_image_path)

# 将图像转换为 NumPy 数组
image_array = np.array(original_image)

print("原始图像形状:", image_array.shape)

# 处理图像
processed_array = increase_brightness(image_array)

# 将处理后的 NumPy 数组转换回 PIL 图像
processed_image = Image.fromarray(processed_array)

# 显示原始图像和处理后的图像
display_images(original_image, processed_image)

1.2显示效果

image

2CNN 提取特征图

2.1设计思路

使用 TensorFlow/Keras 构建 CNN 模型,并可视化 CNN 提取的特征图(feature maps) 的完整流程。
主要功能:

  • 加载并预处理图像
  • 构建一个简单的 CNN 模型
  • 显示原始图像
  • 可视化 CNN 各层的特征图(feature maps)
加载图像
   ↓
预处理图像(缩放、归一化、加 batch)
   ↓
构建 CNN 模型
   ↓
显示原始图像
   ↓
构建子模型提取特征图
   ↓
标准化并拼接 feature maps
   ↓
显示各层的特征图

2.2整体代码

import tensorflow as tf
from tensorflow.keras import layers, models
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt


# 加载并预处理图像
def preprocess_image(image_path, target_size=(64, 64)):
    img = Image.open(image_path)
    img = img.resize(target_size)
    img_array = np.array(img) / 255.0  # 归一化到 [0, 1]
    return np.expand_dims(img_array, axis=0)  # 增加批次维度


# 构建一个简单的 CNN 模型
def build_simple_cnn(input_shape=(64, 64, 3)):
    model = models.Sequential()
    model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=input_shape))
    model.add(layers.MaxPooling2D((2, 2)))
    model.add(layers.Conv2D(64, (3, 3), activation='relu'))
    model.add(layers.MaxPooling2D((2, 2)))
    model.add(layers.Conv2D(64, (3, 3), activation='relu'))
    model.add(layers.Flatten())
    model.add(layers.Dense(64, activation='relu'))
    model.add(layers.Dense(10))  # 假设我们有10个类别

    model.compile(optimizer='adam',
                  loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
                  metrics=['accuracy'])
    return model


# 显示原始和经过 CNN 处理后的特征图
def display_feature_maps(model, image):
    layer_outputs = [layer.output for layer in model.layers[:4]]  # 获取前四层的输出
    activation_model = tf.keras.models.Model(inputs=model.input, outputs=layer_outputs)

    activations = activation_model.predict(image)

    images_per_row = 16
    for layer_name, layer_activation in zip([layer.name for layer in model.layers[:4]], activations):
        n_features = layer_activation.shape[-1]  # 特征图的数量
        size = layer_activation.shape[1]  # 特征图的大小
        n_cols = n_features // images_per_row  # 特征图显示的列数
        display_grid = np.zeros((size * n_cols, images_per_row * size))

        for col in range(n_cols):
            for row in range(images_per_row):
                channel_image = layer_activation[0, :, :, col * images_per_row + row]
                channel_image -= channel_image.mean()  # 处理以使其看起来美观
                channel_image /= channel_image.std()
                channel_image *= 64
                channel_image += 128
                channel_image = np.clip(channel_image, 0, 255).astype('uint8')
                display_grid[col * size: (col + 1) * size,
                row * size: (row + 1) * size] = channel_image

        scale = 1. / size
        plt.figure(figsize=(scale * display_grid.shape[1],
                            scale * display_grid.shape[0]))
        plt.title(layer_name)
        plt.grid(False)
        plt.imshow(display_grid, aspect='auto', cmap='viridis')


# 主函数
if __name__ == "__main__":
    input_image_path = '../static/star.png'  # 替换为你的图片路径
    image = preprocess_image(input_image_path)

    model = build_simple_cnn()

    # 显示原始图像
    plt.figure(figsize=(4, 4))
    plt.imshow(np.squeeze(image))
    plt.title("Original Image")
    plt.axis('off')
    plt.show()

    # 显示特征图
    display_feature_maps(model, image)

效果图
image

2.3代码详细理解

2.3.1导入模块

import tensorflow as tf
from tensorflow.keras import layers, models
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
模块 功能
tensorflow 深度学习框架
layers, models Keras 提供的神经网络层和模型构建工具
PIL.Image 图像处理库,用于加载和缩放图像
numpy 数值计算库,用于处理图像为数组
matplotlib.pyplot 可视化库,用于显示图像

2.3.2图像预处理函数

# 加载并预处理图像
def preprocess_image(image_path, target_size=(64, 64)):
    img = Image.open(image_path)
    img = img.resize(target_size)
    img_array = np.array(img) / 255.0  # 归一化到 [0, 1]
    return np.expand_dims(img_array, axis=0)  # 增加批次维度

作用:

加载图像 → 缩放 → 转换为数组 → 归一化 → 添加 batch 维度
其中:np.expand_dims(..., axis=0):添加 batch 维度,变为 (1, 64, 64, 3),符合模型输入要求

2.3.3构建 CNN 模型

# 构建一个简单的 CNN 模型
def build_simple_cnn(input_shape=(64, 64, 3)):
    model = models.Sequential()
    model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=input_shape))
    model.add(layers.MaxPooling2D((2, 2)))
    model.add(layers.Conv2D(64, (3, 3), activation='relu'))
    model.add(layers.MaxPooling2D((2, 2)))
    model.add(layers.Conv2D(64, (3, 3), activation='relu'))
    model.add(layers.Flatten())
    model.add(layers.Dense(64, activation='relu'))
    model.add(layers.Dense(10))  # 假设我们有10个类别

    model.compile(optimizer='adam',
                  loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
                  metrics=['accuracy'])
    return model

模型结构

层级 类型 参数说明
第1层 Conv2D(32, (3,3), 'relu') 卷积层,32个滤波器,大小3x3,激活函数ReLU
第2层 MaxPooling2D((2,2)) 最大池化层,降低空间维度
第3层 Conv2D(64, (3,3), 'relu') 第二个卷积层,64个滤波器
第4层 MaxPooling2D((2,2)) 第二个池化层
第5层 Conv2D(64, (3,3), 'relu') 第三个卷积层
第6层 Flatten() 展平为一维向量,准备输入全连接层
第7层 Dense(64, 'relu') 全连接层,64个神经元
第8层 Dense(10) 输出层,10个类别(无 softmax)

编译配置

  • optimizer='adam':使用 Adam 优化器
  • loss=...:使用稀疏交叉熵损失(适用于整数标签)
  • metrics=['accuracy']:评估准确率

Conv2D 卷积层

model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=input_shape))

作用:用于提取图像的局部特征(如边缘、纹理等)。卷积核大小为 (3, 3),输出通道数为 32。
激活函数:ReLU(Rectified Linear Unit),引入非线性,增加模型表达能力。

MaxPooling2D 最大池化层

model.add(layers.MaxPooling2D((2, 2)))

作用:减少特征图的空间维度(宽高减半),降低计算复杂度和过拟合风险。同时有助于保留最重要的特征信息。

第三个 Conv2D 层

model.add(layers.Con

作用:在更深一层中继续提取特征,但不再进行池化操作。这有助于捕捉更高层次的特征表示。

Flatten 展平层

model.add(layers.Flatten())

作用:将多维特征图展平成一维向量,以便作为全连接层的输入。

Dense 全连接层

作用:引入全连接层,允许神经元之间完全连接,进一步处理特征并分类。这里使用了 64 个神经元,并应用 ReLU 激活函数。

2.3.4可视化特征图函数

# 显示原始和经过 CNN 处理后的特征图
def display_feature_maps(model, image):
    layer_outputs = [layer.output for layer in model.layers[:4]]  # 获取前四层的输出
    activation_model = tf.keras.models.Model(inputs=model.input, outputs=layer_outputs)

    activations = activation_model.predict(image)

    images_per_row = 16
    for layer_name, layer_activation in zip([layer.name for layer in model.layers[:4]], activations):
        n_features = layer_activation.shape[-1]  # 特征图的数量
        size = layer_activation.shape[1]  # 特征图的大小
        n_cols = n_features // images_per_row  # 特征图显示的列数
        display_grid = np.zeros((size * n_cols, images_per_row * size))

        for col in range(n_cols):
            for row in range(images_per_row):
                channel_image = layer_activation[0, :, :, col * images_per_row + row]
                channel_image -= channel_image.mean()  # 处理以使其看起来美观
                channel_image /= channel_image.std()
                channel_image *= 64
                channel_image += 128
                channel_image = np.clip(channel_image, 0, 255).astype('uint8')
                display_grid[col * size: (col + 1) * size,
                row * size: (row + 1) * size] = channel_image

        scale = 1. / size
        plt.figure(figsize=(scale * display_grid.shape[1],
                            scale * display_grid.shape[0]))
        plt.title(layer_name)
        plt.grid(False)
        plt.imshow(display_grid, aspect='auto', cmap='viridis')

作用

  • 构建一个子模型,提取指定层的输出
  • 对每层的 feature map 进行标准化和可视化

详细解释

  • layer_outputs = [...]:获取模型前四层的输出(通常是卷积层 + 池化层)
  • activation_model = Model(...):构建一个新模型,输入是原模型的输入,输出是各层的激活值
  • activations = activation_model.predict(image):对输入图像进行前向传播,得到每层的 feature maps
  • display_grid:创建一个大图,用于显示所有 feature map
  • for col, row in ...:遍历所有 feature map,标准化后放入 display_grid
  • plt.imshow(display_grid):显示拼接好的特征图

特征图处理步骤

  • 提取每个 channel 的 feature map
  • 去均值、标准化
  • 增强对比度
  • 限制在 [0,255] 范围
  • 转换为图像格式
  • 拼接到 display_grid 中

后续

添加模型训练 使用 model.fit() 和 CIFAR-10 数据集
使用预训练模型 如 VGG16, ResNet50
保存特征图图像 使用 plt.savefig() 保存为文件
使用彩色图像增强 使用 tf.image 模块进行图像变换
posted @ 2025-07-18 15:56  13149942875  阅读(14)  评论(0)    收藏  举报