detect a single shape and colour in realtime using opencv - python

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:

Related

Camera unable to detect multiple colours in 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)

Python opencv Defect detection

I am trying to detect foreign substances in a round circle using opencv.
However, if the threshold is increased, the area around the circle is distorted, and if the threshold is decreased, foreign matter cannot be detected. Is there a way to detect foreign matter well while maintaining the circle?
import cv2
import cv2 as cv
import numpy as np
def roiSetting():
img = cv2.imread('img.jpg')
x = 100; y = 10;
w = 700; h = 600;
img_roi = img[400:1250,600:1450] #[colStart:colEnd, rowStart:rowEnd]
cv2.imwrite("3_roi_img.jpg", img_roi)
return img_roi
def imgCvt():
print("imgCvt in")
roi_img = roiSetting()
bgr_img = cv2.cvtColor(roi_img,cv2.COLOR_RGB2BGR) #RGB->BGR convert
bila_img = cv2.bilateralFilter(bgr_img,9,100,100) #bilaterafilter apply
r,g,b=cv2.split(bila_img) #split
merge_img=cv2.merge((r,g,b)) #merge
gray_img = cv2.cvtColor(merge_img,cv2.COLOR_RGB2GRAY) #RGB->GRAY convert
ret,thresh_img = cv2.threshold(gray_img, 0, 255, cv2.THRESH_OTSU+cv2.THRESH_BINARY) #threshold apply
equalize_img = cv2.equalizeHist(thresh_img) #Histogram equlization
canny_img = cv2.Canny(equalize_img,250,255) #Canny edge
kernel = np.ones((2,2), np.uint8)
dilate_img = cv2.dilate(canny_img, kernel, iterations = 1) # img dilate
new, contours, hierarchy = cv2.findContours(dilate_img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours= sorted(contours, key = cv2.contourArea, reverse = True)[:10] #sorting
print(contours)
c = contours[0]
mask = np.zeros(roi_img.shape,np.uint8) #mask create(roi_img.shape)
cont_image = cv2.drawContours(mask, [c], -1, (255, 255, 255), -1) #background remove
con_gray_img = cv2.cvtColor(cont_image, cv2.COLOR_BGR2GRAY)
ret, thresh1 = cv2.threshold(con_gray_img, 0, 255, cv2.THRESH_OTSU+cv2.THRESH_BINARY)
last_img = cv2.bitwise_and(roi_img, roi_img, mask = thresh1)
kernel = np.ones((3,3), np.uint8)
src = cv2.erode(last_img, kernel, iterations = 2)
gray = cv2.cvtColor(src, cv2.COLOR_RGB2GRAY)
rt1, dst1 = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU+cv2.THRESH_BINARY)
rt1, dst2 = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
_, contour1, _ = cv.findContours(dst2, cv2.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
for cnt in contour1:
cv2.drawContours(roi_img, [cnt], 0, (255, 0, 0), 2, cv2.LINE_8)
cv2.imshow('cont_roi.jpg', roi_img)
cv2.waitKey()
cv2.destroyAllWindows()
if __name__ == '__main__':
imgCvt()

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

How do I fix openCV cvtColor error in my project?

I am building handwriting recognition project but I am getting this error of cvtColor while trying to change the image from BGR2HSV.
cap = cv2.VideoCapture(0)
Lower_blue = np.array([110, 50, 50])
Upper_blue = np.array([130, 255, 255])
pred_class = 0
pts = deque(maxlen = 512)
blackboard = np.zeros((480, 640, 3), dtype = np.uint8)
digit = np.zeros((200, 200, 3), dtype = np.uint8)
while(cap.isOpened()):
ret, img = cap.read()
img = cv2.flip(img, 1)
imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(imgHSV, Lower_blue, Upper_blue)
blur = cv2.medianBlur(mask, 15)
blur = cv2.GaussianBlur(blur, (5, 5), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(thresh.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[1]
center = None
if len(cnts) >= 1:
contour = max(cnts, key = cv2.contourArea)
if cv2.contourArea(contour) > 250:
((x, y), radius) = cv2.minEnclosingCircle(contour)
cv2.circle(img, (int(x), int(y)), int(radius), (0, 255, 255), 2)
cv2.circle(img, center, 5, (0, 255, 255), -1)
M = cv2.moments(contour)
center = (int(M['m10'] / M['m00']), int(M['m01'] / M['m00']))
pts.appendleft(center)
for i in range (1, len(pts)):
if pts[i - 1] is None or pts[i] is None:
continue
cv2.line(blackboard, pts[i - 1], pts[i], (255, 255, 255), 10)
cv2.line(img, pts[i - 1], pts[i], (0, 0,255), 5)
elif len(cnts) == 0:
if len(pts) != []:
blackboard_gray = cv2.cvtColor(blackboard, cv2.COLOR_BGR2GRAY)
blur1 = cv2.medianBlur(blackboard_gray, 15)
blur1 = cv2.GaussianBlur(blur1, (5, 5), 0)
thresh1 = cv2.threshold(blur1, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
blackboard_cnts = cv2.findContours(thresh1.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[1]
if len(blackboard_cnts) >= 1:
cnt = max(blackboard_cnts, key = cv2.contourArea)
print(cv2.contourArea(cnt))
if cv2.contourArea(cnt) > 2000:
x, y, w, h = cv2.boundingRect(cnt)
digit = blackboard_gray[y:y + h, x:x + w]
#new Image = process_letter(digit)
pred_probab, pred_class = keras_predict(model1, digit)
print(pred_class, pred_probab)
pts = deque(maxlen = 512)
blackboard = np.zeros((480, 640, 3), dtype = uint8)
cv2.putText(img, "Conv Network : " + str(letter_count [pred_class]), (10, 470),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
cv2.imshow("Frame", img)
cv2.imshow("Contours", thresh)
k = cv2.waitkey(10)
if k == 27:
break
How do I fix this issue of OpenCV error? Please help!
I am getting following error:
error: OpenCV(3.4.1) C:\Miniconda3\conda-bld\opencv-suite_1533128839831\work\modules\imgproc\src\color.cpp:11214: error: (-215) (scn == 3 || scn == 4) && (depth == 0 || depth == 5) in function cv::cvtColor
I think following error: error: (-215) (scn == 3 || scn == 4) && (depth == 0 || depth == 5) in function cv::cvtColor is because of camera unable to capture frame correctly. Check this by printing ret value. It camera is able to capture frame correctly, it will return True, else False. Above error is happening because None is passed to cv2.cvtColor function. You can use below code as a safety check:
if ret is True:
# your code goes here
else:
break
Moreover, please consider below points:
It's cv2.waitKey(10), not cv2.waitkey(10)[Capital 'K']
cv2.findContours function return 3 values(i.e. image, contours and hierarchy) in OpenCV 3.x but just 2 values(i.e. contours, hierarchy) in openCV 4.x
len(pts) != [] doesn't make sense. Here, you are trying to compare a number to an empty list. Change it to len(pts) != 0.
What's letter_count inside cv2.putText function. Kindly recheck it.
In place of re-initializing deque(pts = deque(maxlen = 512)) in case of len(cnts)==0 and len(pts) != 0, you can use the old pts by simply clearing it using pts.clear(). Just a thought!
Also, add below code at the end:
cap.release()
cv2.destroyAllWindows()
Try below modified code(Tested using openCV v4.0.0):
import cv2
import numpy as np
from collections import deque
cap = cv2.VideoCapture(0)
Lower_blue = np.array([110, 50, 50])
Upper_blue = np.array([130, 255, 255])
pred_class = 0
pts = deque(maxlen = 512)
blackboard = np.zeros((480, 640, 3), dtype = np.uint8)
digit = np.zeros((200, 200, 3), dtype = np.uint8)
while(cap.isOpened()):
ret, img = cap.read()
img = cv2.flip(img, 1)
imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(imgHSV, Lower_blue, Upper_blue)
blur = cv2.medianBlur(mask, 15)
blur = cv2.GaussianBlur(blur, (5, 5), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(thresh.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[0]
center = None
if len(cnts) >= 1:
contour = max(cnts, key = cv2.contourArea)
if cv2.contourArea(contour) > 250:
((x, y), radius) = cv2.minEnclosingCircle(contour)
cv2.circle(img, (int(x), int(y)), int(radius), (0, 255, 255), 2)
cv2.circle(img, center, 5, (0, 255, 255), -1)
M = cv2.moments(contour)
center = (int(M['m10'] / M['m00']), int(M['m01'] / M['m00']))
pts.appendleft(center)
# print(pts)
for i in range (1, len(pts)):
if pts[i - 1] is None or pts[i] is None:
print("Continue")
continue
cv2.line(blackboard, pts[i - 1], pts[i], (255, 255, 255), 10)
cv2.line(img, pts[i - 1], pts[i], (0, 0,255), 5)
cv2.imshow("Frame", img)
cv2.imshow("Contours", thresh)
# press q to stop
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
if len(pts) != 0:
blackboard_gray = cv2.cvtColor(blackboard, cv2.COLOR_BGR2GRAY)
blur1 = cv2.medianBlur(blackboard_gray, 15)
blur1 = cv2.GaussianBlur(blur1, (5, 5), 0)
thresh1 = cv2.threshold(blur1, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
print('Hello')
blackboard_cnts = cv2.findContours(thresh1.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[0]
if len(blackboard_cnts) >= 1:
cnt = max(blackboard_cnts, key = cv2.contourArea)
print(cv2.contourArea(cnt))
if cv2.contourArea(cnt) > 2000:
x, y, w, h = cv2.boundingRect(cnt)
digit = blackboard_gray[y:y + h, x:x + w]
#new Image = process_letter(digit)
#pred_probab, pred_class = keras_predict(model1, digit)
print(digit.shape)
#pts = deque(maxlen = 512)
pts.clear()
blackboard = np.zeros((480, 640, 3), dtype = np.uint8)
#cv2.putText(img, "Conv Network : " + str(letter_count[pred_class]), (10, 470), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
cv2.putText(img, "Conv Network :", (10, 470), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
cv2.imshow("Frame", img)
cv2.imshow("Contours", thresh)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()

Placing a png image inside a tracked ball, OpenCV,Python

I am using OpenCV to track a ball with webcam footage, i combined two scripts i found on the internet, but now I would like to take a png image and place it resized in the center of the tracked circle and have it scale proportionally with the bounding circle tracking.
I tried the sublime robots, mustache tutorial, but i am getting a bit lost with the region of interest and resizing the image, any help would be much appreciated.
import numpy as np
import cv2
import time
import imutils
import math
import os
uniImg = cv2.imread('unicorn1.png')
def nothing(*arg):
pass
cap = cv2.VideoCapture(0)
#Initial HSV GUI slider values to load on program start.
icol = (36, 202, 59, 71, 255, 255) # Green
icol = (18, 0, 196, 36, 255, 255) # Yellow
icol = (89, 0, 0, 125, 255, 255) # Blue
icol = (0, 100, 80, 10, 255, 255) # Red
icol = (104, 117, 222, 121, 255, 255) # test
icol = (0, 0, 0, 255, 255, 255) # New start
icol2 = (0, 0, 0, 255, 255, 20) # New start
icol3 = (0, 0, 0, 255, 255, 20) # New start
cv2.namedWindow('colorTest')
# Lower range colour sliders.
cv2.createTrackbar('lowHue', 'colorTest', icol[0], 255, nothing)
cv2.createTrackbar('lowSat', 'colorTest', icol[1], 255, nothing)
cv2.createTrackbar('lowVal', 'colorTest', icol[2], 255, nothing)
# Higher range colour sliders.
cv2.createTrackbar('highHue', 'colorTest', icol[3], 255, nothing)
cv2.createTrackbar('highSat', 'colorTest', icol[4], 255, nothing)
cv2.createTrackbar('highVal', 'colorTest', icol[5], 255, nothing)#
cv2.createTrackbar('erode','colorTest',icol2[5], 20, nothing)
cv2.createTrackbar('dilate','colorTest',icol3[5], 20, nothing)
while(1):
timeCheck = time.time()
lowHue = cv2.getTrackbarPos('lowHue', 'colorTest')
lowSat = cv2.getTrackbarPos('lowSat', 'colorTest')
lowVal = cv2.getTrackbarPos('lowVal', 'colorTest')
highHue = cv2.getTrackbarPos('highHue', 'colorTest')
highSat = cv2.getTrackbarPos('highSat', 'colorTest')
highVal = cv2.getTrackbarPos('highVal', 'colorTest')
erode = cv2.getTrackbarPos('erode', 'colorTest')
dilate = cv2.getTrackbarPos('dilate', 'colorTest')
_, frame = cap.read()
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# Get HSV values from the GUI sliders.
# define range of white color in HSV
# change it according to your need !
colorLow = np.array([lowHue,lowSat,lowVal])
colorHigh = np.array([highHue,highSat,highVal])
# Threshold the HSV image to get only white colors
mask = cv2.inRange(hsv, colorLow, colorHigh)
mask = cv2.erode(mask, None, iterations= erode)
mask = cv2.dilate(mask, None, iterations= dilate)
# Bitwise-AND mask and original image
res = cv2.bitwise_and(frame,frame, mask= mask)
# find contours in the mask and initialize the current
# (x, y) center of the ball
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]
center = None
# only proceed if at least one contour was found
if len(cnts) > 0:
# find the largest contour in the mask, then use
# it to compute the minimum enclosing circle and
# centroid
c = max(cnts, key=cv2.contourArea)
((x, y), radius) = cv2.minEnclosingCircle(c)
M = cv2.moments(c)
center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
# only proceed if the radius meets a minimum size
if radius > 10:
# draw the circle and centroid on the frame,
# then update the list of tracked points
cir = cv2.circle(frame, (int(x), int(y)), int(radius),
(0, 255, 255), 2)
cv2.imshow('frame',frame)
cv2.imshow('mask',mask)
cv2.imshow('res',res)
k = cv2.waitKey(5) & 0xFF
if k == 27:
break

Categories

Resources