Camera unable to detect multiple colours in python - python

I'm trying to get my camera to detect both red and green colours.
Now it can detect either one colour successfully, but it can't detect both colours.
ball_color=('red','green')
If I change it to ball_color=('red') or ball_color=('green') it can work, but when i put ball_color=('red','green') there's errors.
I added the error code at the bottom. Thanks alot!
import cv2
import numpy as np
ball_color=('red','green')
color_dist = {'red': {'Lower': np.array([0, 60, 60]), 'Upper': np.array([10, 255, 255])},
'green': {'Lower': np.array([35, 43, 35]), 'Upper': np.array([90, 255, 255])},
}
cap = cv2.VideoCapture(0)
cv2.namedWindow('camera', cv2.WINDOW_AUTOSIZE)
while cap.isOpened():
ret, frame = cap.read()
if ret:
if frame is not None:
gs_frame = cv2.GaussianBlur(frame, (5, 5), 0) # 高斯模糊
hsv = cv2.cvtColor(gs_frame, cv2.COLOR_BGR2HSV) # 转化成HSV图像
erode_hsv = cv2.erode(hsv, None, iterations=2) # 腐蚀 粗的变细
inRange_hsv = cv2.inRange(erode_hsv, color_dist[ball_color]['Lower'], color_dist[ball_color]['Upper'])
cnts = cv2.findContours(inRange_hsv.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]
c = max(cnts, key=cv2.contourArea)
rect = cv2.minAreaRect(c)
box = cv2.boxPoints(rect)
cv2.drawContours(frame, [np.int0(box)], -1, (0, 255, 255), 2)
cv2.imshow('camera', frame)
cv2.waitKey(1)
cap.release()
cv2.waitKey(0)
cv2.destroyAllWindows()
Error code are as follows:
Traceback (most recent call last):
File "/Users/fangyaoting/PycharmProjects/pythonProject/顏色辨識.py", line 21, in <module>
inRange_hsv = cv2.inRange(erode_hsv, color_dist[ball_color]['Lower'], color_dist[ball_color]['Upper'])
KeyError: ('red', 'green')

I think it could be the soultion:
import cv2
import numpy as np
ball_color=('red','green')
color_dist = {'red': {'Lower': np.array([-10, 100, 100]), 'Upper': np.array([10, 255, 255])},
'green': {'Lower': np.array([35, 43, 35]), 'Upper': np.array([90, 255, 255])},
}
cap = cv2.VideoCapture(0)
cv2.namedWindow('camera', cv2.WINDOW_AUTOSIZE)
while cap.isOpened():
ret, frame = cap.read()
if ret:
if frame is not None:
gs_frame = cv2.GaussianBlur(frame, (5, 5), 0) # 高斯模糊
hsv = cv2.cvtColor(gs_frame, cv2.COLOR_BGR2HSV) # 转化成HSV图像
erode_hsv = cv2.erode(hsv, None, iterations=2) # 腐蚀 粗的变细
b_shape = hsv.shape[0], hsv.shape[1], 1
inRange_hsv = np.zeros(b_shape, hsv.dtype)
for i in ball_color:
inRange_hsv_tmp = cv2.inRange(erode_hsv, color_dist[i]['Lower'], color_dist[i]['Upper'])
inRange_hsv = cv2.bitwise_or(inRange_hsv, inRange_hsv_tmp)
cnts = cv2.findContours(inRange_hsv.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]
if len(cnts) > 0:
c = max(cnts, key=cv2.contourArea)
rect = cv2.minAreaRect(c)
box = cv2.boxPoints(rect)
cv2.drawContours(frame, [np.int0(box)], -1, (0, 255, 255), 2)
cv2.imshow('camera', frame)
cv2.waitKey(1)
else:
print("無畫面")
else:
print("無法讀取鏡頭!")
cap.release()
cv2.waitKey(0)
cv2.destroyAllWindows()
You tried to pass tuple of strings as argument to cv2.inRange and it could work with tuple length 1, but it won't work with more arguments. So you should iterate them and use cv2.inRange for every color separately and then use cv2.bitwise_or for them to 'concat' binary images.
And about cnts: sometimes it could not find any contours so you should use if statement to control it.
Edit: in this line inRange_hsv = cv2.bitwise_or(inRange_hsv, inRange_hsv_tmp)

Related

How to correctly find contours?

Hi I wrote this code with the objective of detect contours of an object from a live video produced by a camera (in videoCapture I put 0 as input to indicate the camera built-in of computer.
import cv2
import numpy as np
def nothing(x):
pass
cap = cv2.VideoCapture(0)
cv2.namedWindow("Trackbars")
cv2.createTrackbar("L-H", "Trackbars", 0, 180, nothing)
cv2.createTrackbar("L-S", "Trackbars", 68, 255, nothing)
cv2.createTrackbar("L-V", "Trackbars", 154, 255, nothing)
cv2.createTrackbar("U-H", "Trackbars", 180, 180, nothing)
cv2.createTrackbar("U-S", "Trackbars", 255, 255, nothing)
cv2.createTrackbar("U-V", "Trackbars", 243, 255, nothing)
while True:
_, frame = cap.read()
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
l_h = cv2.getTrackbarPos("L-H", "Trackbars")
l_s = cv2.getTrackbarPos("L-S", "Trackbars")
l_v = cv2.getTrackbarPos("L-V", "Trackbars")
u_h = cv2.getTrackbarPos("U-H", "Trackbars")
u_s = cv2.getTrackbarPos("U-S", "Trackbars")
u_v = cv2.getTrackbarPos("U-V", "Trackbars")
lower_red = np.array([l_h, l_s, l_v])
upper_red = np.array([u_h, u_s, u_v])
mask = cv2.inRange(hsv, lower_red, upper_red)
# rilevazione contorni
_, contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print(contours)
for cnt in contours:
cv2.drawContours(frame, [int(cnt)], 0, (0, 0, 0), 5)
cv2.imshow("Frame", frame)
cv2.imshow("Mask", mask)
key = cv2.waitKey(1)
if key == 27:
break
cap.release()
cv2.destroyAllWindows()
when the execution arrives to cv2.findContours I receive this error message
Traceback (most recent call last):
File "c:\Users\gpoli\Desktop (3176)\peachthon\rilevaContorno.py", line 37, in <module>
_, contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
ValueError: not enough values to unpack (expected 3, got 2)
findContours has two parameters as output not three- In new version of OpenCV.
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
What are contours?
OpenCV (findContours) Detailed Guide

How Can I Solve cv2.drawContours() Error?

I want to do find contours in camera video and Draw the line with Contours
But I got Something Error on my code :|
File ".\Contour.py", line 28, in <module>
cv2.drawContours(frame, contours[i], 1, (0, 0, 255), 3)
cv2.error: OpenCV(4.5.1) C:\Users\appveyor\AppData\Local\Temp\1\pip-req-build-r2ue8w6k\opencv\modules\imgproc\src\drawing.cpp:2490: error:
(-215:Assertion failed) 0 <= contourIdx && contourIdx < (int)last in function 'cv::drawContours'
What I should do in this situation?
My Full Code
import cv2
import sys
import time
import numpy as np
cap = cv2.VideoCapture(0)
while True:
# if cap.isOpened() == False:
# print("Cant Open The Camera")
# sys.exit(1)
ret, frame = cap.read()
# if ret == False:
# print("Can't load the Camera")
# sys.exit(1)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
thresh, binary = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY)
contours = cv2.findContours(binary, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
print(len(contours))
if len(contours) > 0:
# cnt = contours[len(contours) - 1]
for i in range(len(contours)):
cv2.drawContours(frame, contours[i], 1, (0, 0, 255), 3)
key = cv2.waitKey(1)
cv2.imshow("frame", frame)
# cv2.imshow("gray", gray)
# cv2.imshow("binary", binary)
time.sleep(0.5)
if key == 27:
break
cap.release()
cv2.destroyAllWindows()
My Environment
openCV : '4.5.1'
python : '3.7.0'
Camera : Laptop Built-In Camera
:D
cv2.drawContours is expecting a list and the index in that list you want to plot. In your code, the list has just one item, so 1 is out of range.
You could fix that using the following code:
for i in range(len(contours):
cv2.drawContours(frame, [contours[i]], 0, (0,0,255), 3)
If you want to draw all contours, simply pass all the contours to the function:
cv2.drawContours(frame, contours, -1, (0, 0, 255), 3)
As a side note, since cv2.drawContours overwrites the input image (frame in your code), I would recommend creating a copy before drawing the contours, so you can keep the original image for further processing if needed:
output = frame.copy()
cv2.drawContours(output, contours, -1, (0, 0, 255), 3)

where add cv2.resize to get appropriate resolution?

I have a problem with my code. I don't know where I could put cv.resize() in order to get requirement resolution. I want to change it because the file which I upload is full HD resolution and I want to get smaller resolution. I will be glad of solution and explanation.
Below I show my code:
import cv2
import numpy as np
cap = cv2.VideoCapture('DJI_0037.MP4')
while cap.isOpened():
ret, frame = cap.read()
if ret == True:
frame_resize = cv2.resize(frame, (640, 480), interpolation=cv2.INTER_CUBIC)
else:
break
ret, frame_resize1 = cap.read(frame_resize)
ret, frame_resize2 = cap.read(frame_resize)
diff = cv2.absdiff(frame_resize1, frame_resize2)
gray = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5, 5), 0)
_, thresh = cv2.threshold(blur, 20, 255, cv2.THRESH_BINARY)
dilated = cv2.dilate(thresh, None, iterations=3)
contours, _ = cv2.findContours(dilated, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
(x, y, w, h) = cv2.boundingRect(contour)
if cv2.contourArea(contour) < 2000:
continue
cv2.rectangle(frame_resize1, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.putText(frame_resize1, "Status: {}".format('Movement'), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255),3)
cv2.imshow("feed", frame_resize1)
frame_resize1 = frame_resize2
ret, frame_resize2 = cap.read()
if cv2.waitKey(40) == 27:
break
cap.release()
cv2.destroyAllWindows()

detect a single shape and colour in realtime using opencv

I'm working on a project that requires me to detect a red rectangle in real time. so far I've managed to get the colour and shape detected together but it can't differentiate between other objects that are red.
How might I go about doing this?
import cv2
import numpy as np
def nothing():
pass
cap = cv2.VideoCapture(0)
font = cv2.FONT_HERSHEY_COMPLEX
while True:
_, frame = cap.read()
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# Red color
low_red = np.array([175, 50, 20])
high_red = np.array([180, 255, 255])
mask1 = cv2.inRange(hsv, low_red, high_red)
kernel = np.ones((5, 5), np.uint8)
mask2 = cv2.erode(mask1, kernel)
red = cv2.bitwise_and(frame, frame, mask=mask2)
contours, _ = cv2.findContours(mask2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
area = cv2.contourArea(cnt)
approx = cv2.approxPolyDP(cnt, 0.02 * cv2.arcLength(cnt, True), True)
hull = cv2.convexHull(cnt)
x = approx.ravel()[0]
y = approx.ravel()[1]
if area > 400:
cv2.drawContours(frame, [approx], 0, (0, 0, 0), 5)
if len(approx) == 4:
cv2.putText(frame, "Rectangle", (x, y), font, 1, (0, 0, 0))
edges = cv2.Canny(frame, 100, 200)
_, threshold_binary = cv2.threshold(frame, 128, 255, cv2.THRESH_BINARY)
_, threshold_binary_inv = cv2.threshold(frame, 128, 255, cv2.THRESH_BINARY_INV)
_, threshold_trunc = cv2.threshold(frame, 128, 255, cv2.THRESH_TRUNC)
_, threshold_to_zero = cv2.threshold(frame, 12, 255, cv2.THRESH_TOZERO)
cv2.imshow("Frame", frame)
cv2.imshow('edges', edges)
cv2.imshow('red', red)
cv2.imshow("mask", mask1)
key = cv2.waitKey(1)
if key == 27:
cap.release()
cv2.destroyAllWindows()
break
Output image:

OpenCV Background Subtraction Get Color Objects (Python)

Background subtraction method (BackgroundSubtractorMOG2) will normally return the output in binary image.
Is there a solution on how I can get the original colour of the object after implementing the BackgroundSubtractorMOG2 ?
import cv2
import numpy as np
cap = cv2.VideoCapture("people.mkv")
kernel_dil = np.ones((10,10), np.uint8)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
fgbg = cv2.createBackgroundSubtractorMOG2(history=0, varThreshold=444, detectShadows=False)
while True:
ret, frame1 = cap.read()
frame = cv2.resize(frame1,(1364,700),fx=0,fy=0, interpolation = cv2.INTER_CUBIC)
mask = np.zeros(frame.shape, dtype=np.uint8)
mask.fill(255)
roi_corners = np.array([[(11,652), (1353,652), (940,84), (424,84)]], dtype=np.int32)
cv2.fillPoly(mask, roi_corners, 0)
masking = cv2.bitwise_or(frame, mask)
if ret == True:
fgmask = fgbg.apply(masking,mask)
fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)
dilation = cv2.dilate(fgmask2, kernel_dil, iterations = 1)
(contours,hierarchy) = cv2.findContours(dilation, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for pic, contour in enumerate(contours):
area = cv2.contourArea(contour)
x,y,w,h = cv2.boundingRect(contour)
if(area>0.001):
cv2.rectangle(frame, (x,y), (x+w,y+h), (0,0,255), 2)
cv2.putText(frame, 'People', (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255,0,0), 2, cv2.LINE_AA)
cv2.imshow("FullScreen", frame)
cv2.imshow("FGMask1", fgmask)
cv2.imshow("FGMask2", dilation)
key = cv2.waitKey(12)
if key == ord("q"):
break
If you consider the output as binary mask, you could just do a bitwise and with your original image
cv.bitwise_and(input, input, mask = yourMOG_output);

Categories

Resources