PyQtGraph十字ROI手柄文本镜像问题修复求助
解决CrossHairROI文本镜像与旋转倒置问题
核心问题分析
文本镜像源于ROI的场景变换矩阵包含Y轴方向的翻转(pyqtgraph坐标系Y轴向下),而旋转时文本会跟随ROI的旋转角度同步转动,导致出现倒置情况。
具体修复方案
1. 修复镜像问题
放弃直接复用ROI的场景变换绘制文本,改为基于手柄的全局坐标计算文本位置,手动抵消坐标系Y轴翻转的影响。
2. 确保旋转时文本可读
ROI旋转时,让文本的旋转角度与ROI的旋转角度反向抵消,始终保持水平正立状态。
修改后的完整代码
import pyqtgraph as pg from pyqtgraph.Qt import QtCore, QtGui import numpy as np class CrossHairROI(pg.ROI): def __init__(self, pos, size, **kwargs): super().__init__(pos, size, **kwargs) self.addScaleHandle([1, 0.5], [0, 0.5]) self.addScaleHandle([0, 0.5], [1, 0.5]) self.addScaleHandle([0.5, 1], [0.5, 0]) self.addScaleHandle([0.5, 0], [0.5, 1]) self.addRotateHandle([1, 1], [0.5, 0.5]) def paint(self, p, opt, widget): super().paint(p, opt, widget) p.save() # 隔离文本绘制状态,避免影响ROI其他绘图 # 获取ROI核心参数 pos = self.pos() size = self.size() angle = self.angle() # ROI旋转角度(弧度) radius_x = size[0] / 2 radius_y = size[1] / 2 # 四个手柄的局部坐标 handle_local_pos = [ (pos.x() + radius_x, pos.y()), # 右 (pos.x() - radius_x, pos.y()), # 左 (pos.x(), pos.y() + radius_y), # 下 (pos.x(), pos.y() - radius_y) # 上 ] # 文本偏移(避免与手柄重叠) text_offsets = [ QtCore.QPointF(10, 0), # 右文本右移 QtCore.QPointF(-50, 0), # 左文本左移 QtCore.QPointF(0, 20), # 下文本下移 QtCore.QPointF(0, -20) # 上文本上移 ] # 文本内容 text_contents = [ f"Width: {2*radius_x:.1f}", f"Width: {2*radius_x:.1f}", f"Height: {2*radius_y:.1f}", f"Height: {2*radius_y:.1f}" ] # 逐个绘制文本 for local_pos, offset, text in zip(handle_local_pos, text_offsets, text_contents): # 转换为全局场景坐标 scene_pos = self.mapToScene(QtCore.QPointF(local_pos)) text_pos = scene_pos + offset # 重置变换,清除ROI的镜像/旋转影响 p.resetTransform() # 反向旋转,抵消ROI的旋转角度,保持文本水平 p.rotate(-pg.radians(angle)) # 绘制文本 p.drawText(text_pos, text) p.restore() # 恢复绘图状态 # 测试代码 if __name__ == '__main__': app = QtGui.QApplication([]) win = pg.GraphicsLayoutWidget() win.show() view = win.addViewBox() view.setAspectLocked(True) img = pg.ImageItem(pg.gaussianFilter(np.random.normal(size=(100,100)), sigma=2)) view.addItem(img) roi = CrossHairROI(pos=(50,50), size=(40,60)) view.addItem(roi) app.exec_()
关键修改点说明
- 用
self.mapToScene()将手柄局部坐标转为全局坐标,避开ROI自身变换矩阵导致的镜像。 - 绘制文本前调用
p.resetTransform()清除之前的变换,确保文本绘制不受ROI变换干扰。 - 通过
p.rotate(-pg.radians(angle))反向抵消ROI的旋转角度,让文本始终保持水平可读。 - 用
painter.save()和restore()隔离文本绘制状态,避免影响ROI其他绘图逻辑。
内容的提问来源于stack exchange,提问作者温泽海
相关产品推荐
相关产品推荐

