title: Semantic Segmentation to Bounding Boxes
body: <p>Suppose you are performing semantic segmentation. For simplicity, let's assume this is 1D segmentation rather than 2D (i.e. we only care about finding objects with width).</p>
  
  <p>So the desired output of our model might be something like:</p>
  
  <pre><code>[
      [0, 0, 0, 0, 1, 1, 1], # label channel 1 
      [1, 1, 1, 0, 0, 1, 1], # label channel 2 
      [0, 0, 0, 1, 1, 1, 0], # label channel 3
      #...
  ]
  </code></pre>
  
  <p>However, our trained imperfect model might be more like</p>
  
  <pre><code>[
      [0.1,  0.1,  0.1,  0.4,  0.91, 0.81, 0.84], # label channel 1 
      [0.81, 0.79, 0.85, 0.1,  0.2,  0.61, 0.91], # label channel 2 
      [0.3,  0.1,  0.24, 0.87, 0.62, 1,    0   ], # label channel 3
      #...
  ]
  </code></pre>
  
  <p>What would be a performant way, using python, for getting the boundaries of the labels (or bounding box)</p>
  
  <p>e.g. (zero-indexed)</p>
  
  <pre><code>[
      [[4, 6]],        # "objects" of label 1
      [[0, 2], [5, 6]] # "objects" of label 2
      [[3, 5]],        # "objects" of label 3
  ]
  </code></pre>
  
  <p>if it helps, perhaps transforming it to a binary mask would be of more use?</p>
  
  <pre><code>def binarize(arr, cutoff=0.5):
    return (arr &gt; cutoff).astype(int)
  </code></pre>
  
  <p>with a binary mask we just need to find the consecutive integers of the indices of nonzero values:</p>
  
  <p>def consecutive(data, stepsize=1):
      return np.split(data, np.where(np.diff(data) != stepsize)[0]+1)</p>
  
  <p>find "runs" of labels:</p>
  
  <pre><code>def binary_boundaries(labels, cutoff=0.5):  
    return [consecutive(channel.nonzero()[0]) for channel in binarize(labels, cutoff)]
  </code></pre>
  
  <p>name objects according to channel name:</p>
  
  <pre><code>def binary_objects(labels, cutoff=0.5, channel_names=None):
    if channel_names == None: 
      channel_names = ['channel {}'.format(i) for i in range(labels.shape[0])]
  
    return dict(zip(channel_names, binary_boundaries(labels, cutoff)))
  </code></pre>