我的目标是编写一个无法旋转的椭圆 ROI。考虑以下从 PyQtGraph 示例之一修改而来的代码:
import numpy as np
import cv2
import pyqtgraph as pg
from PyQt5 import QtGui
import numpy.ma as ma
from PyQt5.QtWidgets import QMessageBox
pg.setConfigOptions(imageAxisOrder='row-major')
## Create image to display
image = cv2.imread('panda.jpg')
def picturetranspose(picture):
shape = picture.shape
result = np.empty((shape[1],shape[0],shape[2]),dtype= np.uint8)
for i in range(0,3):
result[:,:,i] = np.transpose(picture[:,:,i])
return result
arr = np.rot90(picturetranspose(image))
app = pg.mkQApp("ROI Examples")
w = pg.GraphicsLayoutWidget(show=True, size=(1000,800), border=True)
w.setWindowTitle('pyqtgraph example: ROI Examples')
w1 = w.addLayout(row=0, col=0)
v1a = w1.addViewBox(row=1, col=0, lockAspect = True)
v1a.setLimits(minXRange = arr.shape[0]//10, minYRange = arr.shape[1]//10, maxXRange = 5*arr.shape[0], maxYRange = 5*arr.shape[1])
img1a = pg.ImageItem(arr)
v1a.addItem(img1a)
rois = []
x=pg.EllipseROI([60, 10], [30, 20], pen=pg.mkPen('b', width=5),rotatable = False)
x.removeHandle(0)
rois.append(x)
for roi in rois:
roi.sigRegionChanged.connect(img1a.setImage(arr))
v1a.addItem(roi)
img1a.setImage(arr)
这里的图像“panda.jpg”由以下方式给出:https://drive.google.com/drive/folders/1ejY0CjfEwS6SGS2qe_uRX2JvlruMKvPX?usp=sharing。运行代码并移动 ROI 将给出:
通过单击浅蓝色方形手柄,可以更改 ROI 的大小。由于我设置了
rotatable = False
,ROI无法旋转,点击圆形手柄也不会旋转ROI。
但是,
x.removeHandle(0)
行应该删除浅蓝色圆形手柄,以便它根本不会显示在屏幕上。这是一个错误吗?我错过了什么?
创建 QGraphicsItem 时,它不会立即添加到场景中,并且在该时间范围内,一些与场景相关的方面会被“存储”,直到该项目实际放入场景中。其中一些属性非常明显(例如项目位置),但其他属性则不然。其中之一是添加 child 项目。当“主要”项目添加到场景中时,它的所有子项(以及孙子项、曾孙项等)都会随之添加。
这就是创建 ROI 时发生的情况:它的句柄是在其
__init__
中创建的(请参阅源),但是 removeHandle()
仅当 ROI 实际上具有 scene()
时才会从场景中删除句柄.
请记住,PyQt(和 PySide)是 Qt 的绑定,这意味着我们始终使用围绕 C++ 对象的 Python 包装器。即使删除了对 python 对象的最后一个引用,实际上也只删除了 python 对象,但如果该对象是 C++ 对象的包装器并且该对象有父对象,则 actual 对象毕竟不会被删除。
虽然 pyqtgraph 从其内部列表中删除句柄,但表示句柄的 C++ 对象仍然作为 ROI 的子对象存在,因此,当 ROI 添加到场景时,句柄仍然存在。
一个可能的解决方案是在 ROI 添加到场景后删除手柄:
for roi in rois:
roi.sigRegionChanged.connect(img1a.setImage(arr))
v1a.addItem(roi)
roi.removeHandle(0)
这是有效的,因为removeHandle
仅在该项目存在场景时删除句柄,这样子项目就可以从场景中实际删除。请注意,根据消息来源,
EllipseROI
添加了两个手柄:旋转和缩放。您可能想删除所有这些:
for roi in rois:
roi.sigRegionChanged.connect(img1a.setImage(arr))
v1a.addItem(roi)
while roi.handles:
roi.removeHandle(0)
我建议您在 pyqtgraph 存储库上提交一份关于此问题的报告,在他们这边解决它应该非常容易。
pg.ROI(
# arguments
handlePen='#0000',
handleHoverPen='#0000',
# arguments
)
然后然后按照您的描述禁用手柄。这使得手柄完全透明(即不可见)
希望对遇到这个问题的人有所帮助!