【基于 PyQt6 的红外与可见光图像配准工具开发实战】

前言

图像配准是计算机视觉中的重要技术,特别是在多模态图像融合领域。本文将介绍如何使用 Python 和 PyQt6 开发一个功能完善的红外与可见光图像配准工具,支持手动调整、批量处理和游戏化键盘控制。

项目背景

在实际应用中,我们经常需要将红外图像与可见光图像进行配准,以便进行图像融合、目标检测等后续处理。传统的配准工具往往操作复杂、学习成本高,因此我们开发了一个直观易用的配准工具。

技术栈

  • Python 3.11: 主要开发语言
  • PyQt6: GUI 框架
  • OpenCV: 图像处理
  • NumPy: 数值计算
  • PyInstaller: 打包工具

核心功能

1. 双模式配准

全局模式(Global Mode)
  • 使用统一的配准参数
  • 适用于批量处理
  • 快速预览效果
手动模式(Manual Mode)
  • 为每张图像单独调整参数
  • 精确控制配准效果
  • 参数自动保存

2. 游戏化键盘控制

这是本工具的一大亮点,采用类似游戏的键盘控制方式:

python 复制代码
def keyPressEvent(self, event):
    key = event.key()
    
    if key not in self.pressed_keys:
        self.pressed_keys.add(key)
        if len(self.pressed_keys) == 1:
            self.key_repeat_timer.start(self.key_repeat_interval)

特性

  • 方向键移动图像
  • W/E 控制水平缩放
  • A/D 控制垂直缩放
  • 支持长按连续移动
  • 支持多键同时按下(斜向移动)
  • 50ms 重复间隔,流畅如游戏

3. 可视化控制面板

除了键盘控制,还提供了可视化的方向键面板:

python 复制代码
keyboard_group = QGroupBox("移动控制")
keyboard_layout = QGridLayout()

self.key_up_btn = QPushButton("↑")
self.key_up_btn.pressed.connect(lambda: self.simulate_key_press(Qt.Key.Key_Up))
self.key_up_btn.released.connect(lambda: self.simulate_key_release(Qt.Key.Key_Up))

布局如下:

复制代码
  ↑
← ↓ →

4. 自动参数管理

自动保存
  • 切换图像时自动保存当前参数
  • 静默保存,不弹窗干扰
  • 参数保存到 results 目录
参数加载
  • 加载图像时自动读取已保存的参数
  • 自动恢复到上次配准状态
  • 支持 JSON 格式存储

5. 批量导出功能

python 复制代码
def export_images(self):
    # 统计已配准图像
    params_count = 0
    for ir_file in self.ir_files:
        json_file = self.result_dir / f"{ir_file.stem}.json"
        if json_file.exists():
            params_count += 1
    
    # 只导出已配准的图像
    for i, ir_file in enumerate(self.ir_files):
        json_file = self.result_dir / f"{ir_file.stem}.json"
        
        if not json_file.exists():
            skip_count += 1
            continue
        
        # 读取参数并应用
        with open(json_file, 'r', encoding='utf-8') as f:
            params = json.load(f)
            dx = params.get('dx', 0)
            dy = params.get('dy', 0)
            angle = params.get('angle', 0.0)
            scale_x = params.get('scale_x', 1.0)
            scale_y = params.get('scale_y', 1.0)

特性

  • 使用 results 目录下的参数
  • 只导出已配准的图像
  • 显示详细的导出统计

6. 长按快速切换

"下一张"按钮支持长按功能:

python 复制代码
def next_btn_pressed(self):
    self.next_btn_is_long_press = False
    self.next_btn_timer = QTimer()
    self.next_btn_timer.setSingleShot(True)
    self.next_btn_timer.timeout.connect(self.on_next_btn_long_press)
    self.next_btn_timer.start(500)  # 500ms 长按阈值

def on_next_btn_long_press(self):
    self.next_btn_is_long_press = True
    self.next_image()
    self.start_auto_switch()  # 每 300ms 自动切换

核心实现

1. 图像显示与变换

python 复制代码
class ImageCanvas(QWidget):
    def update_transformed_image(self):
        h, w = self.ir_image.shape[:2]
        center = (w // 2, h // 2)
        
        # 创建变换矩阵
        M = cv2.getRotationMatrix2D(center, self.angle, 1.0)
        M[0, 0] *= self.scale_x
        M[1, 1] *= self.scale_y
        M[0, 2] += self.dx
        M[1, 2] += self.dy
        
        # 应用变换
        self.transformed_image = cv2.warpAffine(
            self.ir_image, M, (w, h)
        )
        
        # 混合显示
        self.blended_image = cv2.addWeighted(
            self.vis_image, 1 - self.alpha,
            self.transformed_image, self.alpha, 0
        )
        
        self.update()

2. 信号与槽机制

python 复制代码
class ImageCanvas(QWidget):
    parameters_changed = pyqtSignal(int, int, float, float, float)
    
    def mouseMoveEvent(self, event):
        if self.dragging:
            dx = int(event.position().x() - self.last_pos.x())
            dy = int(event.position().y() - self.last_pos.y())
            
            self.dx += dx
            self.dy += dy
            self.last_pos = event.position()
            
            self.update_transformed_image()
            self.parameters_changed.emit(
                self.dx, self.dy, 
                self.scale_x, self.scale_y, 
                self.angle
            )

class ImageRegistrationWindow(QMainWindow):
    def __init__(self):
        self.image_canvas = ImageCanvas(self)
        self.image_canvas.parameters_changed.connect(
            self.update_parameter_labels
        )

3. 参数同步

python 复制代码
def update_parameter_labels(self, dx=None, dy=None, scale_x=None, 
                        scale_y=None, angle=None):
    if dx is None or dy is None or scale_x is None or scale_y is None or angle is None:
        dx, dy, scale_x, scale_y, angle, alpha = \
            self.image_canvas.get_parameters()
    
    self.dx_spin.setValue(dx)
    self.dy_spin.setValue(dy)
    self.scale_x_slider.setValue(int(scale_x * 100))
    self.scale_y_slider.setValue(int(scale_y * 100))
    self.angle_slider.setValue(int(angle))
    
    self.scale_x_label.setText(f"ScaleX: {scale_x:.2f}")
    self.scale_y_label.setText(f"ScaleY: {scale_y:.2f}")
    self.angle_label.setText(f"Angle: {angle:.1f}°")

打包发布

使用 PyInstaller 将程序打包为独立的 exe 文件:

spec 文件配置

python 复制代码
a = Analysis(
    ['image_registration_tool.py'],
    pathex=[],
    binaries=[],
    datas=[],
    hiddenimports=[
        'cv2',
        'numpy',
        'PyQt6',
        'PyQt6.QtCore',
        'PyQt6.QtGui',
        'PyQt6.QtWidgets',
    ],
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    win_no_prefer_redirects=False,
    win_private_assemblies=False,
    cipher=block_cipher,
    noarchive=False,
)

exe = EXE(
    pyz,
    a.scripts,
    a.binaries,
    a.zipfiles,
    a.datas,
    [],
    name='ImageRegistrationTool',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    console=False,  # 无控制台窗口
    icon=None,
)

打包命令

bash 复制代码
pyinstaller image_registration_tool.spec

打包后生成 dist/ImageRegistrationTool.exe,文件大小约 84 MB,包含所有依赖库,可在任何 Windows 机器上直接运行。

使用指南

1. 准备数据

创建以下目录结构:

复制代码
JZ_data/
├── images/          # 可见光图像
├── imagesIR/        # 红外图像
└── results/         # 配准参数(自动创建)

2. 运行程序

bash 复制代码
python image_registration_tool.py

或直接运行打包后的 exe:

bash 复制代码
ImageRegistrationTool.exe

3. 加载图像

  1. 点击"加载红外目录",选择红外图像文件夹
  2. 点击"加载可见光目录",选择可见光图像文件夹
  3. 程序会自动匹配同名图像

4. 配准图像

方法一:键盘控制
  • 方向键:移动图像
  • W/E:水平缩放
  • A/D:垂直缩放
  • +/-:调整混合比例
方法二:鼠标控制
  • 直接拖拽图像进行移动
  • 使用右侧滑块调整参数
方法三:可视化按钮
  • 点击方向按钮移动图像

5. 保存参数

  • 按 S 键保存
  • 或点击"保存参数"按钮
  • 切换图像时自动保存

6. 批量导出

  1. 完成所有图像的配准
  2. 点击"批量导出"
  3. 选择输出目录
  4. 等待导出完成

项目亮点

  1. 游戏化操作体验:键盘控制流畅自然,学习成本低
  2. 自动参数管理:切换图像时自动保存,无需手动操作
  3. 批量处理能力:支持一键导出所有已配准图像
  4. 可视化控制:提供多种控制方式,满足不同用户习惯
  5. 独立可执行:打包为 exe,无需 Python 环境

完整代码

完整代码已上传至 GitHub:

复制代码
https://github.com/xy200303/image_registration_tool.git

包含以下文件:

  • image_registration_tool.py - 主程序
  • requirements.txt - 依赖列表
  • image_registration_tool.spec - 打包配置
  • build.bat - 自动打包脚本
  • README.md - 项目说明

总结

本文介绍了一个基于 PyQt6 的红外与可见光图像配准工具的开发过程。通过游戏化的键盘控制、自动参数管理和批量处理功能,大大提升了配准效率。该工具已成功打包为独立 exe 文件,可在任何 Windows 机器上直接运行。

参考资料


作者 : xy200303
GitHub : https://github.com/xy200303/image_registration_tool.git
日期: 2026-01-23

如果觉得这篇文章对你有帮助,欢迎点赞、收藏和转发!有任何问题欢迎在评论区讨论。

相关推荐
Ethernet_Comm2 小时前
从 C 转向 C++ 的过程
c语言·开发语言·c++
GatiArt雷4 小时前
基于YOLOv8的轻量化AI目标检测在嵌入式设备上的落地实现
人工智能·yolo·目标检测
0思必得04 小时前
[Web自动化] 处理爬虫异常
运维·爬虫·python·selenium·自动化·web自动化
喵手4 小时前
Python爬虫零基础入门【第九章:实战项目教学·第17节】内容指纹去重:URL 变体/重复正文的识别!
爬虫·python·爬虫实战·python爬虫工程化实战·零基础python爬虫教学·内容指纹去重·url变体
Katecat996634 小时前
使用YOLOv26实现乌鸦鸽子麻雀等城市鸟类自动检测与分类
人工智能·yolo·分类
喵手4 小时前
Python爬虫零基础入门【第五章:数据保存与入库·第1节】先学最通用:CSV/JSONL 保存(可复现、可分享)!
爬虫·python·python爬虫实战·python爬虫工程化实战·python爬虫零基础入门·数据保存与入库·csv/jsonl
子夜江寒4 小时前
OpenCV 学习:图像拼接与答题卡识别的实现
python·opencv·学习·计算机视觉
bjxiaxueliang4 小时前
一文掌握Python Flask:HTTP微服务开发从入门到部署
python·http·flask
SunnyRivers5 小时前
Python 中的 HTTP 客户端:Requests、HTTPX 与 AIOHTTP 对比
python·httpx·requests·aiohttp·区别