Numpy array manipulation within range of columns and rows
<p>I have a numpy boolean 2D array that represents a grayscale image which is essentially an unfilled shape (triangle, square, circle) consisting of <code>True</code> for white pixels, and <code>False</code> for black pixels. I would like to add a black fill by modifying the white pixels to black pixels.</p>

<pre><code>array([[True, True, True, False, False, False, False, False, True, True, True],
       [True, True, True, False,  True,  True,  True, False, True, True, True],
       [True, True, True, False,  True,  True,  True, False, True, True, True],
       [True, True, True, False,  True,  True,  True, False, True, True, True],
       [True, True, True, False, False, False, False, False, True, True, True]])
</code></pre>

<p>(The 9 <code>True</code> values in a square in the middle of this array should become <code>False</code>.)</p>

<p>Is there a numpy slice method that will make this easy/fast? Something that I can modify all <code>True</code>s anytime there's a <code>False</code> followed by a <code>True</code> until the next instance of a <code>False</code>?</p>

<p>Here one idea that's easy to implement and should perform reasonably quickly.</p>

<p>I'll use 0s and 1s so it's a little clearer to look at.</p>

<p>Here's the starting array:</p>

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

<p>Accumulate left-to-right using <code>np.logical_and.accumulate</code>, flip left-to-right, do the same again, flip back, and the "or" the two arrays together:</p>

<pre><code>&gt;&gt;&gt; andacc = np.logical_and.accumulate
&gt;&gt;&gt; (andacc(a, axis=1) | andacc(a[:, ::-1], axis=1)[:, ::-1]).astype(int)
array([[1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1],
       [1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1],
       [1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1],
       [1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1],
       [1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1]])
</code></pre>

<p>(Leave out <code>.astype(int)</code> to keep a boolean array instead of 0s and 1s.)</p>

<p>Here's a triangle:</p>

<pre><code>&gt;&gt;&gt; b
array([[1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1],
       [1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1],
       [1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1],
       [0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0]])

&gt;&gt;&gt; (andacc(b, axis=1) | andacc(b[:, ::-1], axis=1)[:, ::-1]).astype(int)
array([[1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1],
       [1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1],
       [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
</code></pre>

python arrays performance numpy