Color detection in opencv (python) - python

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

Related

How to choose pixels based on specific color

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:

HSV mask within two ranges

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.

How to define the orange color-space

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)

OpenCV - Lane detetion, both yellow and white lanes

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()

Detecting line by color using Opencv in python

I have a picture( Basic X-Y plot image, where the plot line is in blue color and x,y axis are in black color), where in that I need to detect the edges based on the color. I came across below code, where its detecting all the lines by using canny edge detection and hough algorithm. But I need to detect only the blue color line in this image. What can i do in order to detect that?
Below is the code that I used.
import numpy as np
import cv2
img = cv2.imread('xyplot.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv2.imshow('grayimage',gray)
edges = cv2.Canny(gray,50,150,apertureSize = 3)
cv2.imshow('edgesimage',edges)
print img.shape[1]
print img.shape
minLineLength=img.shape[1]-300
lines = cv2.HoughLinesP(image=edges,rho=0.02,theta=np.pi/500,
threshold=10,lines=np.array([]),
minLineLength=minLineLength, maxLineGap=100)
a,b,c = lines.shape
for i in range(a):
cv2.line(img, (lines[i][0][0], lines[i][0][1]), (lines[i][0][2],
lines[i][0] [3]), (0, 0, 255), 3, cv2.LINE_AA)
cv2.imshow('edges', edges)
cv2.imshow('result', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Apply a (blue) color mask on your image before converting to gray scale. You can do so by defining the lower and upper boundary of all 3 channels and performing BITWISE_AND on the original image. You will have to play around with the values of the channel ranges to make sure only the pixels you want get captured.
lower = np.array([200, 20, 20], dtype = "uint8")
upper = np.array([255, 100, 100], dtype = "uint8")
mask = cv2.inRange(img, lower, upper)
img = cv2.bitwise_and(img, img, mask = mask)
Note: The three channels in the list are B, G and R respectively.

Categories

Resources