I have a pair of black scissors (image below) and I want to calculate its angle. The angle is between 180 and 0.so I used cv2.line() to get two lines for angle calculation but I could only detect angel if its 180 or 0.how can I find a " > " shape with contours?(the handle is also black)
#Decapitary
import cv2
import numpy as np
import cv2.cv as cv
import math
import sys
cap = cv2.VideoCapture(0)
max_area =0
while(1):
# Take each frame
_, frame = cap.read()
# Convert BGR to HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower_black = np.array([0,0,0])
upper_black = np.array([180,255,30])
mask= cv2.inRange(hsv, lower_red, upper_red)
mask = cv2.GaussianBlur(mask,(1,1),2)
mask = cv2.dilate(mask, np.ones((7,7),np.uint8))
mask = cv2.erode(mask, np.ones((5,5),np.uint8))
edges = cv2.Canny(mask,thresh,thresh*5)
contours, hierarchy = cv2.findContours(edges,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) ### use this to calculte the angel.
for c in contours:
area = cv2.contourArea(c)
if area > max_area:
max_area = area
yu = c
nss = np.asarray(yu,dtype=np.int32)
cv2.polylines(frame, [nss], 0 , (0,0,250))
cv2.imshow('frame',frame)
cv2.imshow('edges',edges)
cv2.imshow('mask',mask)
k = cv2.waitKey(5) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
Im open to ideas and really need help.just show me the right direction please
EDIT:
Can I train a cascade to find a specific point a an object(in this case 3points on edges to calculate angel) ???
Related
I'm using Python3 and OpenCV (4.6.0) to realize a script that:
detects a specific color tone (green) and draw (with the use of the polyline) the path followed by the green object during the use of the webcam.
calculates the distance traveled by the object.
So far, I'm trying:
import numpy as np
import cv2
from math import dist
cap = cv2.VideoCapture(0)
distance=0
distcm=0
centroide={}
mask={}
centroide[0]=(0,0)
i=1
while True:
ret, frame = cap.read()
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower_green = np.array([50, 50, 50])
upper_green = np.array([70, 255, 255])
mask = cv2.inRange(hsv, lower_green, upper_green)
result = cv2.bitwise_and(frame, frame, mask=mask)
contourns,hierarchy = cv2.findContours(mask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cont_sorted = sorted(contourns, key=cv2.contourArea, reverse=True)[:5]
for each in contourns:
area= cv2.contourArea(each)
if len(cont_sorted) > 0 and area>300 :
x,y,w,h = cv2.boundingRect(cont_sorted[0])
centroide[i]=[x+(w/2), y+(h/2)]
distance+= dist(centroide[i],centroide[i-1])
cv2.rectangle(frame,(x,y),(x+w,y+h),(0,0,255),5)
mask=cv2.line(frame,(int(centroide[i-1][0]), int(centroide[i-1][1])),(int(centroide[i][0]),int(centroide[i][1])),(255,0,0),5)
#mask=cv2.polylines(frame,np.int32(np.array(centroide)),(255,0,0),5)
i=i+1
cv2.imshow('orig',frame)
distancecm=distance*0.0264583333;
print('distancia en cm:',distancecm)
if cv2.waitKey(30) == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
With the previous code what it does is only to create a line between one centroid and another but the line of previous centroids does not remain static to observe the path of the object. Any suggestions?
Thanks
LJ
My code does the following :
Grab the video frame.
Convert the video frame to the HSV colour space.
Split the frame into individual components (separate images for H, S, and V).
Apply a threshold to each component
Locates the centroid and applies the bounding circle
I can find the two largest contours. From the two largest indexed contours how do I calculate the moments for these contours to find the centroid?
Here is an example image to help. Blue are the centroids, Red is the minimum enclosing circle and white are the laser pointers (After the threshold has been applied).
#Dependacies import
from cmath import inf
from pickle import FRAME
import cv2
from matplotlib.pyplot import hsv
import numpy as np
import imutils
# Video Capture
cap = cv2.VideoCapture(0)
if (cap.isOpened()== False):
print("Error opening video stream or file")
# Read until video is completed
while(cap.isOpened()):
# Capture frame-by-frame
ret, frame = cap.read() #reading video
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) #Making hsv frame
red_lower = np.array ([16, 132, 0])
red_upper = np.array ([20, 236, 255])
mask = cv2.inRange (hsv,red_lower,red_upper)
res = cv2.bitwise_and(frame,frame, mask= mask)
thresh = cv2.cvtColor(res, cv2.COLOR_BGR2GRAY)
if ret== True:
contours, hiearachy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cnt = sorted(contours,key=cv2.contourArea)
print ('Number of contours found = ', len(contours))
if len(contours) >= 2:
def get_contour_areas(contours):
all_areas = []
for cnt in contours:
area = cv2.contourArea(cnt)
all_areas.append(area)
return all_areas
sorted_contours= sorted(contours, key=cv2.contourArea, reverse= True)
largest_item= sorted_contours[0]
second_item= sorted_contours[1]
cv2.drawContours(frame, largest_item, -1, (255,0,0),1)
cv2.drawContours(frame, second_item, -1, (255,0,0),1)
if ret == True:
cv2.imshow('Frame',frame)
cv2.imshow('mask', mask)
cv2.imshow('gray', thresh)
# Press Q on keyboard to exit
if cv2.waitKey(25) & 0xFF == ord('q'):
break
# Break the loop
else:
break
# When everything done, release the video capture object
cap.release()
# Closes all the frames
cv2.destroyAllWindows()
I'm new to opencv and for a school project i need to detect a red and a green circle with a camera, so i've use blobdetection, but it detect me the two colors, i think that my mask is bad, each color is linked to a specific action.
At the moment my code detect well red and green circle on the same page but i want it to detect only red circle on a white page.
Thank for your help
# Standard imports
import cv2
import numpy as np;
# Read image
im = cv2.VideoCapture(0)
# Setup SimpleBlobDetector parameters.
params = cv2.SimpleBlobDetector_Params()
# Change thresholds
params.minThreshold = 100;
params.maxThreshold = 200;
# Filter by Area.
params.filterByArea = True
params.minArea = 200
params.maxArea = 20000
# Filter by Circularity
params.filterByCircularity = True
params.minCircularity = 0.1
# Filter by Convexity
params.filterByConvexity = True
params.minConvexity = 0.1
# Filter by Inertia
params.filterByInertia = True
params.minInertiaRatio = 0.1
blueLower = (0,85,170) #100,130,50
blueUpper = (140,110,255) #200,200,130
while(1):
ret, frame=im.read()
mask = cv2.inRange(frame, blueLower, blueUpper)
mask = cv2.erode(mask, None, iterations=0)
mask = cv2.dilate(mask, None, iterations=0)
frame = cv2.bitwise_and(frame,frame,mask = mask)
# Set up the detector with default parameters.
detector = cv2.SimpleBlobDetector_create(params)
# Detect blobs.
keypoints = detector.detect(mask)
# Draw detected blobs as red circles.
# cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ensures the size of the circle corresponds to the size of blob
im_with_keypoints = cv2.drawKeypoints(mask, keypoints, np.array([]), (0,0,255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
# Display the resulting frame
frame = cv2.bitwise_and(frame,im_with_keypoints,mask = mask)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
im.release()
cv2.destroyAllWindows()
EDIT 1: Code update
Now i got a issue where my full circle isn't detected.
No Blob Detection
Second Version
# Standard imports
import cv2
import numpy as np;
# Read image
im = cv2.VideoCapture(0)
while(1):
ret, frame=im.read()
lower = (130,150,80) #130,150,80
upper = (250,250,120) #250,250,120
mask = cv2.inRange(frame, lower, upper)
lower, contours, upper = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
blob = max(contours, key=lambda el: cv2.contourArea(el))
M = cv2.moments(blob)
center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
canvas = im.copy()
cv2.circle(canvas, center, 2, (0,0,255), -1)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
im.release()
cv2.destroyAllWindows()
You need to work out what the BGR numbers for your green are (let's say for arguments sake [0, 255, 0]), then create a mask that ignores any colours outside a tolerance around your green:
mask = cv2.inRange(image, lower, upper)
Take a look at this tutorial for a step by step.
Play around with lower and upper to get the right behaviour. Then you can find the contours in the mask:
_, contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_NONE)
Then go through the contours list to find the biggest one (filter out any possible noise):
blob = max(contours, key=lambda el: cv2.contourArea(el))
And that's your final 'blob'. You can find the center by doing:
M = cv2.moments(blob)
center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
You can draw this center onto a copy of your image, for checking:
canvas = im.copy()
cv2.circle(canvas, center, 2, (0,0,255), -1)
Obviously, this makes the assumption that there's only one green ball and nothing else green in the image. But it's a start.
EDIT - RESPONSE TO SECOND POST
I think the following should work. I haven't tested it, but you should be able to at least do a bit more debugging with the canvas and mask displayed:
# Standard imports
import cv2
import numpy as np;
# Read image
cam = cv2.VideoCapture(0)
while(1):
ret, frame = cam.read()
if not ret:
break
canvas = frame.copy()
lower = (130,150,80) #130,150,80
upper = (250,250,120) #250,250,120
mask = cv2.inRange(frame, lower, upper)
try:
# NB: using _ as the variable name for two of the outputs, as they're not used
_, contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
blob = max(contours, key=lambda el: cv2.contourArea(el))
M = cv2.moments(blob)
center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
cv2.circle(canvas, center, 2, (0,0,255), -1)
except (ValueError, ZeroDivisionError):
pass
cv2.imshow('frame',frame)
cv2.imshow('canvas',canvas)
cv2.imshow('mask',mask)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
im.release()
cv2.destroyAllWindows()
You should use HSV color space for better results if you wanna make filter by color.
ret, frame=im.read()
frame= cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) # Add this to your code
mask = cv2.inRange(frame, blueLower, blueUpper)
I am working on a line follower bot which follows black line on white background The code is something like this
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
try:
while(1):
## Read the image
ret, img = cap.read()
#cv2.imshow('image',img)
img = img[160:320,:,:]
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,170,255,cv2.THRESH_BINARY_INV)
#Applying Dilation Morphological Operation To Dilate the image
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
dilation = cv2.dilate(thresh, kernel, iterations = 5)
#Apllying Gaussian Bluring Algorithm to reduce the number of contours
blur3 = cv2.medianBlur (dilation,5)
i = 0
contours, hierarchy = cv2.findContours(blur3,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img,contours,-1,(0,255,0),3)
cv2.imshow('image',img)
M = cv2.moments(contours[i])
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
if cx < 190:
print "LEFT"
if cx > 450:
print "RIGHT "
if ((cx > 189) & (cx < 449)):
print "FRONT"
finally:
cap.release()
cv2.destroyAllWindows()
I want to also detect blue and red color while the bot is following the line using the same camera.
I tried reading center pixel of the centroid center_px = img[cy,cx]
But reading just one pixel dosent prove efficient in determining the color.
So is there any other approach to do this
I am using python2.7 with cv2
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