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显示效果

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)
效果图

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 模块进行图像变换 |
浙公网安备 33010602011771号