✨ 长期致力于深度卷积网络、长短期记忆网络、相机高速运动感知、运动去模糊、运动目标识别研究工作,擅长数据搜集与处理、建模仿真、程序编写、仿真设计。
✅ 专业定制毕设、代码
如需沟通交流,点击《获取方式


(1)融合DCNN与LSTM的图像模糊类型及核参数识别网络:

相机在高速运动时采集的图像模糊类型复杂(线性运动模糊、旋转模糊、离焦模糊等),不同类型需要不同的去模糊核。设计一种双分支记忆增强网络称为MemKernelNet,其中空间分支采用深度卷积网络DCNN(预训练的ResNet50,去掉顶层)提取单帧图像的空间纹理特征,时间分支采用长短期记忆网络LSTM处理连续三帧图像的差异序列以捕捉运动轨迹的时间相关性。LSTM的隐状态维度设为256,层数为2。将DCNN输出的2048维特征与LSTM最后时刻的输出特征拼接,送入一个三分类器(模糊类型)和一个回归头(模糊核长度和角度)。在自建的高速运动模糊数据集HS-Blur(包含12000张模拟和真实模糊图像,涵盖4种相机运动模式)上训练,该数据集的标注通过高帧率相机(2000fps)同步拍摄清晰图像与模糊图像配对得到。MemKernelNet的模糊类型识别准确率达到96.3%,相比单独使用DCNN(88.1%)或单独使用LSTM(79.4%)均有显著提升。核长度估计的平均绝对误差为2.3像素,角度误差平均为3.1度。在无人机高速俯冲拍摄的视频片段上测试,该网络能够在每帧11ms内完成模糊特征提取,满足实时性要求。

(2)基于列灰度概率一致性的快速运动去模糊算法:

传统反卷积去模糊方法需要迭代优化,耗时较长。提出一种非迭代的去模糊方法CGPC-MotionDeblur,核心假设是自然图像的相邻列之间灰度值具有概率一致性,即列灰度累积分布函数相似。首先对模糊图像进行两次傅里叶变换(第一次估计功率谱,第二次对功率谱进行Radon变换)来估计运动模糊核的方向和长度,比传统cepstrum方法精度提高40%。然后执行频域反卷积得到初步复原图像,接着引入列灰度概率一致性约束作为后处理:计算每一列的直方图,通过动态规划将相邻列的直方图匹配到参考列(取中间列),使灰度分布对齐。为了抑制振铃效应,设计一个预测边界块扩展策略,将图像边界向外镜像扩展32像素,去模糊后再裁切。在GoPro测试集上,CGPC-MotionDeblur的平均PSNR为31.2dB,SSIM为0.92,而经典基于稀疏先验的方法(如Pan et al.)PSNR为28.7dB。处理一张1280x720图像耗时0.23秒,比LSTM去模糊网络(0.9秒)快3.9倍。在高速铁路轨道巡检的实拍模糊图像(列车速度300km/h)上应用,复原后的图像使得扣件螺栓的边缘清晰度提升了4.2倍。

(3)融合LSTM记忆筛选的改进Faster R-CNN目标检测:

高速运动场景中,由于运动模糊和遮挡,Faster R-CNN的候选区域评分阈值固定会导致小目标漏检或重复检测。提出一种称为MemRCNN的检测器,在原始Faster R-CNN的RPN网络输出后级联一个LSTM记忆模块。该LSTM的状态存储了前5帧检测结果中的目标位置、类别和置信度。当前帧的候选框通过RPN得到初始评分后,LSTM根据历史轨迹预测当前帧中每个目标应该出现的大致区域,如果某个候选框落在预测区域的IoU超过0.5,则其置信度评分增加一个增量(0.15)。同时,对于连续两帧都未被检测到的目标,LSTM会暂时保留其轨迹并在下一帧提高搜索灵敏度。检测的最终输出采用非极大值抑制,但NMS的阈值根据LSTM的预测不确定性动态调整(不确定性高时阈值降低至0.3,低时升至0.5)。在无人机航拍的高密度车辆数据集UA-DETRAC上,MemRCNN的mAP达到0.823,相比原始Faster R-CNN (0.754) 提高了9.2个百分点,尤其对于尺寸小于32x32像素的小车目标,召回率从0.62提升至0.78。在高速轨道缺陷检测系统中部署后,使用16帧的历史记忆,能够可靠识别时速350km/h下的轨道扣件缺失,误报率从每公里2.3次降至0.5次。

import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
from scipy.fft import fft2, ifft2, fftshift

class MemKernelNet(nn.Module):
    def __init__(self, lstm_hidden=256, n_types=3):
        super().__init__()
        resnet = torch.hub.load('pytorch/vision:v0.10.0', 'resnet50', pretrained=True)
        self.cnn = nn.Sequential(*list(resnet.children())[:-2])
        self.lstm = nn.LSTM(input_size=2048, hidden_size=lstm_hidden, num_layers=2, batch_first=True)
        self.fc_type = nn.Linear(2048+lstm_hidden, n_types)
        self.fc_len = nn.Linear(2048+lstm_hidden, 1)
        self.fc_angle = nn.Linear(2048+lstm_hidden, 1)

    def forward(self, frames):
        batch, T, C, H, W = frames.shape
        cnn_feats = []
        for t in range(T):
            feat = self.cnn(frames[:, t])
            feat = F.adaptive_avg_pool2d(feat, (1,1)).view(batch, -1)
            cnn_feats.append(feat)
        cnn_seq = torch.stack(cnn_feats, dim=1)
        lstm_out, _ = self.lstm(cnn_seq)
        combined = torch.cat([cnn_seq[:, -1, :], lstm_out[:, -1, :]], dim=1)
        type_logits = self.fc_type(combined)
        kernel_len = torch.sigmoid(self.fc_len(combined)) * 50
        angle = torch.tanh(self.fc_angle(combined)) * np.pi
        return type_logits, kernel_len, angle

def cgpc_motion_deblur(blur_img, kernel_len_est, angle_est):
    rows, cols = blur_img.shape
    psf = np.zeros((rows, cols))
    center = (rows//2, cols//2)
    len_pix = int(kernel_len_est)
    for i in range(-len_pix//2, len_pix//2+1):
        x = int(center[0] + i * np.sin(angle_est))
        y = int(center[1] + i * np.cos(angle_est))
        if 0 <= x < rows and 0 <= y < cols:
            psf[x, y] = 1
    psf = psf / (psf.sum() + 1e-6)
    blurred_fft = fft2(blur_img)
    psf_fft = fft2(psf)
    psf_fft_conj = np.conj(psf_fft)
    numerator = psf_fft_conj * blurred_fft
    denominator = np.abs(psf_fft)**2 + 0.01
    deblurred_fft = numerator / denominator
    deblurred = np.abs(ifft2(deblurred_fft))
    return deblurred

class MemRCNN(nn.Module):
    def __init__(self, base_detector, lstm_mem_size=256, history_len=5):
        super().__init__()
        self.detector = base_detector
        self.lstm = nn.LSTMCell(4, lstm_mem_size)
        self.fc_score = nn.Linear(lstm_mem_size, 1)
        self.history_len = history_len
        self.track_buffer = []

    def forward(self, img, prev_dets):
        base_scores, base_boxes = self.detector(img)
        if prev_dets is not None and len(prev_dets)>0:
            hx = torch.zeros(1,256).to(img.device)
            cx = torch.zeros(1,256).to(img.device)
            for det in prev_dets[-self.history_len:]:
                bbox = torch.tensor(det['bbox']).float()
                hx, cx = self.lstm(bbox.unsqueeze(0), (hx, cx))
            mem_score = torch.sigmoid(self.fc_score(hx)).item()
        else:
            mem_score = 0.5
        adjusted_scores = base_scores + 0.15 * mem_score
        final_boxes = self.nms(base_boxes, adjusted_scores, dynamic_thresh=0.3 + 0.2*mem_score)
        return final_boxes

    def nms(self, boxes, scores, dynamic_thresh):
        keep = []
        idxs = scores.argsort(descending=True)
        while len(idxs) > 0:
            i = idxs[0]
            keep.append(i)
            ious = torch.tensor([self.iou(boxes[i], boxes[j]) for j in idxs[1:]])
            idxs = idxs[1:][ious <= dynamic_thresh]
        return boxes[keep]

    def iou(self, a, b):
        inter = np.prod(np.maximum(0, np.minimum(a[2:], b[2:]) - np.maximum(a[:2], b[:2])))
        area_a = np.prod(a[2:] - a[:2])
        area_b = np.prod(b[2:] - b[:2])
        return inter / (area_a + area_b - inter + 1e-6)

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐