Here's my issue:
I need to isolate the blue curve from the following image :
The curve can be anywhere in the image, so I implemented a pattern recognition which works just fine, giving me the following box:
Now, what I'm trying to do is extract the curve itself. The curve can be of whatever color, so I thought I'd extract the dominants color in the picture and apply a HSV mask corresponding to those.
I've managed to do so and recover the colors of the curve.
These are, in BGR : [68, 240, 86] and [160, 81, 76]
Now my issue is finding the HSV value corresponding in order to apply the mask. All the things I've tried ended up in a completely black result.
Here's my current code for the mask:
low = np.uint8([[llow]])
high = np.uint8([[lhigh]])
hsv_low = cv2.cvtColor(low, cv2.COLOR_BGR2HSV)
hsv_high = cv2.cvtColor(high, cv2.COLOR_BGR2HSV)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
print(hsv_low, hsv_high)
mask1 = cv2.inRange(hsv, hsv_low, hsv_high)
output = cv2.bitwise_and(img, img, mask=mask1)
show("hsv", output)
wait()
with:
llow = [68, 240, 86]
lhigh = [160, 81, 76]
I also believe the HSV value obtained are kind of weird, with
hsv_low ending up being [86, 240, 68] and hsv_high [76, 81, 160], so I don't know which one should be the lower range or the high one. (I've tried to switch them but no changes occured)
Any help would be greatly appreciated !
Try maybe with masks
lower_blue = np.array([60, 40, 40])
upper_blue = np.array([130, 255, 255])
They are already in HSV color colorspace and I got picture looking like this. Now you would only need to fill holes from the green scale.
Related
I have such image as below and I want to change the pixel colors which have a specific BGR value of [99,30,233] or [255,31,101] to gray, and the rest to green.
Here is my code at the moment
image = cv.imread("path")
def change_img_color(image, image_dummy):
image_dummy[np.logical_or(np.all(image==[99,30,233],axis=2), np.all(image==[255,31,101],axis=2))] = [95, 95, 95]
image_dummy[np.logical_or(np.all(image==[146,61,65],axis=2),np.all(image==[147,177,218],axis=2))] = [95, 95, 95]
image_dummy[np.logical_or(np.all(image==[54,67,244],axis=2),np.all(image==[180,187,42],axis=2))] = [0, 0, 0]
image_dummy[np.logical_and(np.all(image_dummy!=[95,95,95],axis=2), np.all(image_dummy!=[0,0,0],axis=2))] = [50, 130, 110]
return image_dummy
The problem is that when I want to transform the image to this form, logically it should be like this:
but it ends up like this:
I can't figure out why that orange color does not change to green color, when I specified all the pixels that are not gray and are not black should be converted to green.
I think there's a typo somewhere and the red regions are not identified by the logic of your definition. To avoid such errors, it can be helpful to avoid "magic numbers".
Here's another approach to your problem based on a previous SO thread: https://stackoverflow.com/a/50215020/9870343.
image = cv2.imread("path")
cimage = image.copy()
color1 = np.array([99,30,233])
color2 = np.array([255,31,101])
gray = np.array([95,95,95])
green = np.array([110, 130, 50])
gscale = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
mask1 = cv2.inRange(image, color1, color1)
mask2 = cv2.inRange(image, color2, color2)
mask = mask1 + mask2
image[gscale!=0] = green
image[mask!=0] = gray
The output image:
I'm new to image processing and video processing and I tried to get the orange color space for use in my color detecting python file. But unfortunately it doesn't work. It works when I give the blue color space define range in HSV colorspace.
I tried giving the color space for orange but then system doesn't show any output
Define 'orange' range in HSV colorspace
upper = np.array([32,255,255])
lower = np.array([110, 50, 50])
mask = cv2.inRange(hsv, lower, upper)
I want the proper 'orange' range in HSV colorspace
For me the following values were OK to get an approximate orange color space.
# Threshold of orange in HSV space
lower_orange = np.array([0, 100, 45])
upper_orange = np.array([225, 250, 255])
# preparing the mask to overlay
mask = cv2.inRange(hsv, lower_orange, upper_orange)
I have road photos from the racing game.
I want to detect yellow and white lanes.
If I use RGB space,
def select_rgb_white_yellow(image):
# white color mask
lower = np.uint8([123, 116, 116])
upper = np.uint8([186, 172, 160])
white_mask = cv2.inRange(image, lower, upper)
# yellow color mask
lower = np.uint8([134, 121, 100])
upper = np.uint8([206, 155, 87])
yellow_mask = cv2.inRange(image, lower, upper)
# combine the mask
mask = cv2.bitwise_or(white_mask, yellow_mask)
masked = cv2.bitwise_and(image, image, mask = mask)
return masked
I only get white lanes.
So tweaked little bit, using HLS space, by using this code.
def convert_hls(image):
return cv2.cvtColor(image, cv2.COLOR_RGB2HLS)
Then, extracting the yellow and white lane again,
def select_white_yellow(image):
converted = convert_hls(image)
# white color mask
lower = np.uint8([0, 0, 0])
upper = np.uint8([0, 0, 255])
white_mask = cv2.inRange(converted, lower, upper)
# yellow color mask
lower = np.uint8([ 10, 0, 100])
upper = np.uint8([ 40, 255, 255])
yellow_mask = cv2.inRange(converted, lower, upper)
# combine the mask
mask = cv2.bitwise_or(white_mask, yellow_mask)
return cv2.bitwise_and(image, image, mask = mask)
Then it cannot detect white lane anymore. Is there good way to detect both white and yellow lane?
Here are all RGB colour code that I found
Yellow
c2974A (194, 149, 74)
a07444 (160, 116, 68)
b38e55 (179, 142, 85)
867964 (134, 121, 100)
ce9b57 (206, 155, 87)
ce9853 (206, 152, 83)
white
b4a59d (180, 165, 157)
b9a99a (185, 169, 154)
baaca0 (186, 172, 160)
867e79 (134, 126, 121)
7b7474 (123, 116, 116)
827d7c (130, 125, 124)
To extend the comment: this is an implementation of a 2 stage approach. Take some time to look at the intermediate images/masks to fully understand everything that happens.
Cropping to region of interest
You can automate this, but I cheated a little and did it manually. The cropped sky area will rarely ever have road surface, this is an easy solution that suffices (for now) I think. Similarly, I also cut of the HUD boxes on the right hand side, as they have similar gray colors as the road and were interfering. It's more neat to draw black boxes over them, so they are excluded from processing.
Isolating road
Convert the cropped image to HSV an select only gray-ish values. After some noise removal I improved the mask using findContours to draw the convexhull. If performance is an issue, you could maybe skip it by tweaking the close mask step.
Selecting lines
Using the mask you can create an image of only the road surface. You can use this for color separation without having to worry about also selecting surroundings. My result is not perfect, but I assume you have larger versions of the images which will give better results.
Result:
Code:
import cv2
import numpy as np
# load image
image = cv2.imread('pw12b.jpg')
# crop image
h,w = image.shape[:2]
image = image[200:h-20,20:550]
# create hsv
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# set lower and upper color limits
low_val = (0,0,0)
high_val = (179,45,96)
# Threshold the HSV image
mask = cv2.inRange(hsv, low_val,high_val)
# remove noise
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel=np.ones((8,8),dtype=np.uint8))
# close mask
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel=np.ones((20,20),dtype=np.uint8))
# improve mask by drawing the convexhull
ret, contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
hull = cv2.convexHull(cnt)
cv2.drawContours(mask,[hull],0,(255), -1)
# erode mask a bit to migitate mask bleed of convexhull
mask = cv2.morphologyEx(mask, cv2.MORPH_ERODE, kernel=np.ones((5,5),dtype=np.uint8))
# remove this line, used to show intermediate result of masked road
road = cv2.bitwise_and(image, image,mask=mask)
# apply mask to hsv image
road_hsv = cv2.bitwise_and(hsv, hsv,mask=mask)
# set lower and upper color limits
low_val = (0,0,102)
high_val = (179,255,255)
# Threshold the HSV image
mask2 = cv2.inRange(road_hsv, low_val,high_val)
# apply mask to original image
result = cv2.bitwise_and(image, image,mask=mask2)
#show image
cv2.imshow("Result", result)
cv2.imshow("Road", road)
cv2.imshow("Mask", mask)
cv2.imshow("Image", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
I am trying to perform a simple colored object detection using OpenCV and Python.
I have read several tutorials but I encounter a confusing problem that prevents me to progress. Although I provide correct data HSV, my program does not seem to detect objects of that color.
I use this image (sorry for the poor quality of my webcam):
In order to detect the red object, I recovered the HSV color data:
And here is my code:
YELLOW = 30
BLUE = 210
GREEN = 145
RED = 320
color = RED
img = cv2.imread("sample.png")
hue = color // 2
lower_range = np.array([max(0, hue - 10), 0, 0], dtype=np.uint8)
upper_range = np.array([min(180, hue + 10), 255, 255], dtype=np.uint8)
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(img, lower_range, upper_range)
binary_img = cv2.bitwise_and(img_hsv, img_hsv, mask=mask)
binary_img = cv2.cvtColor(binary_img, cv2.COLOR_BGR2GRAY)
_, binary_img = cv2.threshold(binary_img, 127, 255, cv2.THRESH_BINARY)
cv2.imshow('sample', binary_img)
cv2.waitKey(0)
Result:
The result for others colors is correct (not perfect because of the poor quality I guess), but I can not get something for the red. Yet, the HSV converted image is quite explicit:
Do you see what am I doing wrong, please?
You are doing everything right, the only problem is that you apply your threshold on the BGR image instead of the HSV.
Change:
mask = cv2.inRange(img, lower_range, upper_range)
To
mask = cv2.inRange(img_hsv, lower_range, upper_range)
I tested it and it looks just fine. I guess you'll need some morphological operations to get to your final result.
I'm trying to make a mask of all green pixels and one of all yellow pixels using the inrange function. The big trouble I have is finding the correct HSV values for both colors because they seem to overlap.
The following picture (green circle) should detect the green circle only in the yellow mask, this picture (yellow square) must do the opposite (only yellow) but i cannot seem to seperate them.
I use the following HSV values
#Yellow
lower_yellow = np.array([20, 20, 20], dtype=np.uint8)
upper_yellow = np.array([35, 255, 255], dtype=np.uint8)
#Green
lower_green = np.array([24, 40, 40], dtype=np.uint8)
upper_green = np.array([60, 255, 120], dtype=np.uint8)
I hope anyone can help