Finding the Brightest Spot in an Image using Python and OpenCV

Originally I had intended on doing a followup post on my Getting Started with Deep Learning Guide, but due to some unfortunate personal events, I wasn’t able to complete the blog post. But don’t worry…I still have a really great tutorial for you today!


Bad tutorials are worse than warm beer.

You want to know why?

Because you can always chug a warm beer down in a few seconds…

But you can spend hours going down the wrong path when reading a misguiding tutorial.

And that’s my inspiration for this post — I really hate all the blog posts I’ve seen that detail how to find the brightest spot of an image using OpenCV.

You see, they are leaving out a single line of code that is absolutely crucial to being more robust to noise.

Now, if you’re like me, that doesn’t sit well.

So sit back. Relax. And know that you’re about to read a good tutorial. You won’t spend hours wasting your time here.

In this blog post I’ll show you how to find the brightest spot in an image using Python and OpenCV…and I’ll show you the single line of pre-processing code you’ll need to improve your results.

Looking for the source code to this post?
Jump right to the downloads section.

OpenCV and Python versions:
This example will run on Python 2.7/Python 3.4+ and OpenCV 2.4.X/OpenCV 3.0+.

You Need More than cv2.minMaxLoc

A few weeks ago a PyImageSearch reader wrote in and asked about the best way to find the brightest spot in the image.

You see, they were working with retinal images (see the top of this post for an example). These images are normally orange or yellowish in color, circular, and contain important physical structures of the eye, including the optic nerve and the macula.

This reader wanted to know the best way to find the optic nerve center, which is normally the brightest spot of the retinal image.

To find the brightest spot of the image using Python and OpenCV, you would utilize the cv2.minMaxLoc  function.

However, the term “spot” here is a little misleading.

The “brightest spot” of the image according to cv2.minMaxLoc  actually isn’t a region — it’s simply the brightest single pixel in the entire image.

This means that the cv2.minMaxLoc  function is extremely susceptible to noise if you don’t take the necessary pre-cautionary steps. A single bright pixel in an area where there wouldn’t normally be a bright pixel (in this case, an area other than the optic nerve center) can dramatically throw off your results.

Instead, you are better off examining regions of the image, rather than a single pixel. When you examine regions you let the average balance everything out — and you’re less susceptible to noise.

So how do you mimic this “region” effect without explicitly examining each and every region of the image?

I’ll show you.

The rest of this blog post is dedicated to showing you how to find the brightest spot of an image using Python and OpenCV

Finding the Brightest Spot in an Image using Python and OpenCV

Let’s go ahead and get started.

Open up your favorite editor, create a new file named bright.py , and let’s get started.

On Lines 2-4 we’ll import the packages we’ll need. If you’re a regular PyImageSearch reader, these packages should feel like old hat to you now. We’ll use NumPy for numerical processing, argparse  to parse command line arguments, and cv2  for our OpenCV bindings.

From there, we’ll parse our command line arguments on Lines 7-11. Nothing too special here.
The first switch, --image , is the path to the image we are going to find the brightest spot in. The second switch --radius , is an integer indicating the radius of the Gaussian blur we are going to apply to the image.

It’s important to note that this radius value must be odd and not even.

Next up, lets go ahead and load the image on Line 14, make a clone of it on Line 15, and convert it to grayscale on Line 15.

The Susceptible Method:

Now, let’s go ahead and apply the suspectible method method to detecting the brightest spot in the image:

The susceptible method to finding the brightest spot in an image is to use the cv2.minMaxLoc  function without any pre-processing. This function requires a single argument, which is our grayscale image. Then, this function takes our grayscale image and finds the value and (x, y) location of the pixel with the smallest and largest intensity values, respectively.

To break it down: minVal  contains the smallest pixel intensity value, maxVal  contains the largest pixel intensity value, minLoc  specifies the (x, y) coordinates of minVal, and maxLoc  specifies the (x, y) coordinates of maxLoc .

In this application, we’re only concerned with the pixel with the largest value, so we’ll grab that and draw a circle around the region on Line 20 and display it on Line 24.

The biggest problem with this method, and why I call it the susceptible method to find the brightest spot in an image, is that it’s extremely susceptible to noise.

A single pixel could dramatically throw off your results…

So how do we fix this?

Simple.

We’ll apply a Gaussian blurring through a pre-processing step.

The Slightly More Robust Method:

Let’s go ahead and check out how to do this:

Like I mentioned above, using cv2.minMaxLoc  without any pre-processing can leave you extremely susceptible to noise.

Instead, it’s better to first apply a Gaussian blur to the image to remove high frequency noise. This way, even pixels that have very large values (again, due to noise) will be averaged out by their neighbors.

On Line 28 we apply our Gaussian blur with the supplied radius from our command line argument.

Then we once again make a call to cv2.minMaxLoc  to find the brightest pixel in the image.

However, since we have applied a blurring pre-processing step, we’ve averaged all pixels together with the supplied radius  of each other. Doing this allows us to remove high frequency noise and leaves cv2.minMaxLoc  substantially less susceptible.

By using a larger radius we’ll be averaging over a larger neighborhood of pixels — thus mimicking larger regions of the image.

And by using a smaller radius we can average over smaller regions.

Determining the correct radius will heavily dependent on the application you are developing and the task you are trying to solve.

Results

Fire up a terminal and execute the following command:

If all goes well, you should see the following image:

Figure 1: Detecting the brightest area of a retinal image using our naive and robust methods. The results are good and look quite similar.

Figure 1: Detecting the brightest area of a retinal image using our naive and robust methods. The results are good and look quite similar.

On the left we have the susceptible method using cv2.minMaxLoc  without any pre-processing and on the right we have the robust method.

But you’re probably looking at these images and saying, “Hey Adrian, they both detected the same region of the image!”

You’re right. They did.

But watch what happens when I add a single bright pixel to the top-center part of this image when you issue this command:

Your results should look something like:

Figure 2: Adding a single white pixel to the image has thrown off the results of cv2.minMaxLoc (left), but the robust method is still able to easily find the optic center.

Figure 2: Adding a single bright pixel to the image has thrown off the results of cv2.minMaxLoc without any pre-processing (left), but the robust method is still able to easily find the optic center (right).

Now, the naive cv2.minMaxLoc  method finds this white pixel. Let’s be clear. The function is working correctly. It is indeed finding the single brightest pixel in the entire image.

However, this really isn’t what we want.

We are interested in the brightest region of the image, which is the optic nerve center.

Luckily, by utilizing a Gaussian blur, we are able to average a neighborhood of pixels within a given radius, and thus discard the single bright pixel and narrow in on the optic center region without an issue.

Obviously, a big aspect of getting the robust method to work correctly is properly setting your radius   size. If your radius  size is too small, you won’t be able to find larger, brighter regions of the image.

But if you set the radius   size too large, then you’ll be detecting too large of regions, missing out on the smaller ones, leading to sub-par results.

Definitely spend some time playing with the radius  size and viewing the results.

Summary

In this blog post I showed you why it is critical to apply Gaussian blurring prior to finding the brightest spot in an image.

By applying a Gaussian blur, you are averaging the pixels within a given radius of each other together. Taking the average allows you to remove high frequency noise that would have otherwise thrown off the results of the cv2.minMaxLoc  function.

Be sure to explore appropriate values for the radius of Gaussian blur. If you take too small of a value, you’ll mitigate the effects of the average and miss out on the larger, brighter regions. But if your radius is too large, you won’t detect the small bright regions.

Downloads:

If you would like to download the code and images used in this post, please enter your email address in the form below. Not only will you get a .zip of the code, I’ll also send you a FREE 11-page Resource Guide on Computer Vision and Image Search Engines, including exclusive techniques that I don’t post on this blog! Sound good? If so, enter your email address and I’ll send you the code immediately!

, , , ,

53 Responses to Finding the Brightest Spot in an Image using Python and OpenCV

  1. Jeremy September 29, 2014 at 11:04 am #

    Hi Adrian,

    Nice tutorial. However I think there is a different approach (more similar to finding the brightest pixel) that may also work, without having to write your own method.

    Step 1: filter the image using a Gaussian or median filter (median is best for salt-and-pepper noise)

    Step 2: find the brightest pixel the less-robust way

    That said, I like your method better. However, I think that usually when people learn to find peaks, they have it drilled into them to filter first, for exactly this reason!

    • Adrian Rosebrock September 29, 2014 at 12:03 pm #

      Hi Jeremy, thank you for commenting. Great point — using a filter prior to finding the brightest pixel is a good idea. Given that this is an introductory post, I think using the Gaussian blur is a better idea and easier to understand. I’m going to go back and update the post.

      • Ahmed December 1, 2016 at 11:41 am #

        Hello Adrian, Great to see the post! I want to detect the hot point in my thermal Video. How can I get the exact temperature and is there any method to compare two videos according to the characteristics?
        Sorry to ask this, I am learning tutorials but a new one to Python. Thanks

        • Adrian Rosebrock December 5, 2016 at 1:49 pm #

          If you are using the same thermal sensor to capture the temperatures (and therefore know what temperatures of various color bands are) then yes, it would be possible. This solution would involve color thresholding.

  2. EmmaG November 22, 2014 at 9:19 am #

    Hey Adrian,
    Nice example ! I am working on something similar like draw circle only if the bright spot found.
    Else no circle.One way is to use threshold, if min_val < threshold then draw rectangle. But in my case i am not able to decide threshold values between 0-1.my min max values are something like 221462064.0 and 758624512.0 respectively.I want to work this for other images too.
    Can u show how can i do it or may be some other method to do it?

    • Adrian Rosebrock November 23, 2014 at 7:41 am #

      Hi Emma. You could always scale your values into the range [0, 1] first by dividing my the maximum value that occurs in your image. But not really wouldn’t be a fix. It seems like you are trying to accomplish some sort of adaptive thresholding based on the brightest parts of the image. Without seeing your images (and getting more details), I can’t really provide a solution to the problem.

  3. Azrael March 7, 2015 at 6:57 am #

    Hello Adrian,
    Thanks for the post.
    Can you tell me how to find out the darkest region in the image, but only within the circle(eye)?
    And do you have any thoughts on using kernels to find the darkest and brightest regions of the image? How would you do that?
    I believe using a kernel would greatly help in removing any errors.

    • Adrian Rosebrock March 7, 2015 at 7:15 am #

      Hi Azrael, to find the darkest region of the image simply take a look at the minVal and minLoc values. And to only find the regions within the actual eye, you just need to specify the ROI (Region of Interest) that you want to investigate — which is in this case the eye. Take a look at this blog post on OpenCV basics to learn how to crop the image. You can then take this cropped image and find the min/max values.

      Also, a Gaussian kernel (for blurring) has already been applied (Line 28) to the image prior to finding the min/max values. This helps reduce noise and improve results.

  4. Tuhin March 24, 2015 at 9:53 am #

    If I want to find the mean intensity of the brightest region of an image

    then how would I do that ??

    Thankx in advance

    • Adrian Rosebrock March 24, 2015 at 10:09 am #

      Hi Tuhin. If you want to find the mean intensity of the brightest region of the image, you could use cv2.minMaxLoc as I did in the example. Then you would extract an M x N pixel region surrounding the brightest region. And then call cv2.mean on that region — that will give you the mean intensity of the brightest region.

      • Tuhin March 24, 2015 at 10:40 am #

        How should I extract MxN region ?

        How to find the values of M an N?

        Thanx again!!

        • Adrian Rosebrock March 24, 2015 at 11:21 am #

          You need to determine the values of M and N yourself. For example, you could extract a 20 x 20 pixel region, a 10 x 10 pixel region, etc. That decision is entirely up to you. Take a look at this post to learn more about cropping and extracting regions from images. I would also suggest taking a look a my book, Practical Python and OpenCV. It will definitely help jumpstart your OpenCV education! Cheers.

  5. Tuhin March 24, 2015 at 11:29 am #

    Hey!! thankx a bunch!!!

  6. Miash July 16, 2015 at 5:20 am #

    Sorry to ask stupid question, because i’m a newbie in python and opencv…
    I would like to ask if the method mentioned above can be applied to a live feed video in the previous tutorial “Accessing the Raspberry Pi Camera with OpenCV and Python”.

    • Adrian Rosebrock July 16, 2015 at 6:27 am #

      It certainly can! You just need to update the Accessing Raspberry Pi Camera code, specifically the for loop where the frames are being accessed, to apply the techniques proposed in this post.

      • Vishal December 28, 2016 at 7:20 am #

        Hey Adrian. Could you please explain in detail on how to set this code up for a live video tracking ??

        • Adrian Rosebrock December 31, 2016 at 1:30 pm #

          It depends on what type of camera you are using (webcam or Raspberry Pi camera module), but the gist is that you should start with this blog post and then use it as a template to access your webcam. From there, detect the brightest region in each frame.

  7. vin August 14, 2015 at 6:23 pm #

    hi adrian!

    i understand why blurring works in this specific instance. would there be any instances where you simply filtered by size? (eg, find pixels above a certain value and then simply ignore anything less than N pixels).

    thanks!

    • Adrian Rosebrock August 15, 2015 at 6:27 am #

      Certainly! A great example is in this post on target detection. Notice how I ignore any regions of the image that are smaller than 25×25 pixels.

  8. Brian November 22, 2015 at 12:10 pm #

    Hi Adrian,
    I tried the above code verbatim but encountered the following error:
    AttributeError: ‘Nonetype’ object has no attribute ‘copy’

    Why not use: orig = image?

    Also, must the image be PNG format or will any other format work such as JPG, BMP, etc.?

    Thanks,
    -Brian

    • Adrian Rosebrock November 23, 2015 at 6:39 am #

      If you’re getting an error related to the image being None, then your image is not being properly loaded from disk via the cv2.imread function or the path supplied the cv2.imread is not valid. OpenCV comes with built-in support for reading BMP images, but you need to install the appropriate JPEG and PNG libraries for your system prior to compiling and installing OpenCV.

      • Vishal December 16, 2016 at 12:41 am #

        can you explain on how to remove debug this error now ??

        • Adrian Rosebrock December 18, 2016 at 8:47 am #

          What is your error?

  9. Brian November 22, 2015 at 2:37 pm #

    Adrian,
    Great tutorial!

    When I copied your code verbatim I encountered an error with image.copy(). I was able to get around it by simply replacing this line of code with: orig = image. I’m using OpenCV 3.0.0 so I’m not sure if that was the issue. I thought I should post this to help anyone else who might be having the same issue.

    Digging a little deeper, I didn’t quite understand the purpose of making a copy of the image. I commented out the image.copy lines of code completely and the program seems to work just fine. Can you add some detail as to what the image copy was for?

    One final note, I’d would highly recommend adding to this tutorial:
    cv2.imshow(“Gray”, gray)

    This certainly helped me to understand what was happening during the Gaussian blur process as the radius changes.

    Thanks again for the great tutorials!
    -Brian

    • Adrian Rosebrock November 23, 2015 at 6:36 am #

      The .copy() method is used to make a deep copy (rather than a shallow copy) of the image. This allows us to “draw” the circles on two separate images and display our results. If you’re using this code in an image processing pipeline, you can certainly leave it out.

  10. Angel John Babasa March 1, 2016 at 1:33 am #

    Hi! Is it possible to detect multiple bright spots in an image and find their pixel coordinates? thanks!

    • Adrian Rosebrock March 1, 2016 at 3:41 pm #

      Indeed, it is possible! I plan on covering it in a future blog post, but in the meantime, take a look at this tutorial with scikit-image.

      • TimTom April 16, 2016 at 8:02 pm #

        I’d be really interested in such a tutorial as well.

  11. YaddyVirus March 13, 2016 at 10:43 am #

    Hi Ardian! Nice tutorial there, really helpful tutorial. I am working on a project that requires a raspberry pi doing image processing and finding a traffic light. Once its been found, monitor it until it goes off, and as soon as it does, send appropriate commands to the Arduino(which controls motors). Now since at the moment I don’t have a RPi, I’m writing the code on my PC(Windows 8.1), the PC version of my code, detects a light from the frames captured from my Webcam, and when the light goes off, display a message on the screen, when it comes back on, display the corresponding message.
    I plan to convert the video captured from the webcam into greyscale and then finding the brightest spot(hopefully the light). Now can you please tell me how to display a message (and send command to Arduino too of course), based upon the detected status of the light?
    I’m new to Both OpenCV and Python, but I’ve been coding in other languages so thats not a problem. I’ve literally spent entire nights reading up the OpenCV documentation(I was initially writing the code in C++, but realized that I should switch to python as ultimately I have to use this on a RPi) and writing code. I’m in real need if help!
    Thanks!

    • Adrian Rosebrock March 13, 2016 at 11:11 am #

      Your project sounds very cooL! However, I have never done any Arduino-based development before, so I’m unfortunately not the right person to ask regarding this question. In the future, I’ll try to do more GPIO and Arduino posts that cover computer vision topics as well.

      • YaddyVirus March 13, 2016 at 3:47 pm #

        Okay fine, no problem. Anyways if not Arduino based, can you tell me how to display the corresponding message depending upon the status of the brightest spot(the light being on or off) simply in python?

        Thanks again for such a nice tutorial.

        • YaddyVirus March 13, 2016 at 4:16 pm #

          And yeah, is there any way to make a trackbar to control the Guassian blur radius? Like there are in C++ Visual Studio tutorials for OpenCV object detection based on color where they convert the image to HSV and then control the H,S and V values with trackbars until they get the required binary output in the resultant window. I’m thinking that controlling the Guassian blur with a trackbar would be a good idea as in my case I’m working with a live video feed from my webcam. What do you think?
          Thanks

  12. YaddyVirus March 13, 2016 at 5:14 pm #

    Hi Adrian! Sorry to harass you with so many comments, but I thought I’ll post back with my most recent experiment towards my project. Okay so I did a bit of modification to your code and got the bright spot detection to work from my webcam feed. I ran the test in a room brightly lit and detected LEDs of a spare webcam I had lying around. It was quite successful(just while testing with some extreme angles it detected the collar of my white shirt as the brightest spot). Any ways, since I have to do the actual detection in sunlight, will this method work? I mean I don’t want my robot to see any other “bright spots” other than the traffic light just before a race is about to start. I can’t experiment right now as its night here in world.
    Also, in my previous comment on my previous reply I thought that using a trackbar for applying Guassian blur would be better as it would give me more control over what gets detected. Can that be done? (For some reason I saw that that comment has disappeared.)

    • Adrian Rosebrock March 14, 2016 at 3:27 pm #

      All comments have to be manually approved by me, so please make sure you consolidate your comments whenever possible.

      To address your questions, yes, you can create track-bars to manually control the Gaussian blur radius. Please see the range-detector script for an example of using a trackbar.

      As for changing your lighting conditions, that is entirely dependent on your environment. You won’t know until you try. But in short, if there is a brighter spot in your image (brighter than the LEDs), then yes, the code will (incorrectly) detect the brighter object. In that case, you need to build extra logic into your code to prune the false-positive cases. I would suggest looking into color thresholding and contour properties (solidity, extent, aspect ratio, etc.) to prune these regions.

      • YaddyVirus March 15, 2016 at 9:31 am #

        Well thanks for the reply. So what if I convert the image to HSV instead of grayscale and then adjust the HSV values and apply hough transform to find circles? Once all circles are found, find the brightest circle using this method ( but this method only works for single channel images if I’m right.)

        Also, which language you suggest using for this project on the Raspberry Pi? C++ or Python? I’ve written the code for both languages (to the point where I can find out the required object by thresholding the image.)
        Thanks! You’re a great help buddy!

        • Adrian Rosebrock March 15, 2016 at 4:28 pm #

          If you can use the HSV color space to help filter your object, then yes, absolutely do that. You’ll likely need to experiment with this approach and see if you can filter each channel or use something like cv2.inRange to filter for a specific color. And yes, this method is intended for use on single channels, but if you can filter out extraneous regions and then only examine the Value channel (which will store the intensity of the color), then you can get around this problem.

          As for using Python or C++, I nearly always suggest prototyping in Python and then only coding in C++ if absolutely necessary.

          • YaddyVirus March 16, 2016 at 1:15 am #

            Very well, sounds like a plan. Now the only question that remains is , since I don’t know how to do this in either Python or C++, how do I display a message on the screen once the desired circle(the traffic light) goes off(or comes back on)?

            And yeah what to you mean by “coding in C++ if absolutely necessary”.

            Thanks!

          • Adrian Rosebrock March 16, 2016 at 8:10 am #

            What do you mean by “display a message on the screen”? You could use the print statement/function to write text to the terminal or you could use cv2.putText to draw a message on the actual image.

          • YaddyVirus March 18, 2016 at 8:15 am #

            Well displaying a message in the sense that as soon as the detected spot goes black in my binary image, show a message on the screen. What’s the statement for that?
            Thanks!

          • Adrian Rosebrock March 18, 2016 at 9:12 am #

            Please see my previous comment — use either the print statement/function or cv2.putText.

          • YaddyVirus March 18, 2016 at 5:25 pm #

            Yeah that print statement is fine.
            But there should be some condition checking statement there too, right? Like if (*as long as light is detected*). How do I check for the “visibility” of the light? Or, if no conditional check is required, where do I write the print statement?

            P.S – sorry I’m still new to Python, so I’m not much proficient with the basics yet, but I’m learning! All thanks to you!

          • Adrian Rosebrock March 19, 2016 at 9:14 am #

            Yes, a conditional is required to determine if there is sufficient light. You’ll need to program that logic yourself. Normally you would be looking for a large enough region in an image (based on width and height) that has the pixel intensity you’re looking for. If you’re still getting used to Python + OpenCV, you should absolutely work through Practical Python and OpenCV to help you get up to speed quickly.

  13. Sanira May 1, 2016 at 1:15 am #

    Hi Adrian ,

    Great tutorial..!! thanks a lot for sharing your knowledge. 🙂

    • Adrian Rosebrock May 1, 2016 at 3:07 pm #

      I’m glad you found it useful Sanira! 🙂

  14. Richie Close October 20, 2016 at 5:42 am #

    Hi Adrian

    Thanks for the tutorial – a great introduction to this area! I’ve a couple of questions.
    What does the radius value refer to? Is it pixels?
    What would be the best way to find the 6 (for example) brights area’s on an image? Could you set a brightness target threshold and search for that (along with the radius value)?

    Thanks again

    Richie

    • Adrian Rosebrock October 20, 2016 at 8:38 am #

      The radius is the size (in pixels) of the Gaussian blur. The smaller the radius, the less blur. The larger the radius, the more blur. As for finding multiple bright spots in an image I actually have a blog post scheduled for that. It will be published late October/early November so be sure to keep an eye out!

  15. kiran March 13, 2017 at 5:05 am #

    in the cursor control system,
    the first step was to have robust hand skin detection.
    the image frames from webcam i have converted to HSV and ycbcr colour space,applied morphological operations on individual hsv and ycbcr thresholded images.
    and combined both images.
    thing is that i need to detect only hand skin rest such as face and some body part need to be removed ,
    could you suggest me how to remove non- hand skin regions.

    • Adrian Rosebrock March 13, 2017 at 12:10 pm #

      I would suggest detecting the hand first. You might need to apply other methods than just color thresholding such as object detection. I would also suggest contour extraction and filtering only the hand regions.

  16. Saurav October 25, 2017 at 10:03 am #

    hey thanks for the tutorial but i want to know how will you issue the command in cmd like how will you give arguments.
    sorry for the question but i m a beginner.

  17. Moorthy March 18, 2018 at 5:41 am #

    i have one small help how to find the crop the brightest region on your code please help me .

    • Adrian Rosebrock March 19, 2018 at 5:14 pm #

      You can extract the region using basic NumPy array slicing.

Trackbacks/Pingbacks

  1. Detecting multiple bright spots in an image with Python and OpenCV - PyImageSearch - October 31, 2016

    […] Today’s blog post is a followup to a tutorial I did a couple of years ago on finding the brightest spot in an image. […]

Leave a Reply