Jack O&#39;neill - 1 year ago 82
Python Question

# Get indices of feature position on image mask in python,opencv2,numpy

I am trying to extract index / position of two areas of a image mask and I am using a combination of python, opencv2, numpy and scipy.

I have a binary

`mask`
with the same size as the image.
After generating labels and sizes of it with

``````label_im, nb_labels = ndimage.label(mask)
sizes = ndimage.sum(mask, label_im, range(nb_labels + 1))
``````

With this information, I am able to extract the biggest areas.

Let's say we have a 10x10 matrix:

`````` 1     1     1     0     0     0     0     0     0     0
1     1     1     0     0     0     0     0     0     0
1     1     1     0     0     0     0     2     2     0
0     0     0     0     0     0     0     2     2     0
0     3     3     3     3     0     0     2     2     0
0     3     3     3     3     0     0     2     2     0
0     3     3     3     3     0     0     2     2     0
0     3     3     3     3     0     0     2     2     0
0     3     3     3     3     0     0     0     0     0
0     0     0     0     0     0     0     0     0     0
``````

I have 3 different areas (1,2,3) and I already know, that I need to further analyse area 2 and 3 (because those are the two biggest).

Now I want to find the index of the pixels which are

1. topmost leftmost of the regions - marked below as (n)

2. lowermost rightmost of the regions - marked below with [n]

same matrix as above:

`````` 1     1     1     0     0     0     0     0     0     0
1     1     1     0     0     0     0     0     0     0
1     1     1     0     0     0     0    (2)    2     0
0     0     0     0     0     0     0     2     2     0
0    (3)    3     3     3     0     0     2     2     0
0     3     3     3     3     0     0     2     2     0
0     3     3     3     3     0     0     2     2     0
0     3     3     3     3     0     0     2    [2]    0
0     3     3     3    [3]    0     0     0     0     0
0     0     0     0     0     0     0     0     0     0
``````

How is the fastest way to do that?

Problem 1:
I'm struggling with the syntax for those matrix conditionals.
For example, I try:

``````mask2 = mask[label_im == 2]
``````

It should get a binary mask again, but with only the cells set on which the original mask has a 2.
I'm not exactly sure what the result of the above generates. And I'm therefor not able to process it further.

Problem 2:
After that I will have to do something like finding the the indices of Row/Column where the topmost leftmost pixel is set.
Same to lowermost point.

For example for region 2, the results should be: (like the matrix above)

``````point1-X = 7
point1-Y = 2
point2-X = 8
point2-Y = 7
``````

where X stands for column, and Y for row (starting at index 0)

Or is there a better way to solve a problem like that with the combination of python/opencv2/numpy/scipy?

NumPy based solution

On a flattened version of the input image array, the `topmost leftmost` places would be the first ones, whereas `lowermost rightmost` would be the last ones. So, one trick would be to get the flattened indices of those two regions with `np.nonzero` and simply look for `min` and `max` indices to get those expected outputs respectively. Finally, we would use `np.unravel_index` to retrieve back row, col indices corresponding to original `2D` format.

Thus, one approach would be -

``````# Flattend indices for those two regions using the given labels
idx0 = np.nonzero(a.ravel()==2)[0]
idx1 = np.nonzero(a.ravel()==3)[0]

# Get the min, max indices for them. Use np.unravel_index to retrieve
# back row, col indices corresponding to original format of 2D input.
idxs = [idx0.min(), idx0.max(), idx1.min(), idx1.max()]
out = np.column_stack(np.unravel_index(idxs,a.shape))
``````

Sample run -

``````In [137]: a
Out[137]:
array([[1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 2, 2, 0],
[0, 0, 0, 0, 0, 0, 0, 2, 2, 0],
[0, 3, 3, 3, 3, 0, 0, 2, 2, 0],
[0, 3, 3, 3, 3, 0, 0, 2, 2, 0],
[0, 3, 3, 3, 3, 0, 0, 2, 2, 0],
[0, 3, 3, 3, 3, 0, 0, 2, 2, 0],
[0, 3, 3, 3, 3, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

In [138]: idx0 = np.nonzero(a.ravel()==2)[0]
...: idx1 = np.nonzero(a.ravel()==3)[0]
...: idxs = [idx0.min(), idx0.max(), idx1.min(), idx1.max()]
...: out = np.column_stack(np.unravel_index(idxs,a.shape))
...:

In [139]: out
Out[139]:
array([[2, 7],  # topmost leftmost of region -1
[7, 8],  # lowermost rightmost of region -1
[4, 1],  # topmost leftmost of region -2
[8, 4]]) # lowermost rightmost of region -2
``````

OpenCV based solution

OpenCV's `cv2.findContours` could be used to find the contours, which in itself is a pretty efficient implementation. Thus, we would be restricting the finding of indices to the contours only for a performance-oriented solution. Shown below is the function to get the `topmost leftmost` and `lowermost rightmost` row, column indices for each region -

``````def TL_LR(a, label):
_,contours,hierarchy = cv2.findContours((a==label).astype('uint8'),\
cv2.RETR_TREE,cv2.RETR_LIST)
idx = contours[0].reshape(-1,2)
lidx = idx[:,0] + a.shape[1]*idx[:,1]
return np.unravel_index([lidx.min(), lidx.max()],a.shape)
``````

Please note that for OpenCV versions prior to `3.0`, we would be getting two outputs only from `cv2.findContours`. So, for those versions, skip the `_` at that step.

Let's use it on the given sample -

``````In [188]: TL_LR(a,2)
Out[188]: (array([2, 7]), array([7, 8]))

In [189]: TL_LR(a,3)
Out[189]: (array([4, 8]), array([1, 4]))

In [190]: out  # Output from previous approach
Out[190]:
array([[2, 7],
[7, 8],
[4, 1],
[8, 4]])
``````
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download