How to Count Number of White and Black Pixels in Color Picture in Python? How to Count Total Pixels Using Numpy

Count total number of pixels for each color

This is the simplest way to get the colours and their corresponding counts:

#!/usr/bin/env python3

from PIL import Image
import numpy as np

# Open image and ensure RGB
im = Image.open('UMN9c.png').convert('RGB')

# Make into Numpy array
na = np.array(im)

# Get colours and corresponding counts
colours, counts = np.unique(na.reshape(-1,3), axis=0, return_counts=1)

print(colours, counts)

Sample Outputs

 [[ 37  36  36]
[226 44 11]
[228 239 80]] [255169 1059 5916]

If you don't want to write any Python code, you can just use ImageMagick in the Terminal

magick -verbose UMN9c.png -format %c histogram:info:-

Output

UMN9c.png PNG 512x512 512x512+0+0 8-bit sRGB 3572B 0.020u 0:00.008
255169: (37,36,36,255) #252424FF srgba(37,36,36,1)
1059: (226,44,11,255) #E22C0BFF srgba(226,44,11,1)
5916: (228,239,80,255) #E4EF50FF srgba(228,239,80,1)
UMN9c.png=>info:- PNG 512x512 512x512+0+0 8-bit sRGB 3572B 0.320u 0:00.166

I'm not sure if outright speed is an issue for you. If so, there is a significantly faster method using np.dot() at the end of this answer.

Numpy doesn't count pixels in image correctly

Dumping the data of the original image using print(img) gives

[[[  0   0   0]
[ 0 0 0]
[ 0 0 0]
[ 0 0 0]]

[[ 0 0 0]
[ 0 0 0]
[ 0 0 0]
[ 0 0 0]]

[[255 255 255]
[255 255 255]
[255 255 255]
[ 0 0 0]]

[[ 1 1 1]
[ 0 0 0]
[ 0 0 0]
[ 0 0 0]]]

This agrees with the results of your code: we have 9 255s and 36 0s. As you can see one of the pixels is not quite black, but a very dark gray.

The reason each value appears three times is because it is encoded as RGB. If you only care about handling grayscale images, you can tell opencv to load the image as grayscale instead:

img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
"""
print(img) now gives
[[ 0 0 0 0]
[ 0 0 0 0]
[255 255 255 0]
[ 1 0 0 0]]
"""

How to count number of black pixels in png?

Simple script to count black pixels:

def countBlack (image):
blacks = 0
for color in image.flatten():
if color < 0.0001:
blacks += 1
return blacks

Count total number of white pixels in an image

Notice that Image is capitalized...in PIL, Image is a class. The actual image data is one of the many properties inside the class, and PIL does not use numpy arrays. Thus, your image is not a numpy array. If you want to convert to a numpy array, simply encase the image as an array:

img = np.array(img)

If you read the image with OpenCV, then it already comes as a numpy array.

img = cv2.imread(filename)

Also note that the ordering of channels is different in PIL than OpenCV. In PIL, images are read as RGB order, while in OpenCV, they are in BGR order. So if you read with PIL but display with OpenCV, you'll need to swap the channels before displaying.


Edit: also, check the OpenCV docs for countNonZero(). This function only works on single channel arrays, so you'll need to either convert the image to grayscale, or decide how you want to count a zero. You can also just use numpy just by np.sum(img == 0) to count the number of zero values, or np.sum(img > 0) to count non-zero values. For a three channel array, this will count all the zeros in each channel independently. If you want to only include ones that are zero in all three colors, you can do a number of things---the simplest is probably to add all the channels together into one 2D array, and then do the same as above.


Edit2: also, your code right now is counting the number of black pixels, not white. countNonZero() will return the number of all pixels greater than 0. Then you subtract that off the total number of pixels...which will give you only the black pixels. If you just want to count the number of white pixels, np.sum(img == 255).


Edit3: So with your image, this code works fine:

import cv2
import numpy as np

img = cv2.imread('img.png', cv2.IMREAD_GRAYSCALE)
n_white_pix = np.sum(img == 255)
print('Number of white pixels:', n_white_pix)

Number of white pixels: 5

Note here that cv2.IMREAD_GRAYSCALE is just equal to 0, but this is more explicit.



Related Topics



Leave a reply



Submit