I am using Raspberry Pi 3 and Pi camera. I am doing an image processing program that could detect yellow colour and right now I am testing it but in frame nothing happen.My color detection is wrong?
Here is my code:
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
while(1):
# Take each frame
_, frame = cap.read()
# Convert BGR to HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# define range of yellow color in HSV
lower_yellow = np.array([204,204,0])
upper_yellow = np.array([255,255,254])
# Threshold the HSV image to get only yellow colors
mask = cv2.inRange(hsv, lower_yellow, upper_yellow)
# Bitwise-AND mask and original image
res = cv2.bitwise_and(frame,frame, mask= mask)
cv2.imshow('frame',frame)
cv2.imshow('mask',mask)
cv2.imshow('res',res)
k = cv2.waitKey(5) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
The problem is that you're filtering an HSV image with what looks to be RGB values. If you're looking for yellow, then you want to have a narrow hue range, and then saturation and value wider.
Yellow is roughly 60 degrees for hue, which means around a value of 30 for OpenCV (as the hue value is half the degree value to it can fit in the range 0-255). Similarly, your saturation and value shouldn't be the full range of 0-255 otherwise things that are close to black or white will match.
Try something like
lower_yellow = np.array([20, 30, 30])
upper_yellow = np.array([40, 200, 300])
This will hopefully get you close, but you still may have to play around with the numbers to get what you want.
Related
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
tag = frame[235:245, 315:325]
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower_red = np.array([20, 20, 50])
upper_red = np.array([255, 255, 130])
for i in range (235,245):
for j in range (315,325):
if cv2.inRange(tag[i][j],lower_red,upper_red):
break
cv2.imshow('image',frame)
if cv2.waitKey(1) == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
i want to check my middle 100 pixels in my 480,640 camera to see if they all fall in a certain color range and if they do to end the program but i cant find i way to compare the values of the middle 100 pixels with the values that i want
Problems with your approach:
1. Improper variable handling: You are cropping your image to tag before converting to HSV color space
2. Wrong usage of cv2.inRange(): The function returns a binary image of values either 0 or 255.
0 -> if the pixels do not fall in range
255 -> if the pixels fall in range
Thumb rule: Avoid using for loops
Solution:
Since cv2.inRange() returns a binary image, just find the average of the pixel values within the cropped image. If the average is 255 (all the pixels are white and within the color range) -> break!
You can alter your code using the following snippet:
ret, frame = cap.read()
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower_red = np.array([20, 20, 50])
upper_red = np.array([255, 255, 130])
tag = hsv[235:245, 315:325]
mask = cv2.inRange(tag, lower_red, upper_red)
if np.mean(mask) == 255:
print("All the pixels are within the color range")
break
I have a video with a moving red ball in the middle and I want the program to return the position of that object throughout the video. I've read many examples online but I am not so sure what's the best way to do it in opencv.
import cv2
import numpy as np
coords = []
# Open the video
cap = cv2.VideoCapture('video-4.mp4')
# Initialize frame counter
while(1):
# Take each frame
_, frame = cap.read()
# Convert BGR to HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# define range of blue color in HSV
lower_red = np.array([100, 150, 0])
upper_red = np.array([140, 255, 255])
imgThreshHigh = cv2.inRange(hsv, lower_red, upper_red)
thresh = imgThreshHigh.copy()
countours,_ = cv2.findContours(thresh, cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
for cnt in countours:
area = cv2.contourArea(cnt)
best_cnt = cnt
M = cv2.moments(best_cnt)
cx,cy = int(M['m10']/M['m00']), int(M['m01']/M['m00'])
coord = cx, cy
print(coord)
cv2.imshow('frame',frame)
cv2.imshow('Object',thresh)
k = cv2.waitKey(5) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
I am not sure why, but it only processes a few frames of the videos, not all.
It is not clear to me how the best_cnt contour is selected. Right now it is just selecting the last one. I think it was intended to filter by size to ensure the small red circle was selected, but it is not doing that. Maybe the dropped frames happen because the last contour in the list is not the red circle.
I would try to filter by size and keep the contour smaller than a given max area.
Also, it looks like the red color filter range is off. I could only detect the ball changing the red filter values to:
lower_red = np.array([170, 0, 190])
upper_red = np.array([179, 255, 255])
To do this, I calculated the min and max values in the small area around the red circle:
plt.imshow(hsv[255:275, 170:190, :])
np.min(hsv[255:275, 170:190, :], axis=0)
np.max(hsv[255:275, 170:190, :], axis=0)
And chose min and max values to give some wiggle room for the red to change in different frames. This will need fine tuning using all the frames in your video to make sure no shade of red is left out using those limits.
I have a video of a brick breaking game. Some bricks are in red color. I have to change the red color into black. I am trying to find the location of the red pixel in numpy array and assign black color on those pixels. The code I have provided below turns the red color into black. But the process is so slow that 12s video took more than 5 mins. Is there any faster way to do that?
import numpy as np
import cv2
vid = "input.mp4"
cap = cv2.VideoCapture(vid)
while(True):
ret, frame = cap.read()
if ret:
for i in zip(*np.where(frame == [0,0,255])):
frame[i[0], i[1], 0] = 0
frame[i[0], i[1], 1] = 0
frame[i[0], i[1], 2] = 0
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
cv2.destroyAllWindows()
Try this out, read comments in the code for more information.
import cv2
import numpy as np
img = cv2.imread("1.png")
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# define range of red color in HSV
lower_red = np.array([0,50,50])
upper_red = np.array([10,255,255])
# Threshold the HSV image to get only red colors
mask = cv2.inRange(hsv, lower_red, upper_red)
red_only = cv2.bitwise_and(img,img, mask= mask)
#convert mask to 3-channel image to perform subtract
mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
res = cv2.subtract(img,mask) #negative values become 0 -> black
cv2.imshow("img",img)
cv2.imshow("mask",mask)
cv2.imshow("red_only",red_only)
cv2.imshow("res",res)
cv2.waitKey()
cv2.destroyAllWindows()
PS. And this method takes almost no time, I've tested on my machine and it takes about 3ms for an image of 1280x720
This works just for gray
(you cant specify channels with color you are replacing)
color_find = [0,0,255]
indexes=np.where(frame == color_find)
frame[indexes]=0 # 0-255 creates [0,0,0] - [255,255,255]
More general attitude is like this
Here you specify RGB axis, and you can replace with any color
red = [0,0,255]
black = [0,0,0]
indexes=np.where(np.all(frame == red,axis = 2))
frame[indexes] = black
you can replace your for loop with this:
# [b,g,r]
color_in = [0, 0, 255] # color you want to filter
color_out = [0, 0, 0] # color you want to set
for i in range(3):
frame[frame[:, :, i] == color_in[i]] = color_out[i]
You can use this for video frame with 3 color channels. Also, you can play around with the conditional operator(replace with >, <, etc.) for more control.
Use like this to filter color ranges:
frame[frame[:, :, i] < color_in[i]] = color_out[i]
Using Ha Bom's code and some parts of my code, the problem has been solved. However, it takes a little bit of time. Processing 12-second video takes around 20-25 sec. The main purpose was to convert red pixels into orange-
The code is provided below -
cap = cv2.VideoCapture("input.avi")
while(True):
ret, frame = cap.read()
if ret:
# hsv is better to recognize color, convert the BGR frame to HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# in hsv red color located in two region. Create the mask for red color
# mask the red color and get an grayscale output where red is white
# everything else are black
mask1 = cv2.inRange(hsv, (0,50,20), (5,255,255))
mask2 = cv2.inRange(hsv, (175,50,20), (180,255,255))
mask = cv2.bitwise_or(mask1, mask2)
# get the index of the white areas and make them orange in the main frame
for i in zip(*np.where(mask == 255)):
frame[i[0], i[1], 0] = 0
frame[i[0], i[1], 1] = 165
frame[i[0], i[1], 2] = 255
# play the new video
cv2.imshow("res",frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
cv2.destroyAllWindows()
I'm using Opencv python in raspberry pi, to analize a heatmap, i'm looking for color red, which represents the highest temperature, i need to detect if in an specific area exist red color, in case it does i can use this information to activate a condition, i'm using a heatmap like this:
for the red color detection i'm using this code:
import cv2
import numpy as np
while(1):
# Take each frame
frame = cv2.imread('heatmap.png')
# Convert BGR to HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# define range of blue color in HSV
lower_red = np.array([-20, 100, 100])
upper_red = np.array([13, 255, 255])
# Threshold the HSV image to get only blue colors
mask = cv2.inRange(hsv, lower_red, upper_red)
# Bitwise-AND mask and original image
res = cv2.bitwise_and(frame,frame, mask= mask)
cv2.imshow('heatmap',frame)
cv2.imshow('mask',mask)
cv2.imshow('res',res)
k = cv2.waitKey(5) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
the code above give me al the pixels in red, but i need to determine if the heatmap contour is red, i mean the image contour or border would be a red color not permited area, does anyone how i can do that?
Your HSV range is not right. For red, (0,20,20)~(8,255,255), (170,20,20) ~ (180,255,255).
Here is my result:
The code:
#!/usr/bin/python3
# 2018/05/16 13:54:09
import cv2
import numpy as np
img = cv2.imread('heatmap.png')
# Convert BGR to HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask1 = cv2.inRange(hsv, (0,20,20), (8,255,255))
mask2 = cv2.inRange(hsv, (170,20,20), (180,255,255))
mask = cv2.bitwise_or(mask1, mask2)
dst = cv2.bitwise_and(img, img, mask=mask)
cv2.imshow("dst", dst)
cv2.imwrite("__.png", dst)
cv2.waitKey()
Some useful links:
Choosing the correct upper and lower HSV boundaries for color detection with`cv::inRange` (OpenCV)
How to define a threshold value to detect only green colour objects in an image :Opencv
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
while(1):
# Take each frame
_, frame = cap.read()
# Convert BGR to HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# define range of blue color in HSV
lower_blue = np.array([110,50,50])
upper_blue = np.array([130,255,255])
# Threshold the HSV image to get only blue colors
mask = cv2.inRange(hsv, lower_green, upper_green)
# Bitwise-AND mask and original image
res = cv2.bitwise_and(frame,frame, mask= mask)
cv2.imshow('frame',frame)
cv2.imshow('mask',mask)
cv2.imshow('res',res)
k = cv2.waitKey(5) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
Note: i'm new to open cv ,so please help guys!!!
In this program
while reading a frame , why is there the symbol ' _, ' before frame
is it a syntax??
The lowerbound and upper bound of blue color is specified.
is that RGB values or BGR values or HSV values??
How can i find lower bound and upperbound of others colors like red,green?
Please explain the process of finding values of other colour ,i tried other colours but it gave me black screen output for hsv and res!!!
Can some one change this program to detect red color or other color so i can know the difference?
This is tuple unpacking; cap.read() returns two values, we assign the first to _ (convention for "we won't be using this") and the second to frame.
The comment literally says "in hsv".
You just need to specify your own bounds, or change the ones already there, and see the difference yourself. Use an HSV converter to see what colours you are using. If the colours within your range aren't in the image you process, it will be black.