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

使用OpenCV保存FLIR相机图像时,Matplotlib弹出保存图表弹窗问题

问题原因与解决方案

环境信息

  • OpenCV 4.7
  • Matplotlib 3.7.1
  • Spinnaker-Python 3.0.0.118
  • Python 3.10
  • Windows 10 x64

核心问题

同时用OpenCV显示热成像图、Matplotlib同步绘制直方图时,按s键调用cv2.imwrite()会触发Matplotlib的保存弹窗,最终保存的是直方图而非目标热成像图;移除Matplotlib后功能恢复正常。

原因分析

Matplotlib默认将s键绑定为“保存当前Figure”的快捷键,且当Matplotlib窗口处于焦点时,按键事件会被Matplotlib的事件循环捕获,而非OpenCV的cv2.waitKey()。这就导致按s时触发的是Matplotlib的保存逻辑,而非你编写的OpenCV保存代码。

解决方案

方案1:禁用Matplotlib的s快捷键

在创建Matplotlib Figure后,断开默认的按键处理逻辑,避免s被Matplotlib拦截:

fig = plt.figure(1)
fig.canvas.mpl_connect('close_event', handle_close)
# 禁用默认按键处理器,阻止's'触发保存弹窗
fig.canvas.mpl_disconnect(fig.canvas.manager.key_press_handler_id)

方案2:让OpenCV窗口始终置顶

强制OpenCV窗口保持在最上层,确保按键事件优先被OpenCV捕获:

cv2.imshow("FLIR", image_data)
# 设置窗口置顶
cv2.setWindowProperty("FLIR", cv2.WND_PROP_TOPMOST, 1)

方案3:优化Matplotlib绘图逻辑(推荐)

避免每次循环重绘整个Figure,改为更新已有直方图数据,既提升性能又减少事件冲突:

# 初始化阶段创建直方图对象
plt.ion()
fig, ax = plt.subplots(num=1)
fig.canvas.mpl_connect('close_event', handle_close)
fig.canvas.mpl_disconnect(fig.canvas.manager.key_press_handler_id)

# 提前获取第一帧数据初始化直方图
image_result = cam.GetNextImage(1000)
if not image_result.IsIncomplete():
    image_data = image_result.GetNDArray()
    image_data = cv2.rotate(image_data, cv2.ROTATE_90_COUNTERCLOCKWISE)
    image_data = cv2.flip(image_data, 1)
    count, bins = np.histogram(image_data.flatten())
    line, = ax.stairs(count, bins)
    image_result.Release()

# 循环内仅更新数据
count, bins = np.histogram(image_data.flatten())
line.set_data(bins[:-1], count)
ax.relim()
ax.autoscale_view()
plt.draw()
plt.pause(0.001)

完整修改示例

import PySpin
import cv2
import numpy as np
import matplotlib.pyplot as plt
import keyboard

def handle_close(event):
    global continue_recording
    continue_recording = False

continue_recording = True

# 假设已完成相机初始化(如枚举、选择、初始化相机)
# cam = ... 

cam.BeginAcquisition()
print('Acquiring images...')
print('Press enter to close the program..')

# 初始化Matplotlib并禁用默认's'快捷键
plt.ion()
fig, ax = plt.subplots(num=1)
fig.canvas.mpl_connect('close_event', handle_close)
fig.canvas.mpl_disconnect(fig.canvas.manager.key_press_handler_id)

acq_count = 0 

# 初始化直方图
image_result = cam.GetNextImage(1000)
if not image_result.IsIncomplete():
    image_data = image_result.GetNDArray()
    image_data = cv2.rotate(image_data, cv2.ROTATE_90_COUNTERCLOCKWISE)
    image_data = cv2.flip(image_data, 1)
    count, bins = np.histogram(image_data.flatten())
    line, = ax.stairs(count, bins)
    image_result.Release()

while(continue_recording):
    try:
        image_result = cam.GetNextImage(1000)

        if image_result.IsIncomplete():
            print('Image incomplete with image status %d ...' % image_result.GetImageStatus())

        else:                    
            image_data = image_result.GetNDArray()
            image_data = cv2.rotate(image_data, cv2.ROTATE_90_COUNTERCLOCKWISE)
            image_data = cv2.flip(image_data, 1)
                
            count, bins = np.histogram(image_data.flatten())
                        
            cv2.imshow("FLIR", image_data)
            cv2.setWindowProperty("FLIR", cv2.WND_PROP_TOPMOST, 1)
            
            # 更新直方图
            line.set_data(bins[:-1], count)
            ax.relim()
            ax.autoscale_view()
            plt.draw()
            plt.pause(0.001)
            
            key = cv2.waitKey(100) & 0xFF
            if key == ord('s'):
                f_name = f"test_{acq_count}.png"
                cv2.imwrite(f_name, image_data)
                acq_count += 1
                print(f"Saved image: {f_name}")
                        
            if keyboard.is_pressed('ENTER'):
                print('Program is closing...')
                cv2.destroyAllWindows()
                plt.close('all')             
                input('Done! Press Enter to exit...')
                continue_recording=False                        

            image_result.Release()

    except PySpin.SpinnakerException as ex:
        print('Error: %s' % ex)
        continue_recording = False

cam.EndAcquisition()
# cam.DeInit() # 按需添加相机销毁逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 10:07:45