I am trying to extract red color from an image. I have code that applies threshold to leave only values from specified range:
img=cv2.imread('img.bmp') img_hsv=cv2.cvtColor(img, cv2.COLOR_BGR2HSV) lower_red = np.array([0,50,50]) #example value upper_red = np.array([10,255,255]) #example value mask = cv2.inRange(img_hsv, lower_red, upper_red) img_result = cv2.bitwise_and(img, img, mask=mask)
But, as i checked, red can have Hue value in range, let's say from 0 to 10, as well as in range from 170 to 180. Therefore, i would like to leave values from any of those two ranges. I tried setting threshold from 10 to 170 and using cv2.bitwise_not()
function, but then i get all the white color as well. I think the best option would be to create a mask for each range and use them both, so I somehow have to join them together before proceeding.
Is there a way I could join two masks using OpenCV? Or is there some other way I could achieve my goal?
Edit. I came with not much elegant, but working solution:
image_result = np.zeros((image_height,image_width,3),np.uint8) for i in range(image_height): #those are set elsewhere for j in range(image_width): #those are set elsewhere if img_hsv[i][j][1]>=50 \ and img_hsv[i][j][2]>=50 \ and (img_hsv[i][j][0] <= 10 or img_hsv[i][j][0]>=170): image_result[i][j]=img_hsv[i][j]
It pretty much satisfies my needs, and OpenCV's functions probably do pretty much the same, but if there's a better way to do that(using some dedicated function and writing less code) please share it with me. :)
We can use the inRange() function of OpenCV to create a mask of color, or in other words, we can detect a color using the range of that color. The colors are stored in an RGB triplet value format inside a color image. To create its mask, we have to use the RGB triplet value of that color's light and dark version.
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.
In more technical terms, RGB describes a color as a tuple of three components. Each component can take a value between 0 and 255, where the tuple (0, 0, 0) represents black and (255, 255, 255) represents white.
I would just add the masks together, and use np.where
to mask the original image.
img=cv2.imread("img.bmp") img_hsv=cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # lower mask (0-10) lower_red = np.array([0,50,50]) upper_red = np.array([10,255,255]) mask0 = cv2.inRange(img_hsv, lower_red, upper_red) # upper mask (170-180) lower_red = np.array([170,50,50]) upper_red = np.array([180,255,255]) mask1 = cv2.inRange(img_hsv, lower_red, upper_red) # join my masks mask = mask0+mask1 # set my output img to zero everywhere except my mask output_img = img.copy() output_img[np.where(mask==0)] = 0 # or your HSV image, which I *believe* is what you want output_hsv = img_hsv.copy() output_hsv[np.where(mask==0)] = 0
This should be much faster and much more readable than looping through each pixel of your image.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With