<p>由于您正在处理图像并使用numpy,我认为最简单的方法是将图像分割成块,然后查看这些块中是否有像素是黑色的。例如,假设我有一个边缘图像,中间没有任何黑色像素,如下所示:</p>
<p><a href="https://i.stack.imgur.com/SqKAQ.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/SqKAQ.png" alt="Edge image"/></a></p>
<p>我们可以使用列表理解将图像转换为块:</p>
<pre><code>h, w = img.shape[:2]
bh, bw = h/3, w/3
bw_ind = [0, int(bw), 2*int(bw), w]
bh_ind = [0, int(bh), 2*int(bh), h]
blocks = [img[bh_ind[i]:bh_ind[i+1], bw_ind[j]:bw_ind[j+1]] for i in range(3) for j in range(3)]
</code></pre>
<p><a href="https://i.stack.imgur.com/1qHeR.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/1qHeR.png" alt="top-left"/></a><a href="https://i.stack.imgur.com/XfRW8.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/XfRW8.png" alt="top-mid"/></a><a href="https://i.stack.imgur.com/XHmNL.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/XHmNL.png" alt="top-right"/></a></p>
<p><a href="https://i.stack.imgur.com/RAek0.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/RAek0.png" alt="mid-left"/></a><a href="https://i.stack.imgur.com/MfySf.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/MfySf.png" alt="mid-mid"/></a><a href="https://i.stack.imgur.com/TQhud.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/TQhud.png" alt="mid-right"/></a></p>
<p><a href="https://i.stack.imgur.com/0Rqzf.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/0Rqzf.png" alt="bot-left"/></a><a href="https://i.stack.imgur.com/0xpZU.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/0xpZU.png" alt="bot-mid"/></a><a href="https://i.stack.imgur.com/AeA0S.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/AeA0S.png" alt="bot-right"/></a></p>
<p>现在为了让事情简单一点,我们可以在列表字典中按照块的相同顺序创建一个键列表;这样,<code>blocks[0]</code>将对应于<code>switch_list[0]</code>,即<code>"upperLeft"</code>。在</p>
^{pr2}$
<p>最后要做的就是找到每个块中的黑色像素。所以我们要遍历9个块(使用循环),然后将块内的值与我们感兴趣的任何颜色进行比较。如果您有一个3通道8位图像,那么黑色通常在每个通道中用<code>0</code>表示。所以对于一个像素,如果它是黑色的,那么我们可以用<code>pixel == [0,0,0]</code>来比较它。但这会为每个值返回一个布尔值:</p>
^{3}$
<p>当这三个值都匹配时,像素才是黑色的,所以我们可以对结果使用<code>.all()</code>,如果整个数组是<code>True</code>,则只返回{<cd7>}:</p>
<pre><code>>>> (pixel == [0,0,0]).all()
True
</code></pre>
<p>所以这是一个单一像素是黑色的指示器。但我们需要检查块内是否有任何</em>像素是黑色的。为了简单起见,我们先来看看单通道图像。假设我们有阵列</p>
<pre><code>M = np.array([[0,1], [2,3]])
</code></pre>
<p>如果我们在这里使用逻辑比较<code>M == 5</code>,我们将返回一个布尔数组,与<code>M</code>形状相同,将每个元素与<code>5</code>进行比较:</p>
<pre><code>>>> M == 5
array([[False, False] [False, False]])
</code></pre>
<p>在我们的例子中,我们不需要知道每个比较,我们只想知道块内的一个<em>单个</em>像素是否为黑色,所以我们只需要一个布尔值。我们可以使用<code>.any()</code>来检查是否有任何</em>值在^{<cd10>内是<code>True</code>:</p>
<pre><code>>>> (M == 5).any()
False
</code></pre>
<p>因此,我们需要将这两个操作结合起来;我们将确保<em>所有</em>的值与我们感兴趣的颜色(<code>[0,0,0]</code>)相匹配,以便对该像素进行计数,然后我们可以从每个<em>块内的比较中查看是否返回<code>True</code>:</p>
^{8}$
<p>注意<code>axis=2</code>参数:<code>.all(axis=2)</code>将把多通道图像缩小为一个像素位置的布尔值;<code>True</code>,如果每个通道的颜色匹配。然后我们可以检查是否有任何像素位置返回真值。这将为每个块减少为一个布尔值,告诉它是否包含颜色。因此,我们可以根据是否找到黑色像素将字典值设置为<code>True</code>或{<cd21>}:</p>
<pre><code>for i in range(len(switch_list)):
switch[switch_list[i]] = black_pixel_in_block[i]
</code></pre>
<p>最后,<code>print</code>结果是:</p>
<pre><code>>>> print(switch)
{'upperRight': True,
'upperLeft': True,
'lowerRight': True,
'lowerLeft': True,
'middleLeft': True,
'middleRight': True,
'upperMiddle': True,
'lowerMiddle': True,
'middle': False}
</code></pre>
<p>仅此操作在一张(21402870)图像上花费了~0.1秒。在</p>
<p>按照同样的思路,您可以首先为带有<code>.all()</code>的整个图像创建一个<code>True</code>,<code>False</code>值的矩阵,然后将</em>拆分成块,然后在块内使用<code>.any()</code>。这对于内存来说会更好,因为您存储的是9<code>(h,w)</code>块,而不是9<code>(h,w,depth)</code>块。在</p>