Kadek Dwi Budi Utama - 1 year ago 96
Python Question

# Create Image Histogram Manually and Efficiently in Python

I want to write codes that can show the histogram of an image without using built in Matplotlib hist function.

Here is my codes:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

def manHist(img):
row, col = img.shape # img is a grayscale image
y = np.zeros((256), np.uint64)
for i in range(0,row):
for j in range(0,col):
y[img[i,j]] += 1
x = np.arange(0,256)
plt.bar(x,y,color="gray",align="center")
plt.show()

def main():
manHist(img)

main()

My question is, is there a more efficent way to make an array of pixel value frequency without using for loop?

A NumPy based vectorized solution would be with np.bincount -

out = np.bincount(img.ravel(),minlength=256)

Another vectorized approach based on .sum() -

out = (img.ravel() == np.arange(256)[:,None]).sum(1)

Sample run to verify results -

In [155]: # Input image (512x512) as array
...: img = np.random.randint(0,255,(512,512))
...:
...: # Original code
...: row, col = img.shape
...: y = np.zeros((256), np.uint64)
...: for i in range(0,row):
...:     for j in range(0,col):
...:         y[img[i,j]] += 1
...:

In [156]: out1 = np.bincount(img.ravel(),minlength=256)

In [157]: out2 = (img.ravel() == np.arange(256)[:,None]).sum(1)

In [158]: np.allclose(y,out1)
Out[158]: True

In [159]: np.allclose(y,out2)
Out[159]: True
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download