create custom ROI

53 views
Skip to first unread message

Dig...@gmx.de

unread,
Mar 30, 2019, 7:16:01 AM3/30/19
to pyqtgraph
Hi,

I'd like to create a custom ROI for content selection in an ImageItem. It should consist of two concentric CircleROIs with different handles:

- outer circle with 3 point handles to define the circle
and
- inner concentric circle with just a radius handle

The goal is to have a ring-like selection ROI. I guess the simplest solution would be to somehow combine two CircleROIs. It's just I don't know how to start...
Suggestions are very welcome! Thank you!

Patrick

unread,
Mar 31, 2019, 8:11:37 PM3/31/19
to pyqtgraph
Hi,

If you are only going to use this once, then making two ROIs and synchronising them might be easiest:

from PyQt5 import QtWidgets
import pyqtgraph as pg

class TestPlot(pg.GraphicsLayoutWidget):

   
def __init__(self):
       
super().__init__()

       
self.plot = self.addPlot()
       
self.plot.getViewBox().setAspectLocked(ratio=1.0)

       
self.ring1 = pg.CircleROI(pos=(0.25, 0.25), size=(0.5, 0.5))
       
self.ring2 = pg.CircleROI(pos=(0, 0), size=(0.1, 0.1))
       
self.plot.addItem(self.ring1, ignoreBounds=True)
       
self.plot.addItem(self.ring2, ignoreBounds=True)
       
self.ring1.sigRegionChanged.connect(self._ring1_changed)
       
self.ring2.sigRegionChanged.connect(self._ring2_changed)
       
self._ring1_changed()

   
def _ring1_changed(self):
       
if not self.ring2.pos() == self.ring1.pos() + self.ring1.size()/2 - self.ring2.size()/2:
           
self.ring2.setPos(self.ring1.pos() + self.ring1.size()/2 - self.ring2.size()/2)

   
def _ring2_changed(self):
       
if not self.ring1.pos() == self.ring2.pos() + self.ring1.size()/2 - self.ring2.size()/2:
           
self.ring1.setPos(self.ring2.pos() + self.ring2.size()/2 - self.ring1.size()/2)

def main():
   
import sys
    app
= QtWidgets.QApplication(sys.argv)
    mainwindow
= TestPlot()
    mainwindow
.show()
    sys
.exit(app.exec_())

if __name__ == '__main__':
    main
()

If you needed the getArrayRegion() functionality from EllipseROI, then you would need to implement something yourself. Copy the linked method, but make two masks and you should be able to do a mask = np.logical_and(mask1, mask2) on them.
If you actually wanted two EllipseROIs, then you'd need to modify the above code with similar logic to mirror the two size and angle parameters as well, but making your own ROI component might be easier.
If you want to do that, then start with copying the code from EllipseROI (extending ROI), but add an additional handle (addFreeHandle?) in the _addHandles() method, draw the second ellipse in the paint() method, modify getArrayRegion() as described above. You may be able to get away without modifying the shape() method.

Patrick

Dig...@gmx.de

unread,
Apr 1, 2019, 2:12:29 PM4/1/19
to pyqtgraph
Thank you, Patrick, that helped a lot!
Reply all
Reply to author
Forward
0 new messages