Get value from histogram

I have a lot of images to threshold. The correct threshold seems to be where the histogram of the image dies out a bit.
image
Here for example the correct value to get from the histogram would be about 200.
Except that after 200. The values are not exactly zero. So i can’t pick on the last value there is.
This is my code:

image=io.imread(image_path)

image = NormalizeData(image)
image = 255 * image
image=image.astype(np.uint8)

hist = cv2.calcHist(image, [0], None, [256], [0,256])
np_hist=np.histogram(image.ravel(),256,[0,256])

n, bins, patches=plt.hist(image.ravel(),256,[0,256])
plt.title('Histogram for gray scale image')
plt.show()

If anyone knows of any learnable threshold method too that would be great!

The requirement that the histogram “dies out a bit” is somewhat vague, but it sounds like you can just do this the old fashioned way (no deep learning) - just sort your values and pick the value corresponding to whatever percentile cutoff you think makes sense (i.e. 99.5th percentile or whatnot).

I wrote this. But it doesn’t always give the correct value. can you please elaborate more on your method? (keep in mind that the values after 200 are not zero)

np_hist=np.histogram(image.ravel(),256,[0,256])

def find_nearest(array, value):
    array = np.asarray(array)
    idx = (np.abs(array - value)).argmin()
    return array[idx]

def get_threshold(np_hist):
    n=np_hist[0].copy()
    n.sort()
    try:
        h=np_hist[0][::-1].tolist()
        print(h.index(find_nearest(np_hist[0],np.percentile(n,50))))
        index_pos = len(np_hist[0]) - h.index(find_nearest(h,np.percentile(n,50))) - 1
        print(f'Last Index of element "{np.percentile(n,50)}" in the list : ', index_pos)
    except ValueError as e:
        print(f'Element "{np.percentile(n,50)}" not found in the list: ', e)
    return index_pos

Maybe you can try to use ReLU as a way to set a threshold.

a = torch.randn(300, 300, requires_grad=True) + 5
bins = 401

y, x = a.histogram(bins, range=(0, 10))

plt.bar(x=x.detach().numpy()[:-1], height=y.detach().numpy())
plt.show()

image

class MyNet(torch.nn.Module):
    def __init__(self, threshold=7.):
        super().__init__()
        self.p = torch.nn.Parameter(torch.tensor([threshold]))
        self.relu = torch.nn.ReLU()

    def forward(self, x):
        x = x - self.relu(x-self.p)
        return x

net = MyNet()
b = net(a) # The same a as above

y, x = b.histogram(bins, range=(0, 10))

plt.bar(x=x.detach().numpy()[:-1], height=y.detach().numpy())
plt.show()

image

But as @Andrei_Cristea said, it might make more sense to do this without DL.

Hi Roua,

I just meant something as simple as this:

threshold_percentile = 99
threshold_value = np.percentile(image.ravel(), threshold_percentile)

Where the threshold_percentile is chosen to satisfy you original requirement that

the image dies out a bit.

Which to me suggests something in the 90s (like 95 or 99) rather than 50 as you showed in your snippet.

If this doesn’t do what you’d like, perhaps you can show an example of what this yields and what you’d like the it to yield instead.

Yes this might work. I will try it out :slight_smile: