Reputation: 305
Given an image, is there a quick way to map the pixel value to its bin?
img = cv2.imread('test_image.jpg')
hist_g = cv2.calcHist([img[x:x+w,y:y+h,:]], [1], None, [9], [0, 256])
This returns a 9x1 array with the counts of pixels that fall into 9 bins ranging from 0 - 256. I think.
What I want is [x:x+w,y:y+h]
matrix with each entry having the bin number that the pixel gets mapped to. How can I do this?
For example, let's say I have the matrix
x = np.array([[154, 192],[67,115]])
I would like to return the matrix
x_histcounts = np.array([[5, 7],[3,4]])
based on cv2.calcHist([img[x:x+w,y:y+h,:]], [1], None, [9], [0, 256])
since 154 is in the 5th bin, 192 in the 7th bin, etc.
Upvotes: 0
Views: 748
Reputation: 143056
If you want map pixel to 9
bins then you can convert to grayscale and later divide by (256/9)
using //
to get integer numbers
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
result = img_gray[x:x+w,y:y+h] // (256/9)
In calcHist
you use list of channels [1]
so you want histogram only for one channel and it means you don't have to convert to grayscale but use [..., ..., 1]
result = img[x:x+w, y:y+h, 1] // (256/9)
EDIT: I tested your example data [[154, 192], [67, 115]]
and it gives me
[[5, 6], [2, 4]]
instead of [[5, 7], [3, 4]]
import numpy as np
bins_number = 9
x = np.array([[154, 192], [67, 115]])
result = (x // (256/bins_number)).astype(int)
print('result:', result.tolist())
Using Google "numpy histcounts matlab"
I found also How do i replicate this matlab function in numpy? which uses np.digitize()
to replicate histcounts
and it also gives me [[5, 6], [2, 4]]
instead of [[5, 7], [3, 4]]
but I don't know if I correctly create bins ranges.
import numpy as np
bins_number = 9
x = np.array([[154, 192], [67, 115]])
bins = [(256/bins_number)*x for x in range(1, bins_number+1)]
result = np.digitize(x, bins)
print('result:', result.tolist())
print('bins:', bins)
I don't have Matlab
so I tried to use histc()
in Octave
>> [a, b] = histc([154, 192, 67, 115], [ 28.44444444, 56.88888889,
85.33333333, 113.77777778, 142.22222222, 170.66666667, 199.11111111, 227.55555556, 256. ])
a =
0 1 0 1 1 1 0 0 0
b =
5 6 2 4
and it also gives me [[5, 6], [2, 4]]
instead of [[5, 7], [3, 4]]
EDIT: I found numpy.histogram_bin_edges to generate bins ranges
import numpy as np
bins_number = 9
x = np.array([[154, 192], [67, 115], [0,1]])
bins = np.histogram_bin_edges(x, bins=9, range=(0, 256))
print('bins:', bins)
But it adds 0
as first edge so later it uses numbers 1-9
instead of 0-8
but if you use bins[1:]
then it still use numbers 0-8
import numpy as np
bins_number = 9
x = np.array([[154, 192], [67, 115]])
bins = np.histogram_bin_edges(x, bins=9, range=(0, 255))
print('bins:', bins)
print('result:', np.digitize(x, bins[1:]).tolist())
Upvotes: 1