Pyqtgraph запрет линии покидать пределы изображения

Есть изображение, на котором рисуется линия. Эту линию можно перемещать по сцене и изменять размеры ее, я же хочу запретить линии покидать границы изображения, а также убрать маркеры по краям, с помощью которых можно изменять размер линии и ее положение. Для этого я решил изменить атрибуты класса LineSegmentROI. Насчет скрытия маркеров, я нашел только как их можно скрыть после того как мы перенесли линию, но не нашел как их можно в принципе скрыть, чтобы не было вообще возможности менять размеры линии. А насчет запрета линии выходить за пределы изображения ничего дельного не нашел.

import numpy as np
from pyqtgraph.Qt import QtGui
import pyqtgraph as pg

app = pg.mkQApp("Data Slicing Example")


class DrawLine(pg.LineSegmentROI):
    """
       Графический объект для визуализации области рисования
       - Линия.
    """
    def __init__(self, positions=(None, None), pos=None, color='r'):

        pg.LineSegmentROI.__init__(self, positions=positions, pos=pos, pen=color)

    def setSelected(self, s):
        """
        Скрываем маркеры по краям линии при переносе линии
        """
        QtGui.QGraphicsItem.setSelected(self, s)
        for h in self.handles:
            h['item'].hide()


win = QtGui.QMainWindow()
win.resize(800, 800)
win.setWindowTitle('pyqtgraph example: DataSlicing')
cw = QtGui.QWidget()
win.setCentralWidget(cw)
l = QtGui.QGridLayout()
cw.setLayout(l)
imv1 = pg.ImageView()
imv2 = pg.ImageView()
l.addWidget(imv1, 0, 0)
l.addWidget(imv2, 1, 0)
win.show()

roi = DrawLine([[10, 64], [120, 64]])

imv1.addItem(roi)

x1 = np.linspace(-30, 10, 128)[:, np.newaxis, np.newaxis]
x2 = np.linspace(-20, 20, 128)[:, np.newaxis, np.newaxis]
y = np.linspace(-30, 10, 128)[np.newaxis, :, np.newaxis]
z = np.linspace(-20, 20, 128)[np.newaxis, np.newaxis, :]
d1 = np.sqrt(x1 ** 2 + y ** 2 + z ** 2)
d2 = 2 * np.sqrt(x1[::-1] ** 2 + y ** 2 + z ** 2)
d3 = 4 * np.sqrt(x2 ** 2 + y[:, ::-1] ** 2 + z ** 2)
data = (np.sin(d1) / d1 ** 2) + (np.sin(d2) / d2 ** 2) + (np.sin(d3) / d3 ** 2)


def update():
    global data, imv1, imv2
    d2 = roi.getArrayRegion(data, imv1.imageItem, axes=(1, 2))
    imv2.setImage(d2)


roi.sigRegionChanged.connect(update)

imv1.setImage(data)
imv1.setHistogramRange(-0.01, 0.01)
imv1.setLevels(-0.003, 0.003)

update()

if __name__ == '__main__':
    pg.mkQApp().exec_()

Ответы (1 шт):

Автор решения: Xybyyn

Может кому будет полезно, переопределил класс для рисования линии с возможностью переноса ее. Запретил движение по горизонтали и за пределы изображения. С помощью переопределения функции getHandles удалось скрыть маркеры по краям линии.

import numpy as np
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
from pyqtgraph import Point

app = pg.mkQApp("Data Slicing Example")


class DrawLine(pg.LineSegmentROI):
    """
       Графический объект для визуализации области рисования
       - Линия.
    """
    def __init__(self, positions=(None, None), pos=None, color='r'):

        pg.LineSegmentROI.__init__(self, positions=positions, pos=pos, pen=color)

    def getHandles(self):
        """
        Скрываем маркеры по краям линий
        """
        for el in self.handles:
            el['item'].hide()
        return []

    def mouseDragEvent(self, ev):
        """
        Ограничение передвижение в области изображения
        """
        if ev.isStart():
            if ev.button() == QtCore.Qt.LeftButton:
                if self.translatable:
                    self.isMoving = True
                    self.preMoveState = self.getState()
                    self.cursorOffset = self.pos() - self.mapToParent(ev.buttonDownPos())
                    self.sigRegionChangeStarted.emit(self)
                    ev.accept()
                else:
                    ev.ignore()
        elif ev.isFinish():
            if self.translatable:
                if self.isMoving:
                    self.stateChangeFinished()
                self.isMoving = False
            return
        if self.translatable and self.isMoving and ev.buttons() == QtCore.Qt.LeftButton:
            snap = True if (ev.modifiers() & QtCore.Qt.ControlModifier) else None

            newPos = self.mapToParent(ev.pos()) + self.cursorOffset

            pos = Point(0, self.pos()[1])
            npos = Point(0, newPos[1])
            position_line = self.check_position(npos[1])

            if position_line:
                self.translate(npos - pos, snap=snap, finish=False)

    def check_position(self, pos):
        """
        Проверяем чтобы линия не вышла за пределы изображения
        """
        if -65 <= pos <= 65:
            return True
        return False


win = QtGui.QMainWindow()
win.resize(800, 800)
win.setWindowTitle('pyqtgraph example: DataSlicing')
cw = QtGui.QWidget()
win.setCentralWidget(cw)
l = QtGui.QGridLayout()
cw.setLayout(l)
imv1 = pg.ImageView()
imv2 = pg.ImageView()
l.addWidget(imv1, 0, 0)
l.addWidget(imv2, 1, 0)
win.show()

roi = DrawLine([[0, 64], [128, 64]])

imv1.addItem(roi)

x1 = np.linspace(-30, 10, 128)[:, np.newaxis, np.newaxis]
x2 = np.linspace(-20, 20, 128)[:, np.newaxis, np.newaxis]
y = np.linspace(-30, 10, 128)[np.newaxis, :, np.newaxis]
z = np.linspace(-20, 20, 128)[np.newaxis, np.newaxis, :]
d1 = np.sqrt(x1 ** 2 + y ** 2 + z ** 2)
d2 = 2 * np.sqrt(x1[::-1] ** 2 + y ** 2 + z ** 2)
d3 = 4 * np.sqrt(x2 ** 2 + y[:, ::-1] ** 2 + z ** 2)
data = (np.sin(d1) / d1 ** 2) + (np.sin(d2) / d2 ** 2) + (np.sin(d3) / d3 ** 2)


def update():
    global data, imv1, imv2
    d2 = roi.getArrayRegion(data, imv1.imageItem, axes=(1, 2))
    imv2.setImage(d2)


roi.sigRegionChanged.connect(update)

imv1.setImage(data)
imv1.setHistogramRange(-0.01, 0.01)
imv1.setLevels(-0.003, 0.003)

update()

if __name__ == '__main__':
    pg.mkQApp().exec_()
→ Ссылка