Python script to count pixel values fails on a less-than/greater-than comparison
<p>I wrote a short script to count the pixel values in an image:</p>

<pre><code>import os
import sys
import cv2
import numpy as np

imn = (sys.argv[1])
a = cv2.imread(imn, 0)
b = cv2.imread(imn, 1)
c = cv2.GaussianBlur(cv2.imread(imn, 0), (7,7), 2)

def NC(img):
    y = img.reshape(1, -1)
    numA = (y &lt; 127.5).sum()
    numB = (y &gt; 127.5).sum()
    return ({'less': numA, 'greater': numB})

aa = NC(a)
bb = NC(b)
cc = NC(c)
print "File:  {}".format(imn.split('/')[-1])
print "Image: {} - Set: {}".format('A', aa)
print "Image: {} - Set: {}".format('B', bb)
print "Image: {} - Set: {}".format('C', cc)
</code></pre>

<p>And it works perfectly:</p>

<pre><code>File:  ObamaBidenSituationRoom.jpg
Image: A - Set: {'greater': 480558, 'less': 611282}
Image: B - Set: {'greater': 1441948, 'less': 1833572}
Image: C - Set: {'greater': 471559, 'less': 620281}
</code></pre>

<p>But when I tried to expand it:</p>

<pre><code>def NC(img):
    y = img.reshape(1, -1)

    numA = (00.99 &lt; y &lt; 85.00).sum()
    numB = (85.00 &lt; y &lt; 170.0).sum()
    numC = (170.0 &lt; y &lt; 256.0).sum()

    return ({'low': numA, 'middle': numB, 'high': numC})
</code></pre>

<p>It gave me an error:</p>

<pre><code>Traceback (most recent call last):
  File "Bins--02.py", line 25, in &lt;module&gt;
    aa = NC(a)
  File "Bins--02.py", line 17, in NC
    numA = (00.99 &lt; y &lt; 85.00).sum()
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
</code></pre>

<p>I got this image a while ago, but that was with a matplotlib library that I ended up not using. Why is it coming up here? Am I bounding that greater-than/less-than signs wrong? I tried to fix it</p>

<p><code>numA = (00.99 &lt; y).sum() and (y &lt; 85.00).sum()</code></p>

<p>But that just gave me random super high values.</p>

<p><strong><em>UPDATE - Oct20</em></strong></p>

<p>So, I changed it:</p>

<pre><code>def NC(img):
    x = img.reshape(1, -1)


    numA = x[np.where((00.99 &lt; x) &amp; (x &lt; 85.00))].sum()
    numB = x[np.where((85.00 &lt; x) &amp; (x &lt; 170.0))].sum()
    numC = x[np.where((170.0 &lt; x) &amp; (x &lt; 256.0))].sum()
    numD = x.shape

    return ({'total': numD, 'low': numA, 'middle': numB, 'high': numC})
</code></pre>

<p>And now it works, but there's a problem: the pixel counts don't match up. </p>

<pre><code>Image:  lenna.png
Image:  A Set:{'high': 8367459, 'middle': 20278460, 'total': (1, 262144), 'low': 3455619}
Image:  B Set:{'high': 45250935, 'middle': 43098232, 'total': (1, 786432), 'low': 11609051}
Image:  C Set:{'high': 8216989, 'middle': 20633144, 'total': (1, 262144), 'low': 3531090}
</code></pre>

<p>The measurements are pixels, there can't be more than the total. Where am I getting 2 million from?</p>

<p>For example, I ran it on a 100x100 image of a blue circle: </p>

<pre><code>Image:  lightblue.png
Image:  A Set:{'high': 0, 'middle': 1035999, 'total': (1, 10000), 'low': 0}
Image:  B Set:{'high': 1758789, 'middle': 1212681, 'total': (1, 30000), 'low': 417612}
Image:  C Set:{'high': 0, 'middle': 1014135, 'total': (1, 10000), 'low': 31801}
</code></pre>

<p>and it's completely wrong.</p>

<p><strong><em>Edit Two</em></strong></p>

<p>I just ran it on a test array:</p>

<pre><code>i = np.array([[1, 1, 1, 1, 1, 1, 1, 1], [3, 3, 3, 3, 3, 3, 3, 3], [200, 200, 200, 200, 200, 200, 200, 200]])

def NC(img):
    x = img.reshape(1, -1)
    numA = x[np.where((00.99 &lt; x) &amp; (x &lt; 85.00))].sum()
    numB = x[np.where((85.00 &lt; x) &amp; (x &lt; 170.0))].sum()
    numC = x[np.where((170.0 &lt; x) &amp; (x &lt; 256.0))].sum()
    numD = (img.shape[0] * img.shape[1])
    return ({'total': numD, 'low': numA, 'middle': numB, 'high': numC})

aa = NC(i)
bb = NC(i)
cc = NC(i)

print "Image:  {} Set:{}".format('A', aa)
print "Image:  {} Set:{}".format('B', bb)
print "Image:  {} Set:{}".format('C', cc)
</code></pre>

<p>And it's entirely broken:</p>

<pre><code>Image:  A Set:{'high': 1600, 'middle': 0, 'total': 24, 'low': 32}
Image:  B Set:{'high': 1600, 'middle': 0, 'total': 24, 'low': 32}
Image:  C Set:{'high': 1600, 'middle': 0, 'total': 24, 'low': 32}
</code></pre>

<p>Why is it doing this?</p>

<p>There are a couple of issues with your approach.</p>

<p>When you do</p>

<pre><code>(y &lt; 85.00).sum()
</code></pre>

<p>You're actually summing over the truth condition. So you end up counting where the condition evaluates to <code>True</code>. You can easily see it with a quick example:</p>

<pre><code>In [6]: x = np.arange(10)

In [7]: x
Out[7]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [8]: x &lt; 4
Out[8]: array([ True,  True,  True,  True, False, False, False, False, False, False], dtype=bool)

In [9]: (x &lt; 4).sum()
Out[9]: 4
</code></pre>

<p>Now if you want to get the indices where the condition is satisfied, you can use <code>np.where</code></p>

<pre><code>In [10]: np.where(x &lt; 4)
Out[10]: (array([0, 1, 2, 3]),)
</code></pre>

<p>And use them for your sum</p>

<pre><code>In [11]: x[np.where(x &lt; 4)].sum()
Out[11]: 6
</code></pre>

<p>The other issue comes from using the compact notation for the range which is easily solved splitting it in two with <code>&amp;</code> or <code>np.logical_and()</code></p>

<pre><code>In [12]: x[np.where((2 &lt; x) &amp; (x &lt; 6))].sum()
Out[12]: 12
</code></pre>

python arrays numpy operators truthiness