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

基于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()

关键部分说明

  1. 全卷积特征提取:移除原代码中Flatten和Dense层,保留特征图的空间维度,确保每个特征点对应原图像的一个小区域
  2. 差异热力图输出:通过上采样将差异得分图恢复到接近原图像尺寸,每个像素点代表对应区域的差异概率
  3. Bounding Box生成:用OpenCV连通域分析筛选有效差异区域,过滤小面积噪声,生成精准的矩形标注框
  4. 训练提示:若需要提升模型精度,需准备带差异区域掩码的标注图像对,用二元交叉熵损失训练;无标注场景可采用自监督方式(如对图像做随机扰动生成正负样本)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 11:55:55