Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to go from a contour to an image mask in with Matplotlib

If I plot a 2D array and contour it, I can get the access to the segmentation map, via cs = plt.contour(...); cs.allsegs but it's parameterized as a line. I'd like a segmap boolean mask of what's interior to the line, so I can, say, quickly sum everything within that contour.

Many thanks!

like image 927
Chris Avatar asked Jun 07 '13 02:06

Chris


People also ask

How to draw a contour with a mask?

If (as done in my answer) the contour is drawn in (255) or (255,255,255), the contour is drawn in white and the resulting image is a mask for the contour. Choosing thickness = -1 performs drawing a filled conour, which results in a mask of the whole contour area instead of the contour outline.

How do I create a contour plot of an image?

Create a contour plot of the image using imcontour . Grayscale image, specified as an m -by- n matrix. Number of contour levels, specified as a numeric scalar. Value of contour levels, specified as a numeric vector with length greater than or equal to two. Use V = [v v] to compute a single contour at level v.

How do you remove contours from an image?

The basic algorithm for removing contours from an image goes something like this: Step 1: Detect and find contours in your image. Step 2: Loop over contours individually. Step 3: Determine if the contour is “bad” and should be removed according to some criterion. Step 4: Accumulate a mask of “bad” contours to be removed.

How do I plot images with Matplotlib?

A short tutorial on plotting images with Matplotlib. First, let's start IPython. It is a most excellent enhancement to the standard Python prompt, and it ties in especially well with Matplotlib. Start IPython either directly at a shell, or with the Jupyter Notebook (where IPython as a running kernel).


2 Answers

I dont think there is a really easy way, mainly because you want to mix raster and vector data. Matplotlib paths fortunately have a way to check if a point is within the path, doing this for all pixels will make a mask, but i think this method can get very slow for large datasets.

import matplotlib.patches as patches
from matplotlib.nxutils import points_inside_poly
import matplotlib.pyplot as plt
import numpy as np

# generate some data
X, Y = np.meshgrid(np.arange(-3.0, 3.0, 0.025), np.arange(-3.0, 3.0, 0.025))
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
# difference of Gaussians
Z = 10.0 * (Z2 - Z1)

fig, axs = plt.subplots(1,2, figsize=(12,6), subplot_kw={'xticks': [], 'yticks': [], 'frameon': False})

# create a normal contour plot
axs[0].set_title('Standard contour plot')
im = axs[0].imshow(Z, cmap=plt.cm.Greys_r)
cs = axs[0].contour(Z, np.arange(-3, 4, .5), linewidths=2, colors='red', linestyles='solid')

# get the path from 1 of the contour lines
verts = cs.collections[7].get_paths()[0]

# highlight the selected contour with yellow
axs[0].add_patch(patches.PathPatch(verts, facecolor='none', ec='yellow', lw=2, zorder=50))

# make a mask from it with the dimensions of Z
mask = verts.contains_points(list(np.ndindex(Z.shape)))
mask = mask.reshape(Z.shape).T

axs[1].set_title('Mask of everything within one contour line')
axs[1].imshow(mask, cmap=plt.cm.Greys_r, interpolation='none')

# get the sum of everything within the contour
# the mask is inverted because everything within the contour should not be masked
print np.ma.MaskedArray(Z, mask=~mask).sum()

Note that contour lines which 'leave' the plot at different edges by default wont make a path which follows these edges. These lines would need some additional processing.

enter image description here

like image 82
Rutger Kassies Avatar answered Nov 09 '22 16:11

Rutger Kassies


Another way, perhaps more intuitive, is the binary_fill_holes function from scipy.ndimage.

import numpy as np
import scipy


image = np.zeros((512, 512))
image[contour1[:, 0], contour1[:, 1]] = 1
masked_image = scipy.ndimage.morphology.binary_fill_holes(image)
```
like image 32
HagaiH Avatar answered Nov 09 '22 16:11

HagaiH