How to find the brightest pixel?

2.6k views Asked by At

How do I find the brightness (i.e. V in HSV) of the brightest pixel in an image?

I have a large collection of images that will be used as background assets. In order to make sure there are no bright spots that may distract the viewer, I'd like to find all the images whose brightest pixels exceed a certain threshold, so that they can be reworked.

Is there an Imagemagick operation for doing this?

3

There are 3 answers

0
leu On BEST ANSWER

HSV colorspace in IM is called HSB, so you can get a histogram of image.jpg in that way:

convert image.jpg -colorspace HSB -format %c histogram:info:-

You need to reverse sort the output according to the third column (= brightness) and then pick the first line, which can be achieved like this (for the following, I assume Linux as OS):

convert image.jpg -colorspace HSB -format %c histogram:info:- \
 | sort -t',' -gr -k 3 | head -1

Next step is to filter the brightness value itself. Let's use sed and be aware of an alpha-channel:

sed 's/.* hsb.*,.*,\([0-9.]*\)%.*/\1/'

(this takes the third number out of the hsb- or hsba-parenthesis, which is the percentage value of the brightness of the brightest pixel.)

Taking all this together, we can write a small script bChecker.sh like this to examine png- and jpg-files:

#/bin/bash
Threshold=${1-75}
echo checking threshold $Threshold%

find . -name "*.png" -o -name "*.jpg" | while read pic; do
    Val=$(convert "$pic" -colorspace HSB -format %c histogram:info:- | \
         sort -t',' -gr -k 3 | head -1 | \
         sed 's/.* hsb.*,.*,\([0-9.]*\)%.*/\1/')
    (( $(echo "$Threshold < $Val" | bc) )) && echo "$pic: brightness exceeds threshold ($Val%)"
done

Called in the directory with your images as bash bChecker.sh 80, this script shows all the images whose brightness exceed 80%.

2
Mark Setchell On

Final Answer

Not sure what I was thinking of over the weekend. You can get the maximum intensity like this in a single step:

convert input.jpg -colorspace HSB -separate -delete 0,1 -format "%[max]" info:

The output value will be in the range 0-65535, so if you want to know if there are pixels brighter than, say 80%, you will need to test for a value greater than around 52,000. This assumes that your quantisation is 16-bit, i.e. that it says Q16 when you do identify -version.


Older answers below:

Updated Answer

Ok, back at a computer now. I think my second suggestion below has more mileage for your use case. I was misled by the way you asked the question into believing that you wanted to find the location of the brightest pixel, rather than simply knowing how bright it was. Anyway...

Let's start with an image like this:

convert -size 500x100 gradient:black-"rgb(204,204,204)" input.jpg

that goes from black to 80% white - i.e 204/255 = 80%

enter image description here

If we now convert to HSB and threshold at 70% like this, we get this (I have put an artificial red border around it so you can see the extent of the white area):

enter image description here

If I do the same again and threshold at 75% like this, you get:

enter image description here

And if I set the threshold at 80%:

enter image description here

And if I look at the mean pixel for the 70%, 75% and 80% images like this:

convert input.jpg -colorspace HSB -separate -delete 0,1 -threshold 70% -format "%[mean]" info:
8519.55

convert input.jpg -colorspace HSB -separate -delete 0,1 -threshold 75% -format "%[mean]" info:
4587.45

convert input.jpg -colorspace HSB -separate -delete 0,1 -threshold 80% -format "%[mean]" info:
0

You can see that the mean goes to zero when no pixels exceed the 80% brightness threshold - which hopefully, is exactly what you want.

Previous Answer

I tested it out, and I realised I had omitted the -verbose flag to get the statistics output, so if you run it like this, it should do the trick:

convert image.jpg -colorspace HSL -separate -delete 0,1 -threshold 80% -verbose info: | grep -i "max"

What does it actually do? It converts the image to HSL colorspace, and then seperates the three channels out - Hue, Saturation and Lightness. It then deletes the H&S channels, leaving just the Lightness. It then sets all pixels that have less than 80% lightness to zero (full black) and all those over 80% to one (full white). It then looks at the maximum pixel in the Lightness channel and, if all your pixels are below the 80% threshold, then the maximum pixel will be 0. If any pixels exceeed the 80% threshold, your maximum pixel will be 1.

Original Answer

I am nowhere near a machine with ImageMagick on it to check, but I believe I ran the following command to find the minimum pixel before now and I guess it can be adapted:

identify -precision 5 -define identify:locate=minimum -define identify:limit=3 image.jpg

Documentation is here.

Another option would be to convert to HSB colourspace, separate the channels and discard Hue and Saturation to leave just Brightness. Now threshold that, at say 80% so that everything below the threshold goes to zero (black) and everything above 80% goes white. Now check the mean or max pixel and if it is non zero, there are values above your threshold. Untested as I am still away from a computer:

convert image.jpg -colorspace HSB -separate -delete 0,1 -threshold 80% info: | grep -Ei "mean|max"
0
jcupitt On

I actually prefer the histogram answer, I think. If you search for the single brightest pixel you are likely to be misled by noise. I think it would be better to take a histogram and find (for example) the 95th percentile, ie. the brightness which 95% of pixels are darker than. This will be much less sensitive to noise, and probably more useful for determining the peak brightness in the image.

I don't know IM very well, but vips has an operation for this:

$ vips percent wtc.jpg 95
197

so 95% of pixels are darker then 197. That's in RGB space, of course. I think that would probably be good enough for this case. If you really wanted to test brightness you could convert to CIELAB and measure L*, but that would need a bit of scripting in Python/Ruby/whatever.