Search code examples
pythonmatplotlibroi

How does matplotlib.path.contains_points interact with PolygonSelector?


I'm fairly new to Python and am stuck on a problem...

I'm trying to draw a region of interest (ROI) on an image and calculate the average pixel value in that ROI.

To start, I tried the following - first I used matplotlib.widgets.PolygonSelector to draw a polygon, and then used path.contains_points to create a mask that I could then apply to the original image.

class ROIPolygon(object):
    def __init__(self, ax, row, col):
        self.canvas = ax.figure.canvas
        self.poly = PolygonSelector(ax,
                                    self.onselect,
                                    lineprops = dict(color = 'g', alpha = 1),
                                    markerprops = dict(mec = 'g', mfc = 'g', alpha = 1))
        self.path = None

    def onselect(self, verts):
        path = Path(verts)
        self.canvas.draw_idle()
        self.path = path

def get_mask(drawn_roi, row, col):
    for i in np.arange(row):
        for j in np.arange(col):
             if drawn_roi.path.contains_points([(j,i)]) == [True]:
                 mask[i][j] = 1
    mask_bool = mask.astype(bool)
    mask_bool = ~mask_bool
    return mask_bool

But when I tested this out on a small image containing only 4 colored pixels, I get this image before drawing ROI: enter image description here

And this one after drawing ROI: enter image description here

I expected the mask array to return only 4 False values.

[[ True  True  True  True  True  True  True  True  True  True]
 [ True  True  True  True  True  True  True  True  True  True]
 [ True  True  True  True  True  True  True  True  True  True]
 [ True  True  True  True  True  True  True  True  True  True]
 [ True  True  True  True  True False False  True  True  True]
 [ True  True  True  True  True False False  True  True  True]
 [ True  True  True  True  True  True  True  True  True  True]
 [ True  True  True  True  True  True  True  True  True  True]
 [ True  True  True  True  True  True  True  True  True  True]
 [ True  True  True  True  True  True  True  True  True  True]]

But instead it returned 12 False values. As well, if I were to draw the ROI even larger, I would return more False values.

[[ True  True  True  True  True  True  True  True  True  True]
 [ True  True  True  True  True  True  True  True  True  True]
 [ True  True  True  True  True  True  True  True  True  True]
 [ True  True  True  True  True  True  True  True  True  True]
 [ True  True  True  True False False False False  True  True]
 [ True  True  True  True False False False False  True  True]
 [ True  True  True  True False False False False  True  True]
 [ True  True  True  True  True  True  True  True  True  True]
 [ True  True  True  True  True  True  True  True  True  True]
 [ True  True  True  True  True  True  True  True  True  True]]

So I am wondering if there is something wrong with my approach, or if there is a particular interaction between the PolygonSelector and path.contains_points I am missing?

Thanks!


Solution

  • For anyone else that got confused as I was (by not reading documentation clearly), I solved my problem by altering my get_mask function as follows:

    def get_mask(img_frame, drawn_roi, row, col):
        for i in np.arange(row):
            for j in np.arange(col):
                 if np.logical_and(drawn_roi.path.contains_points([(j,i)]) == [True], img_frame[i][j] > 0):
                     mask[i][j] = 1
        mask_bool = mask.astype(bool)
        mask_bool = ~mask_bool
        return mask_bool