Red and yellow triangles detection using openCV in Python - python

I am trying to detect red triangles and yellow triangles differentiating them using openCV in Python. I am a beginner.
I would like, on a first hand, detectecing, counting (yellow and red) and mark with a rectangle all the triangles the camera can see. I would like also to find their mass-center.
For the moment, I just detect one single triangle at a time without finding it color.
My calcul of mass center does not work, giving me the error:
centroid_x = int(M['m10']/M['m00'])
ZeroDivisionError: float division by zero
I have wrote the following code inspired from examples from the web
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
print cap.get(3)
print cap.get(4)
# changing display size
ret = cap.set(3,320)
ret = cap.set(4,240)
def getthresholdedimg(hsv):
yellow = cv2.inRange(hsv,np.array((10,100,100)),np.array((30,255,255)))
red = cv2.inRange(hsv,np.array((0,0,0)),np.array((190,255,255)))
both = cv2.add(yellow,red)
return both
def nothing(x):
pass
# Create a black image, a window
img = np.zeros((300,512,3), np.uint8)
cv2.namedWindow('image')
while(True):
thr1 = 50
thr2 = 110
# Capture frame-by-frame
ret, frame = cap.read()
# Our operations on the frame come here
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gaussian_blur = cv2.GaussianBlur(gray,(5,5),0)
# Our operations on the frame come here
canny = cv2.Canny(gray,thr1,thr2)
canny_blur = cv2.Canny(gaussian_blur,thr1,thr2)
# Our operations on the frame come here
contours,hier = cv2.findContours(canny,1,2)
for cnt in contours:
approx = cv2.approxPolyDP(cnt,0.02*cv2.arcLength(cnt,True),True)
if len(approx)==3:
cv2.drawContours(frame,[cnt],0,(0,255,0),2)
tri = approx
M = cv2.moments(cnt)
centroid_x = int(M['m10']/M['m00'])
centroid_y = int(M['m01']/M['m00'])
cv2.circle(img,(centroid_x,centroid_y),3,255,-1)
for vertex in tri:
cv2.circle(frame,(vertex[0][0],vertex[0][1]),3,(64,0,128),-1)
cv2.line(img,(vertex[0][0],vertex[0][1]),(centroid_x,centroid_y),(0,0,255),1)
# Display the resulting frame
cv2.imshow('normal flux',frame)
cv2.imshow('gray conversion',gray)
cv2.imshow('canny edges conversion',canny)
cv2.imshow('canny edges gaussian blur',canny_blur)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
Can you help me please?

Maybe you want to do
M = cv2.moments(tri)
instead of M = cv2.moments(cnt) ?

Your camera might not be reading it.
Try this after your cap = cv2.videoCapture(0):
while(1):
# Gets retval and frames from each video
ret ,frame = cap.read()
#Check to see if retval is not None or empty
if not ret
break;

Related

Segment black AND moving Pixels

I’m trying to segment the moving propeller of this Video. My approach is, to detect all black and moving pixels to separate the propeller from the rest.
Here is what I tried so far:
import numpy as np
import cv2
x,y,h,w = 350,100,420,500 # Croping values
cap = cv2.VideoCapture('Video Path')
while(1):
_, frame = cap.read()
frame = frame[y:y+h, x:x+w] # Crop Video
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower_black = np.array([0,0,0])
upper_black = np.array([360,255,90])
mask = cv2.inRange(hsv, lower_black, upper_black)
res = cv2.bitwise_and(frame,frame, mask= mask)
nz = np.argwhere(mask)
cv2.imshow('Original',frame)
cv2.imshow('Propeller Segmentation',mask)
k = cv2.waitKey(30) & 0xff # press esc to exit
if k == 27:
break
cap.release()
cv2.destroyAllWindows()
Screenshot form the Video
Result of the Segmentation
With function cv.createBackgroundSubtractorMOG2()
I think you should have a look at background subtraction. It should be the right approach for your problem.
OpenCV provides a good tutorial on this: Link

Understanding how to deploy python code to pop up balloons

I'm a newbie in programming and I need to write code to detect balloon on the fixed background using numpy and openCV in live video and to return the centre of the object [balloon].
Sorry about the ignorance of the questions.
Since I'm new, I had troubles with thinking about the logic of doing it, I don't have the resources to "teach the machine" and creating cascade XML to detect balloons so I thought about 1 possible solution :
Using cv2.createBackgroundSubtractorMOG2() to detect motion with the same background and once there is some object [balloon], count all the white pixels in the live video and return the centre of it, with the right threshold amount of white pixels.
The problem is, I don't know how to get the value of the pixel from 0-255 to know if it's white or black and shows the video at the same time, I think that there is a much easier way that I couldn't find guides for it.
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
fgbg = cv2.createBackgroundSubtractorMOG2()
while(1):
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
fgmask = fgbg.apply(gray)
img_arr = np.array(fgmask)
cv2.imshow('frame',fgmask)
for i in fgmask:
for j in i:
print(fgmask)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
cap.release()
cv2.destroyAllWindows()
I'm getting fray video on the output and lots of values that I don't know how to understand them on the output.
I would use
changes = (fgmask>200).sum()
to compare all pixels with almost white value (>200) and count these pixels.
And then I can compare result with some value to treat it as move.
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
fgbg = cv2.createBackgroundSubtractorMOG2()
while True:
ret, frame = cap.read()
if frame is None:
break
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
fgmask = fgbg.apply(gray)
#changes = sum(sum(fgmask>200))
changes = (fgmask>200).sum()
is_moving = (changes > 10000)
print(changes, is_moving)
cv2.imshow('frame', fgmask)
k = cv2.waitKey(10) & 0xff
if k == 27:
break
cv2.destroyAllWindows()
cap.release()
print() needs some time to display text so printing all pixels (many times in loop) can slow down program. So I skip this. I don't have to know values of all pixels.
EDIT: Using answer in how to detect region of large # of white pixels using opencv? and add code which can find white regions and draw rectangle. Program opens two window - one with grayscale fgmask and other with RGB frame and they can be hidden one behind another. You have to move one window to see another.
EDIT: I added code which use cv2.contourArea(cnt) and (x,y,w,h) = cv2.boundingRect(cnt) to create list with items (area,x,y,w,h) for all counturs and then get max(items) to get contour with the biggest area. And then it use (x + w//2, y + h//2) as center for red circle.
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
fgbg = cv2.createBackgroundSubtractorMOG2()
while True:
ret, frame = cap.read()
if frame is None:
break
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
fgmask = fgbg.apply(gray)
#changes = sum(sum(fgmask>200))
changes = (fgmask>200).sum() #
is_moving = (changes > 10000)
print(changes, is_moving)
items = []
contours, hier = cv2.findContours(fgmask, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
area = cv2.contourArea(cnt)
if 200 < area:
(x,y,w,h) = cv2.boundingRect(cnt)
cv2.rectangle(fgmask, (x,y),(x+w,y+h),255, 2)
cv2.rectangle(frame, (x,y),(x+w,y+h),(0,255,0), 2)
items.append( (area, x, y, w, h) )
if items:
main_item = max(items)
area, x, y, w, h = main_item
if w > h:
r = w//2
else:
r = h//2
cv2.circle(frame, (x+w//2, y+h//2), r, (0,0,255), 2)
cv2.imshow('fgmask', fgmask)
cv2.imshow('frame', frame)
k = cv2.waitKey(10) & 0xff
if k == 27:
break
cv2.destroyAllWindows()
cap.release()

How this code can be modified to improve it's stability to detect eye gaze/pupil?. In low light this code is performing really bad

I am using hough-circle transform to detect eye pupil. If there is any shade or abit low light it gets detecting unusual circles around the eyes. I have tried several filters but did not work that much.
I have tried gaussian blur, median blur and blur to reduce the noise but not getting that much results.
import numpy as np
import cv2
cap = cv2.VideoCapture(1)
count=0
while True:
# Capture frame-by-frame
_, frame = cap.read()
roi = frame[0: 480, 0: 840]
cv2.imshow("roi",roi)
cimg = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
lower_black = np.array([0, 0, 0])
upper_black = np.array([180, 255, 50])
mask = cv2.inRange(cimg, lower_black, upper_black)
mask = cv2.blur(mask,(9,9),0)
# mask = cv2.medianBlur(mask,)
#circles = cv2.HoughCircles(cimg,cv2.HOUGH_GRADIENT,1,300,param1=300,param2=20,minRadius=10,maxRadius=40)
# circles = cv2.HoughCircles(grey,cv2.HOUGH_GRADIENT,minDist=30,minRadius=0,maxRadius=0)
#circles = cv2.HoughCircles(cimg,cv2.HOUGH_GRADIENT,100,200)
circles = cv2.HoughCircles(mask,cv2.HOUGH_GRADIENT,1,300,param1=300,param2=20,minRadius=10,maxRadius=40)
if circles is None:
cv2.imshow("roi",mask)
print ("Not Found")
continue
a =circles.tolist()
lst1=[item[0] for item in a[0]]
lst2=[item[1] for item in a[0]]
i=0
left_x=0
right_x=0
while i < len(lst1):
if (i==0):
left_x=lst1[i]
if (i==1):
right_x=lst1[i]
i=i+1
i=0
left_y=0
right_y=0
while i < len(lst2):
if (i==0):
left_y=lst2[i]
if (i==1):
right_y=lst2[i]
i=i+1
print("whole List")
print(a)
print("Left_X",left_x)
print("Right_X",right_x)
print("Left_y",left_y)
print("Right_y",right_y)
for i in circles[0,:]:
cv2.circle(mask,(i[0],i[1]),i[2],(0,255,0),2)
# draw the center of the circle
cv2.circle(mask,(i[0],i[1]),2,(0,0,255),3)
# Display the resulting frame
cv2.imshow('hsv',mask)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
I want to detect the pupils. The circles need to be stable.

Drone Feedback: Object Detection / Color Detection? Is there way just to isolate detection on a specific object

I have been working on a code where an A.R Drone 2.0 will detect color and put a red dot in the middle of the image. I am using streaming for the drone. The goal is for the drone to detect a white gutter and fly straight over it from one point to the other. Essentially following a line. I noticed when I changed the BGR to 0, 0, 255, I get the entire gutter to be distinguished but it detects white spots as well. Is there to isolate my detection just to see the gutter. Maybe using shapes, once the gutter is detected, put a bounding box. And my finally question is how do I tell my drone to follow the red dot or maybe drawing a line. I looked at python-AR drone libraries but don't know how to apply it.This is my code.
import numpy as np
import cv2
# open the camera
cap = cv2.VideoCapture('tcp://192.168.1.1:5555')
def nothing(x):
pass
cv2.namedWindow('result')
# Starting with 100's to prevent error while masking
h,s,v = 100,100,100
# Creating track bar
cv2.createTrackbar('h', 'result',0,179,nothing)
cv2.createTrackbar('s', 'result',0,255,nothing)
cv2.createTrackbar('v', 'result',0,255,nothing)
while True:
#read the image from the camera
ret, frame = cap.read()
#You will need this later
frame = cv2.cvtColor(frame, 35)
#converting to HSV
hsv = cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
# get info from track bar and appy to result
h = cv2.getTrackbarPos('h','result')
s = cv2.getTrackbarPos('s','result')
v = cv2.getTrackbarPos('v','result')
# Normal masking algorithm
lower_blue = np.array([h,s,v])
upper_blue = np.array([180,255,255])
mask = cv2.inRange(hsv,lower_blue, upper_blue)
result = cv2.bitwise_and(frame,frame,mask = mask)
cv2.imshow('result',result)
#find center
cnts=cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]
center=None
if len(cnts)>0:
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"]))
if radius>10:
#cv2.circle(frame, (int(x),int(y)), int(radius), 2)
cv2.circle(frame, center,5,(0,0,255),-1)
# color detection limits
lB = 5
lG = 50
lR = 50
hB = 15
hG = 255
hR = 255
lowerLimits = np.array([lB, lG, lR])
upperLimits = np.array([hB, hG, hR])
# Our operations on the frame come here
thresholded = cv2.inRange(frame, lowerLimits, upperLimits)
outimage = cv2.bitwise_and(frame, frame, mask = thresholded)
cv2.imshow('original', frame)
# Display the resulting frame
cv2.imshow('processed',outimage)
# Quit the program when Q is pressed
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
print 'closing program'
cap.release()
cv2.destroyAllWindows()

Find the red circle in video

I want to track a moving cap of a coke bottle in the webcam Feed with OpenCV in Python (or C++). I tried to search for all the red in the frame and then I used some kind of HOUGH TRANSFORM to search for circles.
I cant find the right radius for the circle and fix it so it doesn't change every frame.the process time is not so important I dont want a real time detection but I do want a precise red circle detection.
This is what I have so far:
import cv2
import numpy as np
import cv2.cv as cv
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_red = np.array([160,140,50])
upper_red = np.array([180,255,255])
imgThreshHigh = cv2.inRange(hsv, lower_red, upper_red)
imgray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
thresh = 18
edges = cv2.Canny(imgray,thresh,thresh*3)
circles = cv2.HoughCircles(imgThreshHigh, cv.CV_HOUGH_GRADIENT, 1, 500, 25, 75, 5, 15)
maxRadius= 0
xc = 0.00
yc = 0.00
found = False
if circles is not None:
found = True
for i in circles[0,:3]:
if i[2] < 100:
if i[2] > maxRadius:
maxRadius = i[2]
if maxRadius > 1.0:
# draw the outer circle
cv2.circle(frame,(i[0],i[1]),maxRadius,(0,0,255),2)
# draw the center of the circle
cv2.circle(frame,(i[0],i[1]),1,(0,0,255),3)
xc = i[0]
yc = i[1]
if found:
print "ball detected at position:",xc, ",", yc, " with radius:", maxRadius
else:
print "no ball"
cv2.imshow('frame',frame)
cv2.imshow('edges',edges)
k = cv2.waitKey(5) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
I dont think HOUGH TRANSFORM works for this. So I want to use the edges.
How can I use an equation like (X-Xc)^2 + (Y-Yc)^2 =R^2 and the contours to find circles?
Also if there is an improvement for Hough Transform I will appreciate it if you share with me
Contours:
contours,hierarchy=cv2.findContours(edges,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
My example image: ---> this is not my example Image.this is the object I want to find in videos.
Well for the color you have to find the right range, for the human eye the bottle cap is red, but for the camera could be orange or something like that. Also is affected by the light so the camera could get some white. I learned this on the hard way haha. You could do a code with trackbars and hsv values to get the exact rang for your objet.
Now, are you looking for the center (x,y)? You can try with cv2.moments()
and for
Here is an example
For your code is something like this
import cv2
import numpy as np
import cv2.cv as cv
cap = cv2.VideoCapture(0)
coords = []
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([160,140,50])
upper_red = np.array([180,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)
if area > max_area:
max_area = area
best_cnt = cnt
M = cv2.moments(best_cnt)
cx,cy = int(M['m10']/M['m00']), int(M['m01']/M['m00'])
coord = cx, cy #This are your coordinates for the circle
# area = moments['m00'] save the object area
#perimeter = cv2.arcLength(best_cnt,True) is the object perimeter
#Save the coords every frame on a list
#Here you can make more conditions if you don't want repeated coordinates
points.append(coord)
cv2.imshow('frame',frame)
cv2.imshow('Object',thresh)
k = cv2.waitKey(5) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
With moments you don't have the raidius hough transform that you mentioned because calculate the relative center of the object every time.
Here is the code I use to know which is the exact value, hope it helps you HSV detection code

Categories