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+.
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:
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:
# import the necessary packages
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required = True,
help = "Path to the image to be thresholded")
ap.add_argument("-t", "--threshold", type = int, default = 128,
help = "Threshold value")
args = vars(ap.parse_args())
# load the image and convert it to grayscale
image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# initialize the list of threshold methods
methods = [
# loop over the threshold methods
for (threshName, threshMethod) in methods:
# threshold the image and show it
(T, thresh) = cv2.threshold(gray, args["threshold"], 255, threshMethod)
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:
$ python threshold.py --image images/skateboard_decks.png --threshold 245
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:
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:
Not bad. What else can we do?
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:
Finally, we can invert this behavior as well using cv2.THRESH_TOZERO_INV :
Nothing to it!
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_BINARY, cv2.THRESH_BINARY_INV, cv2.THRESH_TRUNC, cv2.THRESH_TOZERO, cv2.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!