Numpy: Get rectangle area just the size of mask
<p><strong>I have an image and a mask. Both are numpy array.</strong> I get the mask through GraphSegmentation (cv2.ximgproc.segmentation), so the area isn't rectangle, but not divided. I'd like to get a rectangle just the size of masked area, but I don't know the efficient way.</p>

<blockquote>
  <p>In other words, unmasked pixels are value of 0 and masked pixels are value over 0, so I want to get a rectangle where...</p>
</blockquote>

<ul>
<li><strong>top</strong> = the smallest index of axis 0 whose value > 0</li>
<li><strong>bottom</strong> = the largest index of axis 0 whose value > 0</li>
<li><strong>left</strong> = the smallest index axis 1 whose value > 0</li>
<li><strong>right</strong> = the largest index axis 1 whose value > 0</li>
<li><strong>image</strong> = src[top : bottom, left : right]</li>
</ul>

<p><strong>My code is below</strong></p>

<pre><code>segmentation = cv2.ximgproc.segmentation.createGraphSegmentation()
src = cv2.imread('image_file')
segment = segmentation.processImage(src)
for i in range(np.max(segment)):
    dst = np.array(src)
    dst[segment != i] = 0
    cv2.imwrite('output_file', dst)
</code></pre>

<p>If you prefer pure Numpy, you can achieve this using <a href="http://docs.scipy.org/doc/numpy/reference/generated/numpy.where.html" rel="nofollow"><code>np.where</code></a> and <a href="http://docs.scipy.org/doc/numpy/reference/generated/numpy.meshgrid.html#numpy.meshgrid" rel="nofollow"><code>np.meshgrid</code></a>:</p>

<pre><code>i, j = np.where(mask)
indices = np.meshgrid(np.arange(min(i), max(i) + 1),
                      np.arange(min(j), max(j) + 1),
                      indexing='ij')
sub_image = image[indices]
</code></pre>

<p><code>np.where</code> returns a tuple of arrays specifying, pairwise, the indices in each axis for each non-zero element of <code>mask</code>.  We then create arrays of all the row and column indices we will want using <code>np.arange</code>, and use <code>np.meshgrid</code> to generate two grid-shaped arrays that index the part of the image we're interested in.  Note that we specify matrix-style indexing using <code>index='ij'</code> to avoid having to transpose the result (the default is Cartesian-style indexing).</p>

<p>Essentially, <code>meshgrid</code> constructs <code>indices</code> so that:</p>

<pre><code>image[indices][a, b] == image[indices[0][a, b], indices[1][a, b]]
</code></pre>

<h1>Example</h1>

<p>Start with the following:</p>

<pre><code>&gt;&gt;&gt; image = np.arange(12).reshape((4, 3))
&gt;&gt;&gt; image
array([[ 0,  1,  2],
       [ 3,  4,  5],
       [ 6,  7,  8],
       [ 9, 10, 11]])
</code></pre>

<p>Let's say we want to extract the <code>[[3,4],[6,7]]</code> sub-matrix, which is the bounding rectangle for the the following mask:</p>

<pre><code>&gt;&gt;&gt; mask = np.array([[0,0,0],[0,1,0],[1,0,0],[0,0,0]])
&gt;&gt;&gt; mask
array([[0, 0, 0],
       [0, 1, 0],
       [1, 0, 0],
       [0, 0, 0]])
</code></pre>

<p>Then, applying the above method:</p>

<pre><code>&gt;&gt;&gt; i, j = np.where(mask)
&gt;&gt;&gt; indices = np.meshgrid(np.arange(min(i), max(i) + 1), np.arange(min(j), max(j) + 1), indexing='ij')
&gt;&gt;&gt; image[indices]
array([[3, 4],
       [6, 7]])
</code></pre>

<p>Here, <code>indices[0]</code> is a matrix of row indices, while <code>indices[1]</code> is the corresponding matrix of column indices:</p>

<pre><code>&gt;&gt;&gt; indices[0]
array([[1, 1],
       [2, 2]])
&gt;&gt;&gt; indices[1]
array([[0, 1],
       [0, 1]])
</code></pre>

python opencv numpy