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

matplotlib显示数组存储图像时mplcursors悬停失效及首行传感器角点存储方法

问题排查与修复方案

交互功能失效的核心原因

原代码存在多处硬伤,直接导致悬停交互完全失效:

  • 基础逻辑错误:list.append() 为原地修改方法,无返回值。原代码中 sel = cropped_list.append(img.iloc[700:1250,450:1550:]) 的写法,实际得到的sel为None,后续图像渲染、角点检测全是基于空对象运行,画布坐标体系完全错乱。正确逻辑为先完成图像裁剪赋值,再将结果存入列表:
    sel = img.iloc[700:1250, 450:1550]
    cropped_list.append(sel)
    
  • mplcursors高频失效坑:未保留cursor实例的对象引用。matplotlib的事件回调采用弱引用绑定,如果生成的cursor对象没有被有效变量持有,会被Python垃圾回收自动销毁,绘图完成后交互逻辑直接被清理。必须将cursor返回值赋值给生命周期覆盖绘图全程的变量。
  • 语法遗漏:原代码末尾plt.show( 未补全右括号,会直接触发语法错误,代码根本无法运行到交互绑定的步骤。
  • 环境兼容问题:若使用非交互后端(如部分默认纯脚本后端、notebook inline渲染后端),悬停弹窗功能会被限制,需要切换到可交互后端(如TkAgg、Qt5Agg)才能正常触发。

修复后的交互实现参考:

from nptdms import TdmsFile as td
from matplotlib import pyplot as plt
import numpy as np
import mplcursors
from skimage.feature import corner_harris, corner_peaks

file = 'sample.tdms'
with td.open(file) as tdms_file:
    img = tdms_file.as_dataframe()

# 正确完成图像裁剪
cropped_list = []
sel = img.iloc[700:1250, 450:1550]
cropped_list.append(sel)
coords = corner_peaks(corner_harris(sel), min_distance=10, threshold_rel=0.02)

fig, ax = plt.subplots()
ax.imshow(sel, cmap='gray')
plotted_points = ax.plot(coords[:, 1], coords[:, 0], color='cyan', marker='o', linestyle='None', markersize=2)
# 关键:保留cursor实例引用,避免被GC回收
cursor = mplcursors.cursor(plotted_points, hover=True)
# 自定义悬停提示,直接显示真实像素坐标
@cursor.connect("add")
def show_coord(sel):
    sel.annotation.set_text(f"像素x: {sel.target[0]:.0f}\n像素y: {sel.target[1]:.0f}")
plt.show()

无交互状态下提取第一行角点的实现

目标图像为规则阵列排布的矩形传感器结构,角点坐标本身有明确的行列分层特征,完全不需要鼠标交互辅助定位,直接通过数值分布筛选即可:

  • 明确坐标规则:corner_peaks 返回的coords为(y, x)格式(y对应图像从上到下的行号,x对应从左到右的列号),因图像坐标系原点在左上角,第一行传感器对应的角点,整体y坐标为全局最小的一组值。
  • 筛选逻辑:
    • 提取所有角点的y坐标并升序排序
    • 计算相邻y值的差值,定位第一行和第二行传感器之间的间隔跳变
    • 以跳变位置为边界,筛选出所有y值低于边界的点,即为第一行的角点

参考实现代码:

# 排序所有角点的y坐标
sorted_y = np.sort(coords[:, 0])
# 计算相邻y值的间隔,找出行与行之间的明显跳变
y_diff = np.diff(sorted_y)
# 以最大间隔的中点作为第一行和第二行的边界
row_bound = sorted_y[np.argmax(y_diff)] + np.max(y_diff) / 2
# 筛选所有位于边界上方的角点,即为第一行对应坐标
first_row_coords = coords[coords[:, 0] < row_bound]

如果阵列行间距固定,可直接通过y值范围筛选:取全局最小y值为基准,以固定行高为阈值,筛选y值在基准到阈值区间内的所有角点即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.26 11:57:03