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.
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 , B , and G 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:
As you can see, the Red Pokemon cartridge is easily detected!
Now let’s try the blue one:
Nope, no problem there!
And a similar story for Yellow version:
Lastly, the outline of the gray Game Boy cartridge is also found:
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.
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:
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:
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:
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.
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!
Hi there, I’m Adrian Rosebrock, PhD. All too often I see developers, students, and researchers wasting their time, studying the wrong things, and generally struggling to get started with Computer Vision, Deep Learning, and OpenCV. I created this website to show you what I believe is the best possible way to get your start.
this shows up when irun the code
…
cv2.error: arithm.cpp:1947: error: (-209) The lower bounary is neither an array of the same size and same type as src, nor a scalar in function cv::inRange
“
Hi Sultan — you might not have specified a proper path to your input image file. Try specifying the right path and let me know if it works.
Hi Adrian, the post is really great and elegant just one thing I keep running into the same problem as sultan and was wondering if there is alternate method to show the path of the picture in the folder Regards
Hey Dewald — can you clarify what you mean by “alternate method”? Can you tell me where exactly do we have to specify the path to the image?Hi Adrian how do we set that lower and upper limits I used colour palate to find lightest and darkest RGB values for each colour and written in code in BGR sequence but it detects Nothing, But all your four ranges are working perfectly fine. Please let me know how set them for other colours
How much is this efficient to segment pictures according to their colors with other famous existing segmentation algorithms ?
The cv2.inRange function is extremely efficient, but has the caveat that you need to know the pixel intensity boundaries prior to applying it to the image. Methods such as Otsu’s thresholding and Adaptive thresholding can be used to help determine the threshold value in traditional thresholding.
We are trying to find the ratio of red and green glowing armbands from a video stream captured by a RasPi. The images of an outdoor square where the lighting conditions will be changing through an evening. Can you suggest a good method for picking out the red and green bands?
I’ve been playing with your sample code and I’m a bit stuck figuring out the ranges. I am clearly not defining them properly as the masked images come out barely showing the red and green.
Ultimately the output needs to be the ratio of green:red to crowd-control a pong like game.
Thanks for the great sample code and any advice you can offer.
I think this post on ball tracking will really help with your arm band project. Inside that post I make reference to a range-detector script inside the imutils package that will help you determine the appropriate color ranges for tracking.
where is it. I want range-detector for perticulat area not for perticular pixel. You can find it on the imutils GitHub.hey thanks for the instant reply Adrin
you are great. Actually I want to know the lower limit and upper limit of any color from the live webcam. And one more thing
I want to know minimum and maximum hsv value from selected portion(using mouser cursor with click) from the image.
Hey Ankit — please see my previous reply. You need to use the range-detector script to determine your upper and lower limits. It’s hard to define thresholds that will always work, mainly because colors may have different HSV values depending on the lighting conditions of your environment.
Ok. Thank you.
Last question, if I may: do you think that segmenting an image according to its colors is a good idea to use in order to recolor the image with given desired colors for each segment ? Could this give a good result ?
Regards from Begueradj
Great question! The answer is yes, absolutely. This post on color transfer between images could be dramatically improved by performing the local color transfer within each individual segment rather than globally. The caveat is that you’ll have to “match” which segments are the most similar for the source and target image.
Hi Adrian, Great work. I’ve seen several implementations but yours is the most elegant I encountered so far. One thing though, if you wanted just to get a boolean flag like blue_is_present or orange_is_present would you find some way yo compare the current array with the previous ones or go with object tracking instead?
If you wanted to have a boolean flag indicating whether or not a color is present, I would loop over the color ranges, generate a mask for each one, and then count the number of non-zero pixels in the mask using cv2.countNonZero . If the number if non-zero pixels is above a given threshold, then you could say that a given color is present. I hope that helps!
I Adrian, Yes, it did. Thank you.Hi Adrian, I am trying to learn color detection through this guide, but i can’t understand how did you determine the boundaries, can you point me out a good reference for this one? Thanks.
Basically, I end up opening the image in Photoshop (or a similar program) and examining the pixel intensity range. Any simple image editing software can help you out with that one!
Thank you for the reply, Actually I’m using ColorPix.exe to determine the RGB value of the color, but I don’t understand how can I set the boundaries. For example, R = 255, G = 37, B = 37, this is a shade of RED i want to reference with, and i want to make a range (lower and upper), now I’m stuck i don’t know how to determine the lower or upper. I tried subtracting 20 to RGB for the lower, and add 20 to upper, but it doesn’t detect the color.
If you are trying to define “shades” of a color, it’s actually a lot easier to use the HSV color space. I would define your colors in HSV using your color picker tool, and then convert those colors back to RGB.
Hello Adrian . When trying to complete this exercise appears to me the following error: mask = cv2.inRange (image , lower, upper ) error : (209 ) the lower bounary is neither an array of the same size and same type the src , not in scalar function cv :: inRange … I’ve given round and round but still with the same error .
Yours faithfully ,
Francisco
Hi Franciso, I have actually heard about this error from one or two other PyImageSearch readers as well. The code executes without a hitch on my machine and the PyImageSearch virtual machine. The first thing I would do is make sure the path to your image is correct. You supply the image path via command line argument. If after ensuring that your path is correct, can you let me know which version of Python, OpenCV, and NumPy you are using? And it would probably help to know which OS you are using as well.
On my Ubuntu virtual env I compile without any problem too, but when I port over to the RasPi3, I get this same error as above?
Do you know what could be causing this? The image is in the working directory, so I doubt it’s a path issue?
Also I’ve tried running in Python3, with no success but all else in the RasPi virtualEnv is compiling in Python 2.7.9, so I guess I’m forced to go with Python 2 for now.
Will see if I can find out what the issue with Python 3 is.
Hi Tony — I still think this is a path issue. Try hardcoding the path to the image into cv2.imread to verify this.
hello adrian . I have not yet tried the command line because when I click the f5 in python idle gives me error soon . already read on another website that the error may be due to this: np.uint8 instead dtype : ” uint8 ” . my version of python is 2.7.9 . opencv and numpy is recent . Greetings
I would definitely try to execute the script via command line instead of IDLE and see if you still get the error. Like I said, the problem could potentially be that the image is not being read of disk properly. Inspect the returned value of cv2.imread and if the value is None , then you’ll know that the image was not read properly. As for the versions of OpenCV and NumPy, it would be really beneficial if you could give the exact version numbers rather than just “recent”.
Hello , just the night I will try to run the program from the command line and give the versions of opencv and numpy . thank immense availability , you have had . another question : I’m tempted to buy the premium course bundle but at the moment I do not have to finance it. this course will be available in the near future or has to date not be available ? greetings
Hey Francisco, the PyImageSearch Gurus is set to open to the public in August, which is still months away. In the meantime, I definitely recommend that you pick up a copy of Practical Python and OpenCV so you can start to become familiar with OpenCV + Python. It’s definitely the best way to learn computer vision!
Francisco, I was having this same error. I realized that I was using an array with 3 channels like:
lower = np.array([1,3,3]) For a image that was in black and white. Once I only created an array for one channel like this:
lower = np.array([3]) Everything worked fine!
Thanks for the clarification Nick! If you’re only using a black and white image, I would suggest using the cv2.threshold function instead.
Does it work for video stream as well? video stream off Pi camera?Hey Mobin — if you want to use the Raspberry Pi camera, I would suggest reading this post on accessing the Raspberry Pi camera. It will only take a few small modifications to this code to take an input image from the Raspberry Pi.
Hey Adrian! First of all, great work on the blog and the tutorials, I really appreciate your work. This has already helped me a lot with what I am trying to achieve 🙂 Marc already wanted to know, whether there is a way of determining the boundaries from a given colour. In my application, I take a photo of lego bricks with a raspberry pi and want to determine the bricks’ positions inside a grid and what colour they are. I know which brick colours there are in the image, but I have to account for bad lighting (or at least differing lighting conditions). Do you think I could get satisfactory results using the shown approach by first automatically adjusting contrast/lighting and then calculating the boundaries in hsv with some fixed value? Thanks 🙂
Hey Iris, in general I think you are on the right track. But I would strongly encouraging you to work with your lighting conditions prior to writing a single line of code. The success of most computer vision applications starts before a single line of code is written — it all starts with the quality of your images. The higher quality they are, the easier they are to work with.
is it possible to use this through a video?It certainly is! You’ll need to make use of the cv2.VideoCapture function to obtain access to the webcam. I actually detail exactly how to perform color based object tracking inside Practical Python and OpenCV + Case Studies. Definitely take a look!
thank you Adrian. this will be very helpful. can i ask, if you have another one example for shape detection, like arrows or any other shapes?? i just think, that i might easily understand youre example. than the others in the internet.
If you’re interested in doing other types of shape detection, contours are always a good start. I use contours to recognize square targets in image — the same methodology can be used to identify other shapes. Otherwise, you might be interested in shape descriptors such as Hu Moments or Zernike Moments.
Hey adrian,
Thanks for the amazing tutorials .
I just have a small question. What would be the tuple value for green color? in order to only detect green color from an image. Thank you in advance.
Pure green in the RGB color space is (0, 255, 0). However, you’ll need to play with these values a bit to make them detect the particular shade of green you are interested. An alternative is to use the HSV color space where you may find it easier to define the color ranges.
Once again Adrian you grabbed my attention. Now its time to buy the book today. Please keep up the good work, and give us more.
Hey there! Code works perfectly fine, but i seem to be having a rather slow fps rate(~2fps). Any solution to make it go faster? Thank you
All you need to do now is maintain a mask from the output of Line 30. Keep updating the mask for each color, and then when you run out color boundaries, you’ll have your final solution!
Hey, Adrian. Good blog! The fact that I will be able to learn for free through your blog is just exceptional! You are my inspiration! I want to ask something. I want to track two objects in a video. The two objects can change colours between green and orange (those two colours only). Example, if Object1 is green, there will be print out ‘Object1 = On” and at the same time if Object2 is orange, there will be print out ‘Object2 = Off’. I am thinking of a way of doing this that is by slicing parts of the frame into two to focus on those two things differently and applying the cv2.range to both of the sliced frame. If the cv2.range detect green it will returns mask (means there is white pixels inside the sliced frame), so, from that the program will know if the object is green or orange. But how can I tell the program to check if the returns contain mask or not? Or do you have any other better workaround? Thanks in advance! Proud to say to anyone that I am learning OpenCV from you blog 🙂
Just read your post about tracking object movement. I think I can use the function if len(cnts) > 0 to detect if there is any white pixels in the mask. Is it possible? Or you have anymore efficient way?
if cv2.countNonZero(mask) > 0: # do something
It sounds like you’re on the right track. I would use this post as a starting point, and then modify it so you can track both colors.
Hello Adrian, Thanks for this tutorial. Similar to a few other users here, I am also getting the following error: “The lower bounary is neither an array of the same size and same type as src, nor a scalar”. I am using python 2.7.10 and what I believe is OpenCV 2.4.11-7 on Windows through Python(x,y) Idle. Is my set up ok for running this code? I like Python(x,y) because of all the modules it comes with in one quick install. I have been troubleshooting for a while but I can’t figure out what is wrong. I really just want to segment an image by color – do you know of any other simple methods to do this? Thank you – love the site.
Your Windows + OpenCV installation should be fine. As for your error message, can you double check that the image was loaded properly from disk using cv2.imread ? If you do:
image = cv2.imread(args["image"]) print(image)
And image is None , then you’ll know that your image was not loaded from disk properly and is causing the error. EDIT: I have been able to replicate the error on my machine. The error is indeed due to a valid image path not being supplied to the cv2.imread function.
Hey Adrian, thank you for checking this out for me. Indeed you are correct and I am receiving NONE when I try to print the image with opencv commands. After troubleshooting the imread command for a bit, I tried loading the image with scipy instead then continuing the work with cv2 and this works! From a bit of internet browsing, it seems like others who had this problem fixed it by working around it like I did or updating to a newer version of openCV. Thanks for the help.
impath = 'C:\\Users\\naresh\\Desktop\\pokemon_games.jpg' image = cv2.imread(impath) cv2.imshow('pokemon_games', image) print(image)I don’t know why \\ this worked.
Both OSX and Linux systems use “/” as the path separator. However, Windows uses the “\” path separator. But in most programming languages you need to “escape” the “\” character, leading to “\\”.
Hi Adrian, i want to detect the colours using webcam what changes i have to do in above code.Works great. But if i want to separate the image into regions of different colors without knowing what colors will be in the image beforehand, how do I do it? For example, if I have an image that contains just three colors(I don’t know what they are), and want to draw contour around the images how do I do it? Thanks a lot. PS. I saw your other post on labeling different colors in an image but will that work if some of the colored region is inside other region?
You’ll need to segment out each color individually and then label it. I would suggest starting with this post on color quantization with k-means to help segment out the colors.
Hello Adrian, how can i show the original and result images on two different windows ?cv2.imshow("Original", image) cv2.imshow("Result", output)
This works brilliantly! How would I modify the code so it takes multiple images instead of one, and processes them all with one execution of the script? Thank you!
The only piece of code that needs to change is to apply a “loop” that loops over an input set of images. Take a look at how I apply the list_images function in this blog post and it will give you a good idea on how to process multiple images.
Hello Adrian,
Thanks for the amazing tutorials .
I just have a small question :
i want to detect a Picture of apps on my Smartphone Screen: exactly I have a Webcam and i have to detect apps on my Smartphone Screen und recognize where they are.
And i want to define the Coordinate of this .
how can i do it ? please help me 🙂
(I use python 3 and opencv3 with Raspberry pi )
i am copy and paste your program in my desk sir , and then i get an eror , can you help me resolve this ? OpenCV Error: Sizes of input arguments do not match (The lower bounary is neither an array of the same size and same type as src, nor a scalar) in inRange …
mask = cv2.inRange(image, lower, upper)
cv2.error: /home/pi/opencv-3.0.0/modules/core/src/arithm.cpp:5696: error: (-209) The lower bounary is neither an array of the same size and same type as src, nor a scalar in function inRange
Please see my reply to “Francisco” above. The error is 99% likely due to the path passed to cv2.imread being invalid.
If you are absolutely, 100% sure that your path to the image is valid, then OpenCV likely cannot read the image type you are trying to pass in. Again, I’m pretty sure that your image paths are incorrect. But if they are, try placing a print(image) call right after cv2.imread . If you get None back AND your image path is valid, then OpenCV cannot read your image type.
Hi Adrian, thanks for this amazing tutorial! I’m trying to use opencv to filter text from an image (as a pre-processing stage before performing OCR) I wasn’t able to determine colors range for a text color that has some kind of gradient, using range-detector wasn’t really helpful in that case any other tools or tips you can give? my image is: http://imgur.com/9cwuu8E
Yes, both simple and adaptive wasn’t good enough to get tesseract to read the text, I was trying SWT but no luck there too. Still looking for the right way to make it easier for OCR to read it. Thanks !
SWT is a great algorithm, although I’m unaware of a good Python implementation. Which version were you using? Also, I still think simple thresholding can be used one. The first threshold can be used to detect light text against dark backgrounds. And a second round of thresholding can be used to detect dark text against light backgrounds. Furthermore, since this is a scoreboard, you “know” where in the ROI the text will be, allowing you to focus on the regions of the image that are most likely to contain text.
Hi Adrian, How can I know the result of the colour is detected without looking at the image window? Is there any programmable API from cv2 to return a boolean to tell me blue is detected ?
if cv2.countNonZero(mask): # do processing hereAssuming that mask contains your detected blue pixels. I hope that helps! Thanks Adrian
Hi Adrian,
Thank you for the great blog! I am learning Python and openCV at the same time. Because I am just learning, I am using an editor to help me with my Python syntax. Running you code within the IDE produces the same error than many have mentioned above:
“OpenCV Error: Sizes of input arguments do not match………………”
As you have correctly pointed out already it is a path issue to the image. I can run the code in terminal and it runs perfectly. The question I have is this, can I add a line of code that defines specifically the path so that I can run and then edit the code in my IDE? Thanks for your time!! Scott
Are you executing your Python script from within your IDE? Or via command line argument? If you’re using an IDE, I normally recommend using the IDE to write the code — but then use the terminal to execute the code so you have better control over the command line arguments.
hello sir I m not Able to detect red color and blue color.i hv changed range also.still threshold image shows black only
Defining the valid color ranges can be pretty tricky, especially if you’re just getting started. I would start by using the range-detector script in the imutils package. This will help you tune the ranges.
Is there any way to set white color for background instead of black ?Thanks for the tutorial. I used it to detect stationary green objects in a game where player can hide.
That sounds like a perfect use-case for the cv2.inRange function. Have you tried defining the lower and upper boundaries for your green objects yet? I would suggest using the range-detector script mentioned in this blog post as a starting point.
Excellent tutorial Adrian, Thank you!!
But I have a question, what method you are using to define HSV color ranges, it is very hard to adjust the ranges to different images.
I would want to extract black color, range from ( 0 to 50) from the pic (honeybee colony).
Could you help.
To define your own custom color range, just define the lower and upper boundary boundaries. You can do this by modifying the boundaries variable. It might take some trial and error to get exactly right.
Great! Worked well, able to detect black pixels. I thank you.Can you say how to change black background to white one.
Sure, all you need is masking. Create a new image with the same dimensions as the original one, only with a white rather than black background. Then apply bitwise masking to make the foreground show up on the background. I provide more information on masking and bitwise operations inside Practical Python and OpenCV.
the question at the above something missing, so I will fix it from here, I mean you says open cv uses reverse order so it is BGR but in your example you show it R >= 100 B >= 15 and G >=17 so it means you used GBR by the way other pages sayas opencv uses BGR but in my mac GBR worked ? so whic order opencv uses
Normally, we refer to pixel values in RGB order. However, OpenCV refers to them in BGR order (NOT GBR order). Therefore, the pixel values supplied in this blog post are provided in BGR order, which is what OpenCV expects.
hey adrian, ineed your help, i want to combine your work about the color detection and shape detection, adding the position of the object, and the result in show in the terminal, i already success but the color and shape detection didn’t combine in the result output, can you help me?
I would suggest using the range-detector script I mentioned in the blog post. The boundaries for each color can vary dramatically based on your lighting conditions.
Hi Adrian.! can we able to detect some multiple colour combination i.e Military Camuflague colour with this thing .? what are the settings we are going to play with ,?
You would want to define color threshold ranges for each color in the camouflage. Then, apply each of these thresholds to the image and construct a mask and combine the masks for each range. This will help you detect camouflage in your image.
Link for the image?Thanks but i have errors in lines 8 _ 9 .. in reading the image .. could u give me an example to correct arguments?
You supply the path to the image via command line arguments and your terminal: $ python detect_color.py --image pokemon_games.png
Hello Adrian, how can i setting resize the result images and save it to new image jpg format ?To write an image to disk you would see cv2.imwrite . If you’re just getting started with learning computer vision and OpenCV, I would suggest that you go through Practical Python and OpenCV. Your question is addressed in the first few chapters.
sorry to say that i dont know how to get the correct path in line 8~9…..should i replace –image with my pictures’path?
No, you simply need to supply the --image switch as as command line argument when you execute your Python script. Please see this tutorial for more information.
Hey Adrian, i would like to use this to concept to build an app to help people with color vision deficiency (usually known as color blindness). I wanna detect whether in an image there is blue, red, green color, or any of its combination to help those who have partial color blindness. but i also need to detect any colors in an image for those who have total color blindness. Could you help me about this? what should i do to make it works? (fyi im a real newbie with a really basics knowledge in opencv and python, so if u could give a detailed explaination it would be a great help for me)
Thanks in advance! 🙂
In order to perform this type of color balancing you would first need to calibrate your images using a color chart or a gray-level balancing card. From there you can obtain a consistent level of color representation for a given scene with your camera. This is definitely more of an advanced technique and not one I would recommend you taking on if you are just getting started with OpenCV and computer vision. If you’re just getting started in the world of computer vision and OpenCV, I would suggest you work through Practical Python and OpenCV before continuing.
Thanks for ur kind reply, but i haven’t set my goal far to do color balancing, i just meant to ask what should i do to detect all colors within an image without setting any boundaries of RGB color space? Just like the code u share, but without setting any boundaries, could u please give me the answer?
I also wanna ask could we give a highlight or whatsoever to differentiate each region of colors in an image? and how could we give a text lable of the color names in the region of its colors? thanks before…
Are you looking to detect and label various colors in an image without setting any color boundaries and without color balancing? Simply put, that’s not possible, unless you train a classifier to label the colors of pixels based on real-world images.
Hi, your code looks interesting. I am working on a project in which I have to perform color change, not just color detection. As in, if I detect yellow, I have to display an image with white overlapped on the yellow blobs. Any suggestion on how I could do that?
You could use OpenCV’s cv2.drawContours function to draw the white overtop the detected yellow blobs. I discuss the basics of OpenCV and how to use cv2.drawContours inside my book, Practical Python and OpenCV — I would highly suggest starting there.
I run my application in Python 2.7, but the following error
OpenCV Error: Sizes of input arguments do not match (The lower bounary is neither an array of the same size and same type as src, nor a scalar) in inRange …
mask = cv2.inRange(image, lower, upper)
please help me
Hey Amir — it sounds like your input image was not properly read from disk. Double-check your command line arguments.
Hey Adrian, If I have to determine the color of a cloth. I have to manually specify all the color ranges and the corresponding color or there is some other way.
It depends. Normally you define a set of colors that you want to recognize and then quantize the colors in the image to their closest corresponding color in your database. I would look into k-means color clustering as well.
Hi Adrian, may i ask how to find the good range of the object color?, i’m new in opencvHi Hadopan — please see my reply to “Txoof” above where I mention the “range-detector” script in the “imutils” package. I’ll be doing a detailed blog post on this subject in the future.
Hi Adrian, I’m doing a project to detect color. To determine the range values I’m running your range-detector script and I have the ‘orignal’, ‘thresh’ and ‘trackbars windows open and I have adjusted those to make my image black, which i assume means that provided the range values this black object will now be detected, however I’m unable to acquire the range values i.e. how are they printed? I cannot see them on the terminal or anything. Please help! 🙂 Also is there any other way to fix the light condition problem when doing color detection? Thanks!
You’ll want to modify the range-detector script to print the values. I would suggest after a specific key is pressed on the keyboard. I’ll be doing a tutorial on a more user friendly, easier to use range-detector script within the next couple of weeks.
Dear Adrian, I am working on tracking the color balls in snooker game.I can Track the objects but how can I append the numbers to the identified color ball as per the corresponding colors Like 1 for yellow , 2 for blue 3 for green 4 for red etc,.
Please suggest me.
Working on python opencv platform.
Hi Adrian, I think that your tutorial is great but Ι faced an error when runing the code.
mask = cv2.inRange(image, lower, upper) cv2.error: C:\projects\opencv-python\opencv\modules\core\src\arithm.cpp:1947: error: (-209) The lower bounary is neither an array of the same size and same type as src, nor a scalar in function cv::inRange. What should I do?
Congrats on resolving the issue, George! For anyone else who is having a similar problem: Be sure to double-check your input image paths! The cv2.imread function WILL NOT throw an error if you specify an input image path that does not exist. Instead, the function will return None.
i face the same problem.and i also give the image extension but the same error are show.Hello Adrian,
I have been changing the shades of red to make it the shade of red I want. I have been trying and it hasn’t returned anything. My red is a bit lighter than the one in your article, but when I use your BGR values for red, only the dark side is masked. Any ideas?
Try using a different color space such as HSV or L*a*b*. These color spaces tend to be a bit more robust for detecting shades of color.
Hello, sir i have a project for color detection, i need an explanation about the advantages of HSV from RGB. can you explain to me?
HSV tends to be more natural, similar to how humans perceive color. It’s easier to define color ranges in the HSV color space. The Wikipedia article actually does a very good job explaining the benefits.
OK thank you very much.Hi Adrian, Thanks for the useful tutorial. I was wondering, is there an easy way to get box coordinates for the detected colors? Thanks
Compute the bounding box via cv2.boundingRect. Take a look at this blog post for an example of using it.
Hi Adrian, I would like to ask if there is any way to combine two mask into one? Which means to say, i want blue and green color to appear on the same window. Appreciate your help!
Hi Adrian, i am facing an issue whereby the mask detects colors that i do not need. Is there anyway where i can eliminate these unwanted colors? For eg, my BGR range is in the brown region(trying to detect rust) .. but it’s detecting yellow in the surroundings too. is there anyway to eliminate these colors without adjusting the boundaries as i’ve researched on the BGR range for rust and it’s a wide range. Would appreciate your help adrian! Thank you 🙂
I would suggest using a color space more suited for color range detection (and slightly easier to fine-tune) such as HSV or L*a*b*. I would start with the HSV color space.
Hi, I have a few questions regarding colour detection. Basically what I am trying to do is to detect different shades of rust colour (brown-orange kind of colour) and like what you did, mask the other colours. However, it is only about 80% accurate (not all the wanted shades of colour appear and a few of the unwanted shades of colour appear as well) I would like to know how did you come up with the upper and lower boundaries of the red, blue, green and yellow in the example above? Also, do you have any suggestions to what I am trying to do? Thank you very much for your help!
1. Try using a different color space such as HSV or L*a*b*. I would recommend HSV. 2. The range-detector script inside the imutils library can be used to detect color boundaries. I’ll also be releasing a new version of the script soon, so be on the look out!
How do you use the range-detector script inside the imutils library? Do you have to make adjustments to the code or just run it straight? I tried running it straightaway, but it ask me to specify an argument.
Hi Adrian, Thank you for the wonderful blog. It really helps. Instead of displaying four outputs I just want one out whenever the color in the image is found just stop. For eg. I have 5 different upper and lower boundaries but there is only one (say blue) color in the image, so I need only one output with blue image,what changes do I need to make ? Thanks in advance.
Hey Falun — assuming I understand your question, it sounds like you need to loop over each of your color ranges, one-by-one and then compute the mask. Call cv2.countNonZero on the mask to see if there are any masked pixels. And if so, break from your loop. I hope that helps!
Thank you. It really helped me 🙂 One last question from me. I am trying to display multiple colors in the result. I am trying to append the mask and result value to a numpy array if the countNonZer0 > 0 but I am not able to display the mask and result as the values are not getting append correctly. Can you help me with how should I output multiple colors ?
Final one. How can I find the most dominant color in the image ?
If its a sky it should be blue. Thank you once again in advance
What mathematical operation do you use and how many types of methods are there for color detection, you know?
Hi. Adrain. Thanks for your tutorials which are really helpful. I am quite interested in how the range-detector works. Have you post any code explaintion in detail for the range-detector ? Waiting for your reply. Thank you so much. Best regards,
Yimeng
I have not created a dedicated post for range_detector — I’ve been busy with other tutorials. I’ll be writing range_detector to make it easier to use as well.
Hi Adrian,
1.When I run the script on command prompt a window is popped saying that python has stopped working. Any idea?
2. Is there any other way I can read image without having to use command prompt. I am using jupyter notebook.
1. I’m not sure about that. What is the exact error message you are getting? 2. Sure, you can load the code into Jupyter, remove the command line arguments, and hardcode the image paths.
File “”, line 4, in
mask = cv2.inRange(image, lower, upper)
error: (-209) The lower bounary is neither an array of the same size and same type as src, nor a scalar in function inRange please help me to clear this error
Double-check the command line argument paths to your input file. It seems like the path to the input image is invalid and cv2.imread is returning “None”.
im getting a black image sir,the code has run but only black image is obtainedIt sounds like you may need to tune the color threshold parameters. Try tuning them to whatever color object you are using for detection.
hi, is it possible to create real time video with color detection like this sample program?hey adrian, do you have a post where you detect an object based on a certain color and then drawing a bounding box over it. maybe some additional lines to this code itself?
the command cv2.countNonZero(mask)>0 seems not giving any result, i asked to print blabla to see results at the terminal , it print it all time whenever there’s or not a red ( i change the cam view )
You should double-check your mask output. Even there is even a single pixel your conditional will return “True”. You may want to increase the pixel count from 0 to 10 or 100 to handle the event there is some noise in your image.
Hi Adrian, Thank you for all of your posts. I am trying to identify different faces (Bottom / Side) of a “triangular prism” die (NO DOTS on the surface) out of a top-view color image. What will you recommend if I want to count different sides of the die in the image? Should I go for color recognition or shape recognition or both?
Do you have any example images of what you’re working with? I think seeing a visual representation of the images you are working with and what you are trying to accomplish would be helpful in understanding this problem.
Hello Adrian,
Do you know know what’s the benefit of using BGR instead of HSV? I read on the OpenCV tutorial (http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.html), they used HSV instead of BGR. I tried it and couldn’t have my propgram running. All I got was just 2 black windows popped up
Exactly which color space you use depends on your project. HSV tends to be a bit easier, more intuitive (once you understand the basics), and provides better results once you have the threshold defined properly. IF you are getting two black windows then no pixels are falling into your defined range. You will need to further tune the color thresholds.
Hey Adrian,
Thanks a lot for your tutorial. I am trying to do something similar except that I am trying to detect all of the contours in the picture that are not of green colour and draw squares around them. I have looked at your different tutorials like motion detection, shapes detection..etc. However I can’t manage to find the right openCV command that includes all of the colours but the range I don’t want. In other words in your code you ususally use mask =cv2.inrange(hsv, greenlower, greenupper) I am trying to find the “out of range” equivalent. What command do you reckon I use? Many thanks
If it helps I am trying to use this to get detect target in a green environment like in a forest or so.
Is there a particular reason you cannot do a bitwise NOT to flip the mask? You detect your green colors (what you don’t want) and then flip the mask to get everything you do want: mask = cv2.bitwise_not(mask)
Hello Adrian, I’m getting error: (-209) The lower boundary is neither an array of the same size and same type as src, nor a scalar in function cv::inRange Thanks
Double-check your path to the “cv2.imread” function. Your path is invalid causing “cv2.imread” to return “None”. You can learn more about NoneType errors, including how to solve them, in this post.
Hello Adrian, How I solve the problem “the following arguments are required: -i/–image”? Thank youHI Adrian, Great post. I have a simple question. I have a list of colours that I need to detect in an image. Could you tell me how to get boundary/range of any colour I want (say purple)?
You would need to manually specify those color threshold parameters. The range-detector script in the “imutils” library may help you out.
Hi, how did you get the RGB boundaries for your colors?Hi Adrian, how exactly did you use your Range Detector script to determine your color ranges? I’m having trouble working with it.
You load up an image (or video) in the script and then adjust the sliders. You’ll want to use the sliders to determine your color range. From there you record the RGB or HSV values for the range and use them in your own script.
HelloNo, but you can use this tutorial to access your Raspberry Pi camera module and from there use the code here to detect colors in a video stream. I hope that helps!
what changes are to be made to load video instead of imageYou can use the “Downloads” section of this tutorial to download the source code and example dataset.
How you are deciding the values of red,green,blue colors?Hi Adrian! Great stuff! I have a question, is there a way to inverse the output? like, display everything EXCEPT what is in the upper lower boundries? So suppose instead of displaying only red Pokemon, it displays everything except the red Pokemon.
I read the comment above, I have tried to write this line: output = cv2.bitwise_and(image, image, mask=mask) as this line: output = cv2.bitwise_not(image, image, mask=mask) What I am getting is somewhat what I want but not exactly.
I want two things:
1. To display everything, except
2. Except the color blue So I am getting point number one, and the color blue is not being displayed which is what I want, but it is being filled with a yellowish color, instead I want it to be colored in black.
Sorry, got it to work I think: output = cv2.bitwise_and(image, image, mask=cv2.bitwise_not(mask)) but if you have any other comments I’d love to hear them! 🙂 ps, bought your book, will look into it
Hi Adrian. massive work here thanks. I’m a beginner in Python and I’d like to find a way to detect colors in certain areas of an image. I can’t seem to find an easy way to deal it with. what’d you suggest. thank you.
hey Adrian what are uses of this color detection?Can we display the name of the detected color also? if so can you please help me at least giving a reference link .thank you.
It’s simply a threshold test. If you’re new to thresholding I would recommend you read through Practical Python and OpenCV — that book will teach you the basics.
Hello adrian,
Does this code work for reading from a video ?
Also i need to get the rgb values from each frame taken by the video because i need to convert them to cie lab values.. can you help please ?
1. Yes, it works when reading from a video file. 2. You can convert color spaces via the “cv2.cvtColor” function. If you need help learning the basics of OpenCV I would suggest reading Practical Python and OpenCV.
Hey Adrian, Thanks for the tutorial. I wonder how can I extract all the colors of my image. For example, I have an image that contains 10 different colors, How am I going to extract all the colors at the same time instead of extracting color one by one?
Thanks for the awesome article, Adrian! A clarification: since the upper and lower RED values are in BGR in numpy, for the tuple ([17, 15, 100], [50, 56, 200]) are the B and G values switched in the statement below, or am I missing something? “Here, we are saying that all pixels in our image that have a R >= 100, B >= 15, and G >= 17 along with R
Hi Adrian,
Thanks for your work.
Do you know if it is possible to use HSV instead of RGB for color detection please ?
Yes, you would need to define your color range in HSV and then convert the frame to the HSV color space prior to using the “cv2.inRange” function. That process is covered inside the PyImageSearch Gurus course.
Hi, Im trying to add a little audible warning to this script when it would detect a specific color. The warning itself is simple os.system(‘spd-say”Red detected”). I am however not sure how to set it off when the program has detected the color red.
i want to classify a dataset of single colored images by two different shades of the color (e.g. light and dark green) in python how can do it?
Hey Adrian,
Why do you demarcate the boundaries in the GBR format?
Also, what format does openCV use to display the converted numpy arrays?
Hello Adrian. Your post is very useful. But i have a question to ask:
if i want to detect a color, how can i know what is the range of the pixels represent that color? Exactly i want to know how you knew the upper limit and lower limit of that color?
Thank you so much.
Hey, Adrian Rosebrock here, author and creator of PyImageSearch. While I love hearing from readers, a couple years ago I made the tough decision to no longer offer 1:1 help over blog post comments.
At the time I was receiving 200+ emails per day and another 100+ blog post comments. I simply did not have the time to moderate and respond to them all, and the sheer volume of requests was taking a toll on me.
Instead, my goal is to do the most good for the computer vision, deep learning, and OpenCV community at large by focusing my time on authoring high-quality blog posts, tutorials, and books/courses.
If you need help learning computer vision and deep learning, I suggest you refer to my full catalog of books and courses — they have helped tens of thousands of developers, students, and researchers just like yourself learn Computer Vision, Deep Learning, and OpenCV.
Course information:
86+ total courses • 115+ hours of on-demand video • Last updated: July 2024
★★★★★
4.84 (128 Ratings) • 16,000+ Students Enrolled
✓ 86 courses on essential computer vision, deep learning, and OpenCV topics
✓ 94 Certificates of Completion
✓ 115+ hours of on-demand video
✓ Brand new courses released every month, 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 500+ tutorials on PyImageSearch
✓ Easy one-click downloads for code, datasets, pre-trained models, etc.
✓ Access on mobile, laptop, desktop, etc.