PyQtGraph ROI RemoveHandle 不去除椭圆ROI的圆形手柄

PyQtGraph ROI RemoveHandle Does Not Remove the Circular Handle for the Ellipse ROI

我的objective是码出一个不能旋转的椭圆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 时,它不会立即添加到场景中,并且在该时间范围内一些 scene-related 方面被“存储”,直到该项目实际放入场景中。其中一些属性非常明显(例如项目位置),但其他属性则不然。其中之一是添加 child 项目。当一个“主要”项目被添加到场景中时,它的所有子项(和孙子,great-grandchildren,等等)都会随之添加。

这是创建 ROI 时发生的情况:它的句柄是在其 __init__ 中创建的(参见 sources), but removeHandle() 如果 ROI 实际上有 [=14],则仅从场景中删除句柄=].

请记住,PyQt(和 PySide)是 绑定 到 Qt,这意味着我们总是使用 python 围绕 C++ 对象的包装器。即使删除了对 python 对象的最后一个引用,实际上也只删除了 python 对象,但是如果该对象是 C++ 对象的包装器并且该对象有父对象,则 实际对象终究没有删除
虽然 pyqtgraph 从其内部列表中删除句柄,但表示句柄的 C++ 对象仍然作为 ROI 的子对象存在,因此,当将 ROI 添加到场景中时,句柄仍然存在。

一个可能的解决方案是在将 ROI 添加到场景后移除手柄:

for roi in rois:
    roi.sigRegionChanged.connect(img1a.setImage(arr))
    v1a.addItem(roi)
    roi.removeHandle(0)

之所以可行,是因为 removeHandle 仅在项目存在场景时才删除句柄,这样子项目才能真正从场景中删除。

请注意,根据消息来源,EllipseROI 添加了 两个 句柄:rotatescale 。您可能想要删除所有这些:

for roi in rois:
    roi.sigRegionChanged.connect(img1a.setImage(arr))
    v1a.addItem(roi)
    while roi.handles:
        roi.removeHandle(0)

我建议你向 pyqtgraph repository 报告这件事,在他们这边解决应该很容易。