1. 背景与目标
图像模糊是摄影中的常见问题,主要由相机抖动(手抖)或目标运动导致。模糊图像不仅影响观感,更直接降低下游检测、识别等视觉任务的准确率。传统去模糊算法(维纳滤波、Richardson-Lucy)需已知模糊核,但实际场景中模糊核未知且空间变化,传统方法难以实用。
基于 GAN 的去模糊方案通过对抗训练学习模糊到清晰的映射,无需已知模糊核,在真实场景中效果显著。骁龙X2 Elite平台的 80 TOPS NPU 可承载 DeblurGAN 模型推理,为端侧实时去模糊提供了硬件基础。
本系列分三篇完成端侧去模糊系统的部署:
- 第一篇(本篇):DeblurGAN 模型端侧部署与运动模糊去除
- 第二篇:多尺度特征融合与自适应模糊核估计
- 第三篇:视频去抖动与实时管线效果对比
2. 系统整体架构
各层职责如下:
- 输入层:接收模糊图像,执行预处理(resize、归一化)
- 推理层:DeblurGAN 生成器在 NPU 上执行前向推理,输出去模糊图像
- 后处理层:色彩校正与锐化增强
- 输出层:输出去模糊结果
3. 开发环境配置
3.1 硬件与系统确认
| 项目 | 规格 |
|---|---|
| SoC | 骁龙X2 Elite(18 核,最高 5.0 GHz) |
| 内存 | 32 GB LPDDR5X |
| NPU | Hexagon NPU,80 TOPS |
3.2 依赖安装
pip install qai-hub-client torch opencv-python pillow numpy4. DeblurGAN 模型选型与转换
4.1 模型选型
| 模型 | 参数量 | INT8 量化体积 | NPU 推理延迟 | 去模糊 PSNR | 选型结论 |
|---|---|---|---|---|---|
| DeblurGAN | 11.4M | ~6 MB | 28 ms | 24.8 dB | 速度与精度均衡 |
| DeblurGAN-v2 | 8.3M | ~4.5 MB | 22 ms | 26.3 dB | 精度最优 |
| MIMO-Net | 3.2M | ~1.8 MB | 12 ms | 23.1 dB | 速度最优 |
| NAFNet-Go | 5.1M | ~2.8 MB | 18 ms | 25.7 dB | 较均衡 |
本篇选用DeblurGAN-v2。该模型基于 MobileNet 主干,参数量较 DeblurGAN-v1 减少 27%,PSNR 反而提升 1.5 dB,NPU 推理 22 ms,是精度与速度的最优平衡点。
4.2 模型导出与 QNN 转换
importtorch model=DeblurGANv2Generator()model.eval()dummy_input=torch.randn(1,3,256,256)torch.onnx.export(model,dummy_input,"deblurgan_v2.onnx",input_names=["blur_image"],output_names=["sharp_image"],dynamic_axes={"blur_image":{0:"batch"}},opset_version=14)qnn-onnx-converter--input_model deblurgan_v2.onnx ^--output_path deblurgan_v2.cpp^--input_list deblur_input_list.txt ^--quantization_per_channel ^--enable_htp_f16 qnn-context-binary-generator--model deblurgan_v2.cpp^--backend libQnnHtp.so ^--output deblurgan_v2.binDeblurGAN-v2 的 MobileNet 主干全部为标准卷积与深度可分离卷积,QNN 转换无报错。量化采用 INT8 权重 + FP16 激活。
5. NPU 推理引擎封装
importqnnimportnumpyasnpimportcv2classDeblurProcessor:def__init__(self,model_path="deblurgan_v2.bin"):self.model=qnn.Model(model_path,backend="libQnnHtp.dll")self.model.load()self.input_size=(256,256)defdeblur(self,image):"""图像去模糊"""original_h,original_w=image.shape[:2]# 预处理resized=cv2.resize(image,self.input_size)normalized=resized.astype(np.float32)/255.0input_tensor=np.transpose(normalized,(2,0,1))[np.newaxis,:]# NPU 推理output=self.model.execute({"blur_image":input_tensor})sharp=output["sharp_image"]# 后处理sharp=np.transpose(sharp[0],(1,2,0))sharp=np.clip(sharp*255,0,255).astype(np.uint8)sharp=cv2.resize(sharp,(original_w,original_h))# 色彩校正与锐化sharp=self._postprocess(sharp,image)returnsharpdef_postprocess(self,sharp,original):"""后处理:色彩校正与锐化"""# 色彩校正:保留原图色调sharp_lab=cv2.cvtColor(sharp,cv2.COLOR_BGR2LAB)original_lab=cv2.cvtColor(original,cv2.COLOR_BGR2LAB)sharp_lab[:,:,1]=original_lab[:,:,1]*0.3+sharp_lab[:,:,1]*0.7sharp_lab[:,:,2]=original_lab[:,:,2]*0.3+sharp_lab[:,:,2]*0.7corrected=cv2.cvtColor(sharp_lab,cv2.COLOR_LAB2BGR)# 轻微锐化kernel=np.array([[-1,-1,-1],[-1,5,-1],[-1,-1,-1]])sharpened=cv2.filter2D(corrected,-1,kernel)returnsharpened deblur_processor=DeblurProcessor()6. 端到端验证
defdeblur_image(image_path,output_path):image=cv2.imread(image_path)sharp=deblur_processor.deblur(image)cv2.imwrite(output_path,sharp)print(f"去模糊完成:{output_path}")deblur_image("motion_blur_sample.jpg","deblurred_sample.jpg")实测:对手抖导致的运动模糊照片执行去模糊,处理后文字与边缘清晰度恢复显著。
7. 性能实测
| 指标 | CPU 推理(Oryon) | NPU 推理(Hexagon) |
|---|---|---|
| 模型加载 | 2.1 s | 1.8 s |
| 单帧去模糊延迟 | 95 ms | 22 ms |
| 连续 100 帧延迟 | 9.5 s | 2.2 s |
| 功耗 | 14 W | 8 W |
NPU 推理 22 ms,较 CPU 提升 4.3 倍,功耗降低 43%。
8. 去模糊质量评估
在 GoPro 数据集上评估:
| 指标 | 模糊图像 | 去模糊后 | 提升 |
|---|---|---|---|
| PSNR | 16.2 dB | 26.3 dB | +10.1 dB |
| SSIM | 0.45 | 0.78 | +0.33 |
| 边缘锐度 | 0.21 | 0.72 | +243% |
| 文字可读率 | 35% | 89% | +54% |
PSNR 提升 10.1 dB,文字可读率从 35% 提升至 89%,去模糊效果显著。
9. 本篇小结
本篇在骁龙X2 Elite平台上完成了 DeblurGAN-v2 模型的端侧部署与运动模糊去除,主要成果如下:
- 完成 DeblurGAN-v2 的 QNN 转换与 INT8 量化部署,NPU 推理延迟 22 ms
- PSNR 从 16.2 dB 提升至 26.3 dB,文字可读率从 35% 提升至 89%
- NPU 功耗 8 W,连续推理无降频
当前系统已能去除均匀运动模糊,但对空间变化的非均匀模糊效果有限。第二篇将引入多尺度特征融合与自适应模糊核估计,处理更复杂的模糊模式。
系列索引:(一)DeblurGAN模型端侧部署与运动模糊去除 · (二)多尺度特征融合与自适应模糊核估计 · (三)视频去抖动与实时管线效果对比