ROI binary mask

698 views
Skip to first unread message

L. Smash

unread,
May 12, 2015, 8:30:26 AM5/12/15
to pyqt...@googlegroups.com
Hi,

once again a simple question from a new guy to python & pyqtgraph. Basically it is the same as here but more specified: I need a mask of the selected PolyLineROI, meaning a numpy array with the same shape of the image and that has 1 (or True) for all the inside the ROI points and 0 (or False) for all the points outside the ROI. I found this answer:

The latest PolyLineROI has a getArrayRegion method that does the following:
   1. Slice out the rectangular region of the image covered by the bounding rectangle of the ROI
   2. Create a black image and draw the shape of the ROI in white to the image
   3. Convert the image to a float-valued mask
   4. Return the sliced data multiplied by the mask. 

Depending on your intention, you may be able to use this method as-is or construct a modified version that gives you the mask over the entire image.

The getArrayRegion method works really great but how can I modify this method so that I get the desired binary mask?

PS: Nice efforts on pyqtgraph, it helps me very much!

Lars

Julien Lhermitte

unread,
May 14, 2015, 8:07:17 AM5/14/15
to pyqt...@googlegroups.com
Hi L Smash,
     I also had the same difficulty. Here is my workaround from this topic :

            cols,rows = self.data.shape
            m
= np.mgrid[:cols,:rows]
            possx
= m[0,:,:]# make the x pos array
            possy
= m[1,:,:]# make the y pos array
            possx
.shape = cols,rows
            possy
.shape = cols,rows
            mpossx
= self.roi.getArrayRegion(possx,self.img).astype(int)
            mpossx
= mpossx[np.nonzero(mpossx)]#get the x pos from ROI
            mpossy
= self.roi.getArrayRegion(possy,self.img).astype(int)
            mpossy
= mpossy[np.nonzero(mpossy)]# get the y pos from ROI
           
self.mask[mpossx,mpossy] = 1
           
self.plot.removeItem(self.roi)
           
self.mimg.setImage(self.mask,autoLevels=False,levels=[0,2])
           
del self.roi

Basically is the idea is you create two extra images, with the x positions and y positions in your array. You extract those pixels from your ROI and it will give you the index into your original image. From there, you can create a new image.

However, I'd like to warn you to beware, an interpolation is performed in the process. If you add rotations to your ROI, you will run into issues. I haven't had any feedback from this but I hope this helps. :-)

Either way, yes, this library is great :-)

cheers,

Julien

L. Smash

unread,
May 15, 2015, 5:45:50 AM5/15/15
to pyqt...@googlegroups.com
Hi Julien,

thanks very much for your comment! Took me a while to get your idea, I also realized the interpolation issue but in my case I can do without rotations...

Since I am new to this: I am stuck at attaching this part to the ROI classes. Seems that the way I am trying this, I can't use "self" because it always tells me that I need one more argument. Could you help me out here?

cheers,
Lars

Julien Lhermitte

unread,
May 15, 2015, 9:40:12 AM5/15/15
to pyqt...@googlegroups.com
Hi,

     I am not completely sure I understand your question but I think your concern is the self variable. Yes, this was just a quick snippet I copied and pasted.
First, I believe whenever you call a function in an object, the first parameter given is always a reference to the object itself.

So if tiger is part of class Cat, and has member function getColor(), this function:
tiger.getColor() is actually a shortcut for Cat.getColor(tiger), so when declaring a function in a class, the function should be declared as:

def getColor(theObjectCallingIt, otherparameters...):

But let's ignore that for now and just create some self contained code. I have attached it in this message. It generates random data but it's always a good idea to use some sort of image with features to test (just uncomment the relevant lines for that and install PIL image lib for example)

I hope this helps!

julien

testROI.py

Julien Lhermitte

unread,
May 15, 2015, 10:45:27 AM5/15/15
to pyqt...@googlegroups.com
oops the dimensions were wrong (ROI went out of bounds of data array), I have reattached the correct example.

Also, the self variable in my previous example would be the theObjectCallingIt in my current example. It can have whatever name you want.

(doing this on my spare time here and there :-( but hope it helps)
testROI.py

L. Smash

unread,
May 18, 2015, 3:32:31 AM5/18/15
to pyqt...@googlegroups.com
Hi,

thanks for the nice example! I think I've got it now :)

What I actually was trying to do is to put your code into a function/method (like getArrayRegion) and dynamically add it to ROI classes of pyqtgraph (PolyLineROI, Ellipse.ROI etc.). The problem I stumbled across was an issue with bound\unbound methods (see here), that's why I got confused with the self variable. Thanks again for your explanation and the example, it helped me very much!

Best,
Lars

Julien Lhermitte

unread,
May 18, 2015, 11:50:20 AM5/18/15
to pyqt...@googlegroups.com
Great I'm glad to hear this! Thanks for the information by the way, I didn't know you could do this but it's a great feature to have (add a function to a class after the fact just like you can do with attributes).

I'm not sure which way is more pythonic but I would still rather create a new class with this new method that inherits all methods members of the ROI class used in the long run. This might make things easier to keep track of. If you're not familiar, look up inheritance (like here), it's pretty simple to implement. But this is a nice quick fix.

Xingyu Liu

unread,
Apr 6, 2020, 10:45:41 AM4/6/20
to pyqtgraph
Hi guys:

Thank you so much for your helpful discussion! I'm also a new guy to pyqtgraph and trying to find a way to get binary ROI, but when I ran the attached testROI.py, an error occurs:
'''
Traceback (most recent call last):
  File "testROI.py", line 37, in <module>
    mpossx = roi.getArrayRegion(possx,imgview).astype(int)
  File "D:\Program\Miniconda3\envs\bs\lib\site-packages\pyqtgraph\graphicsItems\ROI.py", line 2027, in getArrayRegion
    sliced = ROI.getArrayRegion(self, data, img, axes=axes, fromBoundingRect=True, **kwds)
  File "D:\Program\Miniconda3\envs\bs\lib\site-packages\pyqtgraph\graphicsItems\ROI.py", line 1104, in getArrayRegion
    shape, vectors, origin = self.getAffineSliceParams(data, img, axes, fromBoundingRect=fromBR)
  File "D:\Program\Miniconda3\envs\bs\lib\site-packages\pyqtgraph\graphicsItems\ROI.py", line 1129, in getAffineSliceParams
    raise Exception("ROI and target item must be members of the same scene.")
Exception: ROI and target item must be members of the same scene.
'''
I guess it is because the function 'ROI.getArrayRegion' has been changed/updated over the years. But as a newbie, I don't quite understand how to fix it ... Could you please give me some suggestions? Thank you very much!!

Best,
Xingyu 

在 2015年5月18日星期一 UTC+8下午11:50:20,Julien Lhermitte写道:

Xingyu Liu

unread,
Apr 6, 2020, 10:54:39 PM4/6/20
to pyqtgraph

Hey guys:

Good news! I just fixed the bug by myself. Attached is my modified implementation, which works fine with pyqtgraph 0.10.0. I use v1a to display the original image and v1b to display the mask.

Thanks,
Xingyu
 
在 2020年4月6日星期一 UTC+8下午10:45:41,Xingyu Liu写道:
testROI.py
Reply all
Reply to author
Forward
0 new messages