前言
图像配准是计算机视觉中的重要技术,特别是在多模态图像融合领域。本文将介绍如何使用 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. 加载图像
- 点击"加载红外目录",选择红外图像文件夹
- 点击"加载可见光目录",选择可见光图像文件夹
- 程序会自动匹配同名图像
4. 配准图像
方法一:键盘控制
- 方向键:移动图像
- W/E:水平缩放
- A/D:垂直缩放
- +/-:调整混合比例
方法二:鼠标控制
- 直接拖拽图像进行移动
- 使用右侧滑块调整参数
方法三:可视化按钮
- 点击方向按钮移动图像
5. 保存参数
- 按 S 键保存
- 或点击"保存参数"按钮
- 切换图像时自动保存
6. 批量导出
- 完成所有图像的配准
- 点击"批量导出"
- 选择输出目录
- 等待导出完成
项目亮点
- 游戏化操作体验:键盘控制流畅自然,学习成本低
- 自动参数管理:切换图像时自动保存,无需手动操作
- 批量处理能力:支持一键导出所有已配准图像
- 可视化控制:提供多种控制方式,满足不同用户习惯
- 独立可执行:打包为 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
如果觉得这篇文章对你有帮助,欢迎点赞、收藏和转发!有任何问题欢迎在评论区讨论。