Thresholding: Simple Image Segmentation using OpenCV

thresholding_example

Tragic. Heartbreaking. Unbearable.

These are the three words that I would use to describe my past week.

About a week ago, a close childhood friend of mine passed away in a tragic car accident.

I went to elementary school and middle school with him. We spent our summers skateboarding on my driveway and the winters snowboarding and sledding in my backyard.

Since last week I’ve spent my time traveling and attending his viewing and service. Every moment has been utterly agonizing. I find it extremely hard to focus, my mind always wandering back to memories now over a decade old.

To be honest, it’s a wonder I am even writing this blog post at all.

But if there is anything I believe in, it’s that life should be celebrated. And there is no better form of celebration than the nostalgic memories of a loved one.

Back in middle school, him and I used to go through CCS Catalogs (yes, actual catalogs; they didn’t list all their products online, and even if they did, our internet was dialup and usage was moderated by parents).

We would fantasize about which skateboards we were going to buy next — or rather, which ones we were going to ask our parents to purchase for us as birthday presents.

Little memories like leafing through CCS Catalogs before, during, and after school bring a smile to my face. And they make the days a little easier to get through.

So in this post, I’m going to show how to perform basic image segmentation using Python and OpenCV.

And we’ll give it a little skateboarding theme as well, just to pay homage to a friend whose memory weighs heavy on my mind.

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+.

The cv2.threshold Function

Let’s start by taking a look at the cv2.threshold function signature:

(T, threshImage) = cv2.threshold(src, thresh, maxval, type)

The first parameter is our source image, or the image that we want to perform thresholding on. This image should be grayscale.

The second parameter, thresh, is the threshold value which is used to classify the pixel intensities in the grayscale image.

The third parameter, maxval, is the pixel value used if any given pixel in the image passes the thresh  test.

Finally, the fourth parameter is the thresholding method to be used. The type  value can be any of:

  • cv2.THRESH_BINARY
  • cv2.THRESH_BINARY_INV
  • cv2.THRESH_TRUNC
  • cv2.THRESH_TOZERO
  • cv2.THRESH_TOZERO_INV

Sound complicated? It’s not — I’ll show you examples for each of these thresholding types.

The cv2.threshold  then returns a tuple of two values. The first value, T , is the value that was used for the thresholding. In our case, this will be the same value as thresh  that we pass into the cv2.threshold  function.

The second value is our actual thresholded image.

Anyway, let’s go ahead and explore some code.

Thresholding: Simple Image Segmentation using OpenCV

There are many forms of image segmentation.

Clustering. Compression. Edge detection. Region-growing. Graph partitioning. Watershed. The list goes on.

But in the beginning, there was only the most basic type of image segmentation: thresholding.

Let’s discover how to perform simple image segmentation using OpenCV. Open up your favorite editor, create a file named threshold.py , and let’s get started:

We’ll start by importing the two packages that we’ll need, argparse  and cv2 on Lines 2 and 3.

From there, we’ll parse our command line arguments on Lines 6-11. Here we’ll require two parameters. The first, --image , is the path to the image that we want to threshold. The second, --threshold , is the threshold value that will be passed into the cv2.threshold  function.

From there, we’ll load the image from disk and convert it to grayscale on Lines 14 and 15. We convert to grayscale since cv2.threshold  expects a single channel image.

Lines 18-23 defines our list of thresholding methods.

We loop over our thresholding methods starting on Line 26.

From there, we apply the actual threshold method on Line 28. We pass our grayscale image as the first argument, the command line supplied threshold value as the second argument, 255 (white) as our value for when the threshold test passes as our third argument, and finally the threshold method itself as the final parameter.

Finally, the thresholded image is displayed on Lines 29 and 30.

Let’s look at some results. Open up your terminal, navigate to our code directory, and execute the following command:

In this example we are using a value of 245 for our threshold test. If a pixel in the input image passes the threshold test, it will have the value set to 255.

Now, let’s take a look at the results:

Figure 1: Applying cv2.threshold with cv2.THRESH_BINARY.

Figure 1: Applying cv2.threshold with cv2.THRESH_BINARY.

Using cv2.THRESH_BINARY  the skateboards are segmented to be black with a white background.

To invert the colors, just use cv2.THRESH_BINARY_INV , as seen below:

Figure 2: Applying cv2.threshold with cv2.THRESH_BINARY_INV.

Figure 2: Applying cv2.threshold with cv2.THRESH_BINARY_INV.

Not bad. What else can we do?

Figure 3: Applying cv2.threshold with cv2.THRESH_TRUNC.

Figure 3: Applying cv2.threshold with cv2.THRESH_TRUNC.

Using cv2.THRESH_TRUNC  leaves the pixel intensities as they are if the source pixel is not greater than the supplied threshold.

Then we have cv2.THRESH_TOZERO  which sets the source pixel to zero if the source pixel is not greater than the supplied threshold:

Figure 4: Applying cv2.threshold with cv2.THRESH_TOZERO.

Figure 4: Applying cv2.threshold with cv2.THRESH_TOZERO.

Finally, we can invert this behavior as well using cv2.THRESH_TOZERO_INV :

Figure 5: Applying cv2.threshold with cv2.THRESH_TOZERO_INV.

Figure 5: Applying cv2.threshold with cv2.THRESH_TOZERO_INV.

Nothing to it!

Summary

In this blog post I showed you how to perform the most basic form of image segmentation: thresholding.

To perform thresholding we utilized the cv2.threshold  function.

OpenCV provides us with five basic thresholding methods, including:  cv2.THRESH_BINARYcv2.THRESH_BINARY_INVcv2.THRESH_TRUNCcv2.THRESH_TOZEROcv2.THRESH_TOZERO_INV .

Most importantly, be sure to play around with the thresh  value as it will give different results depending on what value you supply.

In future posts, I’ll show you how to automatically determine the threshold value, no parameter tuning required!

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 17-page Resource Guide on Computer Vision, OpenCV, and Deep Learning. Inside you'll find my hand-picked tutorials, books, courses, and libraries to help you master CV and DL! Sound good? If so, enter your email address and I’ll send you the code immediately!

, , ,

24 Responses to Thresholding: Simple Image Segmentation using OpenCV

  1. Juan Diego September 12, 2014 at 11:13 am #

    This is great content. I’m already waiting for the follow up of the document scanner, specially the preprocessing for OCR to eliminate defects and highlights.
    Congrats,

  2. priya October 6, 2015 at 2:04 pm #

    I cannot execute it ! The threshold function has different parameters !
    I am using open cv2.4 on py 2.7

    • Adrian Rosebrock October 7, 2015 at 6:31 am #

      Hi Priya: This tutorial was designed for OpenCV 2.4 and Python 2.7. Please make sure you download the code at the bottom of this post and give it a try.

  3. karthik October 6, 2015 at 11:53 pm #

    sir can u post leaf colour detection coding

    • Adrian Rosebrock October 7, 2015 at 6:29 am #

      Hey Karthik — do you have any examples of leaf datasets that you are working with?

  4. luthfi January 5, 2016 at 6:30 am #

    Hi Adrian, i have question, how can i get the coordinates of the black pixel after i invert it?

    • Adrian Rosebrock January 5, 2016 at 6:42 am #

      Can you elaborate more on what you mean by getting the “coordinates of a black pixel after I invert it”? I’m not sure what you mean.

  5. luthfi January 5, 2016 at 7:43 am #

    Ok for example i have an image with size (j,i) 256×256 pixel, after convert it to binary, then invert it using cv2.THRESH_TOZERO_INV, i have white background and some black pixels

    what i want to know is in which (j,i) is that black pixels?, sorry my bad english…

    • Adrian Rosebrock January 5, 2016 at 1:57 pm #

      If you want to get the (x, y)-coordinates of the pixels that are black, I would use the np.where function. For example: np.where(mask == 0). You can then transform this into your coordinates.

      • luthfi January 6, 2016 at 1:37 am #

        ok adrian, i will try it, thanks

  6. Kavi November 15, 2016 at 11:32 pm #

    Hii Adriyan, this is great can u explain about how to detect the barcode alone in the given image using any image processing..???

  7. prashant kumar February 6, 2017 at 1:55 pm #

    hi sir , could you please list all the pages in the footer so that we can directly to any page without going through the process of clicking next /previous

    • Adrian Rosebrock February 7, 2017 at 9:05 am #

      There are way too many blog posts on the PyImageSearch blog to list them out entirely, but I will consider creating curated lists specific to topics.

  8. Zartash September 26, 2017 at 2:31 am #

    Good Morning Sir,I am working on my thesis “Apple Yield Estimation using UAV” and in this my first is pixel classification. Can you please guide me what i am going to do in this step. please guide me I am doing mscs in computer vision.

  9. caleyjag September 28, 2017 at 6:02 pm #

    Is it fair to call this segmentation? We are doing the thresholding but as far as I can see we aren’t making the jump to separating out and tagging objects associated with the individual skateboards. Am I correct? (Sorry, new to python and OpenCV).

    • Adrian Rosebrock October 2, 2017 at 10:27 am #

      Yes, thresholding is a type of image segmentation. We are segmenting objects but we do not know what the objects are. To do this we would need to perform object detection.

      If you’re new to the world of computer vision and OpenCV, I would highly suggest you take a look at my book, Practical Python and OpenCV. This book is intended for readers who are eager to learn the fundamentals as quickly as possible.

  10. Sowmya August 17, 2018 at 3:25 am #

    Hello sir,
    But this segmentation code is not as perfect for real time images. For example, super market shelve image which contains products. Can you suggest me any remedy to overcome this problem.

    • Adrian Rosebrock August 17, 2018 at 7:13 am #

      If you’re looking for that advanced level of segmentation you should read up on Mask R-CNNs, UNet, and other deep learning-based segmentation algorithms. Simple image processing is not going to solve complex situations like segmenting products on a supermarket shelf.

  11. Mandowara Ankita December 4, 2018 at 1:42 am #

    Hi everyone!

    Can this approach be used for images having different color fields which depict harvested and bare lands..If not, suggest an approach

    • Adrian Rosebrock December 4, 2018 at 9:40 am #

      Potentially, but if you’re looking for a more robust approach you may want to consider training your own semantic segmentation network.

  12. tamara February 12, 2019 at 7:14 am #

    can we apply this threshold technique in aerial images semantic segmentation task for classify each pixel if its belong to road class or non-road class? and in case yes do you have any useful resources to write this kind of code?
    thank you in advance

    • Adrian Rosebrock February 14, 2019 at 1:18 pm #

      No, basic thresholding would not work well here. I would recommend semantic segmentation instead.

Leave a Reply

[email]
[email]