Title: OpenCV and Python Color Detection - PyImageSearch

URL Source: https://pyimagesearch.com/2014/08/04/opencv-python-color-detection/

Published Time: 2014-08-04T14:00:30+00:00

Markdown Content:
Last updated on July 9, 2021.

![Image 1](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201000%20591'%3E%3C/svg%3E)

So, here I am. Riding the Amtrak 158 train, coming home after a long business trip.

It’s hot. The AC is _barely_ working. A baby is screaming right next to me while the accompanying mother looks forlornly out the window, clearly questioning whether or not having a child was the right life decision.

And to top it all off, **_the Wi-Fi doesn’t work._**

Luckily, I brought along my Game Boy and collection of Pokemon games.

As I slid my trusty Blue version into my Game Boy, I thought to myself, instead of battling Gary Oak for the thousandth time, maybe I can do a little computer vision.

Honestly, wouldn’t it be really cool to be able to **segment** each of the game cartridges _using nothing but color_?

Grab yourself a nice cool glass of water to combat the failed AC and a pair of ear plugs to block out the wailing child. Because in this post I’ll show you how to use OpenCV and Python to perform color detection.

*   **Update July 2021:** Added new section on how to improve color detection accuracy using color matching cards and histogram matching.

![Image 2](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20128%20128'%3E%3C/svg%3E)

#### Looking for the source code to this post?

[Jump Right To The Downloads Section](#download-the-code)

**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 go ahead and get this started.

Open up your favorite editor and create a file named `detect_color.py` :

\# import the necessary packages
import numpy as np
import argparse
import cv2

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add\_argument("-i", "--image", help = "path to the image")
args = vars(ap.parse\_args())

# load the image
image = cv2.imread(args\["image"\])

We’ll start by importing our necessary packages on **Lines 2-4**. We’ll use NumPy for numerical processing, `argparse` to parse our command line arguments, and `cv2` for our OpenCV bindings.

**Lines 7-9** then handle parsing our command line arguments. We’ll need just a single switch, `--image` , which is the path to where our image resides on disk.

Then, on **Line 12**, we load our image off disk.

Now, here comes the interesting part.

We want to be able to detect each of the Game Boy cartridges in the image. That means we’ll have to recognize **red**, **blue**, **yellow**, and **gray** colors in the image.

Let’s go ahead and define this list of colors:

\# define the list of boundaries
boundaries = \[
	(\[17, 15, 100\], \[50, 56, 200\]),
	(\[86, 31, 4\], \[220, 88, 50\]),
	(\[25, 146, 190\], \[62, 174, 250\]),
	(\[103, 86, 65\], \[145, 133, 128\])
\]

All we are doing here is defining a list of `boundaries` in the RGB color space (or rather, BGR, since OpenCV represents images as NumPy arrays in reverse order), where each entry in the list is a tuple with two values: a list of _lower_ limits and a list of _upper_ limits.

For example, let’s take a look at the tuple `([17, 15, 100], [50, 56, 200])` .

Here, we are saying that all pixels in our image that have a _R >= 100_, _B >= 15_, and _G >= 17_ along with _R <= 200_, _B <= 56_, and _G <= 50_ will be considered **red**.

Now that we have our list of boundaries, we can use the `cv2.inRange` function to perform the actual color detection.

Let’s take a look:

\# loop over the boundaries
for (lower, upper) in boundaries:
	# create NumPy arrays from the boundaries
	lower = np.array(lower, dtype = "uint8")
	upper = np.array(upper, dtype = "uint8")

	# find the colors within the specified boundaries and apply
	# the mask
	mask = cv2.inRange(image, lower, upper)
	output = cv2.bitwise\_and(image, image, mask = mask)

	# show the images
	cv2.imshow("images", np.hstack(\[image, output\]))
	cv2.waitKey(0)

We start looping over our upper and lower `boundaries` on **Line 23**, then convert the upper and lower limits to NumPy arrays on **Line 25 and 26**. These two lines seem like they can be omitted, but when you are working with OpenCV Python bindings, OpenCV _expects_ these limits to be NumPy arrays. Furthermore, since these are pixel values that fall within the range _\[0, 256\]_ we can use the unsigned 8-bit integer data type.

To perform the actual color detection using OpenCV, take a look at **Line 29** where we use the `cv2.inRange` function.

The `cv2.inRange` function expects three arguments: the first is the `image` were we are going to perform color detection, the second is the `lower` limit of the color you want to detect, and the third argument is the `upper` limit of the color you want to detect.

After calling `cv2.inRange`, a binary mask is returned, where white pixels (255) represent pixels that fall into the upper and lower limit range and black pixels (0) do not.

_Note: We are performing color detection in the RGB color space. But you can easily do this in the HSV or L\*a\*b\* color space as well. You would simply need to adjust your upper and lower limits to the respective color space._

To create the output image, we apply our mask on **Line 31**. This line simply makes a call to `cv2.bitwise_and`, showing only pixels in the `image` that have a corresponding white (255) value in the `mask`.

Finally, our output images are displayed on **Lines 34 and 35**.

Not bad. Only 35 lines of code, and the vast majority is imports, argument parsing, and comments.

Let’s go ahead and run our script:

$ python detect\_color.py --image pokemon\_games.png

If your environment is configured correctly (meaning you have OpenCV with Python bindings installed), you should see this as your output image:

![Image 3: Figure 1: Detecting the color red in an image using OpenCV and Python.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201000%20591'%3E%3C/svg%3E)

**Figure 1:** Detecting the color red in an image using OpenCV and Python.

As you can see, the Red Pokemon cartridge is easily detected!

Now let’s try the blue one:

![Image 4: Figure 2: Detecting the color blue in an image using OpenCV and Python.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201000%20591'%3E%3C/svg%3E)

**Figure 2:** Detecting the color blue in an image using OpenCV and Python.

Nope, no problem there!

And a similar story for Yellow version:

![Image 5: Figure 3: Detecting the color yellow in an image using OpenCV and Python.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201000%20591'%3E%3C/svg%3E)

**Figure 3:** Detecting the color yellow in an image using OpenCV and Python.

Lastly, the outline of the gray Game Boy cartridge is also found:

![Image 6: Figure 4: Detecting gray in an image using OpenCV and Python.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201000%20591'%3E%3C/svg%3E)

**Figure 4:** Detecting gray in an image using OpenCV and Python.

Improving color detection accuracy with color correction
--------------------------------------------------------

![Image 7](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20700%20450'%3E%3C/svg%3E)

**Figure 5:** Pantone’s color matching card.

In this tutorial, you learned how to perform color correction by hard-coding lower and upper RGB color ranges.

Let’s suppose you are given a dataset of 1,000 images and are told to find all “red” objects with RGB values in the range _(17, 15, 100)_ and _(50, 56, 200),_ respectively.

If your entire dataset of images were captured in controlled lighting conditions with the _same lighting_ for each image, then this won’t be a hard task — you can use the hard-coded RGB values mentioned above.

But … let’s say your dataset of images _were not_ captured in controlled lighting conditions. Some were captured using fluorescent lighting, others were taken outside when it was bright and sunny, while others were captured when it was dark and dreary.

[The point here is that lighting conditions have a huge impact on output pixel values](https://pyimagesearch.com/2021/04/28/opencv-color-spaces-cv2-cvtcolor/).

**Colors can look very different under varying illumination, and when that happens, your hard-coded lower and upper RGB ranges will fail.**

One potential solution is to use a different color space which does a better job of mimicking how humans perceive color — the HSV and L\*a\*b\* color spaces are good choices here.

An even better alternative would be to use a **color correction card**. You place a card (like that in **Figure 5** above) in the scene containing the objects we’re capturing, and then you post-process all these images by:

1.  Detecting the color correction card
2.  Determining the color block region
3.  Performing histogram matching to transfer the color space from one image to another

In that manner you can help ensure a consistent color across all images, even though they may have been captured under different lighting conditions.

To learn more about this technique, I suggest reading the following two tutorials:

1.  [_Histogram matching with OpenCV, scikit-image, and Python_](https://pyimagesearch.com/2021/02/08/histogram-matching-with-opencv-scikit-image-and-python/)
2.  [_Automatic color correction with OpenCV and Python_](https://pyimagesearch.com/2021/02/15/automatic-color-correction-with-opencv-and-python/)

### What's next? We recommend [PyImageSearch University](https://pyimagesearch.com/pyimagesearch-university/?utm_source=blogPost&utm_medium=bottomBanner&utm_campaign=What%27s%20next%3F%20I%20recommend).

**Course information:**  
84 total classes • 114+ hours of on-demand code walkthrough videos • Last updated: February 2024  
★★★★★ 4.84 (128 Ratings) • 16,000+ Students Enrolled

**I strongly believe that if you had the right teacher you could _master_ computer vision and deep learning.**

Do you think learning computer vision and deep learning has to be time-consuming, overwhelming, and complicated? Or has to involve complex mathematics and equations? Or requires a degree in computer science?

That’s _not_ the case.

All you need to master computer vision and deep learning is for someone to explain things to you in _simple, intuitive_ terms. _And that’s exactly what I do_. My mission is to change education and how complex Artificial Intelligence topics are taught.

If you're serious about learning computer vision, your next stop should be PyImageSearch University, the most comprehensive computer vision, deep learning, and OpenCV course online today. Here you’ll learn how to _successfully_ and _confidently_ apply computer vision to your work, research, and projects. Join me in computer vision mastery.

**Inside PyImageSearch University you'll find:**

*   ✓ **84 courses** on essential computer vision, deep learning, and OpenCV topics
*   ✓ **84 Certificates** of Completion
*   ✓ **114+ hours** of on-demand video
*   ✓ **Brand new courses released _regularly_**, ensuring you can keep up with state-of-the-art techniques
*   ✓ **Pre-configured Jupyter Notebooks in Google Colab**
*   ✓ Run all code examples in your web browser — works on Windows, macOS, and Linux (no dev environment configuration required!)
*   ✓ Access to **centralized code repos for _all_ 536+ tutorials** on PyImageSearch
*   ✓ **Easy one-click downloads** for code, datasets, pre-trained models, etc.
*   ✓ **Access** on mobile, laptop, desktop, etc.

[Click here to join PyImageSearch University](https://pyimagesearch.com/pyimagesearch-university/?utm_source=blogPost&utm_medium=bottomBanner&utm_campaign=What%27s%20next%3F%20I%20recommend)

Summary
-------

In this blog post I showed you how to perform color detection using OpenCV and Python.

To detect colors in images, the first thing you need to do is define the _upper_ and _lower_ limits for your pixel values.

Once you have defined your upper and lower limits, you then make a call to the `cv2.inRange` method which returns a mask, specifying which pixels fall into your specified upper and lower range.

Finally, now that you have the mask, you can apply it to your image using the `cv2.bitwise_and` function.

My train is just a few stops away from home, so I better wrap this post up. I hope you found it useful!

And if you have any questions, as always, feel free to leave a comment or [shoot me a message](https://pyimagesearch.com/contact/).

![Image 8](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20410%20567'%3E%3C/svg%3E)

#### Download the Source Code and FREE 17-page Resource Guide

Enter your email address below to get a .zip of the code and 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!