基于Conv2D改进孪生网络实现图像差异检测的代码求助
基于Conv2D区域分割的图像差异检测与Bounding Box标注实现
核心思路
教授要求的核心是以图像小区域为单位做差异判断并定位,而非全局的相似度计算。我们采用全卷积孪生网络结构:
- 用Conv2D提取两幅图像的局部特征,保留空间位置信息
- 对对应位置的特征做差异计算,输出与输入图像尺寸对应的差异热力图
- 通过阈值筛选、连通域分析生成Bounding Box,精准标注差异区域
完整实现代码
import numpy as np import matplotlib.pyplot as plt import cv2 from tensorflow import keras from tensorflow.keras import layers # 加载并预处理图像 def load_and_preprocess(img_path): img = plt.imread(img_path) # 归一化到[0,1]区间 img = img.astype(np.float32) / 255.0 # 增加batch维度 return np.expand_dims(img, axis=0) img1 = load_and_preprocess('1-1.jpg') img2 = load_and_preprocess('1-2.jpg') input_shape = img1.shape[1:] # 获取(height, width, channels)格式的输入形状 # 构建基于区域的全卷积孪生网络 def build_patch_based_siamese(input_shape): # 共享特征提取网络(全卷积结构,不使用Flatten/Dense层保留空间信息) base_network = keras.Sequential([ layers.Conv2D(32, (3, 3), activation='relu', padding='same', input_shape=input_shape), layers.Conv2D(32, (3, 3), activation='relu', padding='same'), layers.MaxPooling2D((2, 2), padding='same'), layers.Conv2D(64, (3, 3), activation='relu', padding='same'), layers.Conv2D(64, (3, 3), activation='relu', padding='same'), layers.MaxPooling2D((2, 2), padding='same') ]) input_img1 = layers.Input(shape=input_shape) input_img2 = layers.Input(shape=input_shape) # 提取两幅图像的局部特征图 feat1 = base_network(input_img1) feat2 = base_network(input_img2) # 计算对应位置特征的L1距离 l1_dist = layers.Lambda(lambda x: keras.backend.abs(x[0] - x[1]))([feat1, feat2]) # 恢复特征图尺寸到接近原图像,输出单通道差异热力图 diff_map = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(l1_dist) diff_map = layers.UpSampling2D((2, 2))(diff_map) diff_map = layers.Conv2D(32, (3, 3), activation='relu', padding='same')(diff_map) diff_map = layers.UpSampling2D((2, 2))(diff_map) # sigmoid激活得到[0,1]区间的差异概率 output = layers.Conv2D(1, (1, 1), activation='sigmoid', padding='same')(diff_map) model = keras.Model(inputs=[input_img1, input_img2], outputs=output) model.compile(optimizer='adam', loss='binary_crossentropy') return model # 初始化模型 model = build_patch_based_siamese(input_shape) # 预测差异热力图(若有标注数据集,可先训练模型提升精度;无标注可直接用此逻辑测试) diff_heatmap = model.predict([img1, img2])[0, ..., 0] # 取出单通道热力图 # 从热力图生成Bounding Box def get_diff_bounding_boxes(heatmap, threshold=0.5, min_area=50): # 二值化热力图,筛选差异区域 binary_map = (heatmap > threshold).astype(np.uint8) * 255 # 连通域分析,提取有效差异区域 contours, _ = cv2.findContours(binary_map, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) boxes = [] for cnt in contours: area = cv2.contourArea(cnt) # 过滤小面积噪声区域 if area >= min_area: x, y, w, h = cv2.boundingRect(cnt) boxes.append((x, y, x+w, y+h)) return boxes # 获取差异区域的Bounding Box boxes = get_diff_bounding_boxes(diff_heatmap, threshold=0.6) # 可视化结果 plt.figure(figsize=(12, 6)) plt.subplot(131) plt.imshow(img1[0]) plt.title('图像1') plt.axis('off') plt.subplot(132) plt.imshow(img2[0]) plt.title('图像2') plt.axis('off') plt.subplot(133) plt.imshow(img2[0]) # 绘制Bounding Box for (x1, y1, x2, y2) in boxes: plt.gca().add_patch(plt.Rectangle((x1, y1), x2-x1, y2-y1, fill=False, edgecolor='red', linewidth=2)) plt.title('差异区域标注') plt.axis('off') plt.show()
关键部分说明
- 全卷积特征提取:移除原代码中
Flatten和Dense层,保留特征图的空间维度,确保每个特征点对应原图像的一个小区域 - 差异热力图输出:通过上采样将差异得分图恢复到接近原图像尺寸,每个像素点代表对应区域的差异概率
- Bounding Box生成:用OpenCV连通域分析筛选有效差异区域,过滤小面积噪声,生成精准的矩形标注框
- 训练提示:若需要提升模型精度,需准备带差异区域掩码的标注图像对,用二元交叉熵损失训练;无标注场景可采用自监督方式(如对图像做随机扰动生成正负样本)
内容的提问来源于stack exchange,提问作者Sajjad Taghinezhad
相关产品推荐
相关产品推荐

