Shape & color detection in python and opencv - python

i found this code on GitHub and it is a function that serves to find circles based on camera frames, yet my problem is that i would like to modify it so that i could choose which shape it has to find. I tried to do it for a square but unfortunately i couldn't do it.
Is there someone who could possibly help me?
Thanks a lot
This is the code of the function that find circles:
def find_circles(frame, mask):
contours = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = imutils.grab_contours(contours)
center = None
if len(contours) > 0:
c = max(contours, key=cv2.contourArea)
((x, y), radius) = cv2.minEnclosingCircle(c)
M = cv2.moments(c) #Finds center point
center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
if radius > 10:
cv2.circle(frame, (int(x), int(y)), int(radius),
(0, 255, 255), 2)
cv2.circle(frame, center, 5, (0, 0, 0), -1)
return center

Related

Detecting circle pattern in image using Python & OpenCV

I've got images like this one:
I need to detect the center of this circular element:
(More precisely - I'm looking for the midpoint of the circular element)
Currently my code detect the mold (the plastic circle that holds the circular element) and select the rectangle ROI to focus the image into the relevant area:
import cv2
import imutils
import numpy as np
if __name__ == "__main__":
image = cv2.imread('Dart - Overview Image - with Film.bmp')
img = imutils.resize(image, width=700)
image = img
output = image.copy()
roi = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# cv2.imshow("Gray", gray)
# cv2.waitKey(0)
# detect circles in the image
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1.2, 100)
# ensure at least some circles were found
if circles is not None:
# convert the (x, y) coordinates and radius of the circles to integers
circles = np.round(circles[0, :]).astype("int")
# loop over the (x, y) coordinates and radius of the circles
for (x, y, r) in circles:
# draw the circle in the output image, then draw a rectangle
# corresponding to the center of the circle
cv2.circle(output, (x, y), r, (0, 255, 0), 2)
cv2.rectangle(output, (x - 2, y - 2), (x + 2, y + 2), (0, 128, 255), -1)
roi = roi[y - r: y + r, x - r: x + r]
cv2.imshow("img", roi)
cv2.waitKey(0)
This will show this image:
Now, I'm trying to find the midpoint of the circular element inside this ROI image by detecting the circular element but It's challenged for me, I've try this methods:
gray_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray_roi, (3, 3), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY_INV)[1]
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
for c in cnts:
(x, y), radius = cv2.minEnclosingCircle(c)
cv2.circle(roi, (int(x), int(y)), int(radius), (35, 255, 12), 3)
cv2.circle(roi, (int(x), int(y)), 1, (35, 255, 12), 2)
print(x, y)
break
# Find Canny edges
edged = cv2.Canny(roi, 30, 121, apertureSize=3, L2gradient=True)
cv2.waitKey(0)
# Finding Contours
# Use a copy of the image e.g. edged.copy()
# since findContours alters the image
contours, hierarchy = cv2.findContours(edged,
cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cv2.imshow('Canny Edges After Contouring', edged)
cv2.waitKey(0)
And got this output:
I've also tried to change the threshold parameters in the cv2.Canny function but it's didn't give me better results.
Thanks a lot!

Exclude Part of Video/Image OpenCV Object Recognition/Tracking

I am trying to track a basketball through a short clip using OpenCV. I am using code to help me try to find the correct upper and lower bounds for the color code, but the ball is of very similar color to the game clock near the bottom of the video. How can I cut this off in my object tracking code, so that the program does not simply track the clock? I am using code from this tutorial: https://www.pyimagesearch.com/2015/09/14/ball-tracking-with-opencv/
The code where I think this change would be made is in the following block:
# 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 = imutils.grab_contours(cnts)
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
cv2.circle(frame, (int(x), int(y)), int(radius),
(0, 255, 255), 2)
cv2.circle(frame, center, 5, (0, 0, 255), -1)
I know I haven't provided a MWE but I'm not sure how to do that in this case. I think my question is at least straightforward, if not simple.

Cropping live video feed in OpenCV

I have a live video feed that tracks green objects and draws a rectangle over the object's area. I'm curious as to how I would be able to crop the feed to only show the area that the rectangle encompasses.
Here's the section of relevance:
while True:
(success, frame) = webcam.read()
frame = imutils.resize(frame, width = 1000)
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, greenLower, greenUpper)
mask = cv2.erode(mask, None, iterations=2)
mask = cv2.dilate(mask, None, iterations=2)
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"]))
for c in cnts:
if cv2.contourArea(c) < 500:
continue
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(frame, (x,y), (x+w, y+h), (0, 255, 0), 2)
pts = deque(maxlen = 32)
pts.appendleft(center)
for i in xrange(1, len(pts)):
if pts[i - 1] is None or pts[i] is None:
continue
thickness = int(np.sqrt(args["buffer"] / float(i + 1)) * 2.5)
cv2.line(frame, pts[i - 1], pts[i], (0, 255, 0), thickness)
cv2.imshow("Presentation Tracker", frame)
What you might be looking for is to create a 'Region of Interest(ROI)' using OpenCV Python.
You can do so in your code as shown:
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(frame, (x,y), (x+w, y+h), (0, 255, 0), 2)
roi = frame[y:y+h, x:x+w]
Note that (x,y) corresponds to the top-left point of your rectangle.
The area inside the rect declared above has been stored in Mat roi.

ZeroDivisionError (Python)

I am getting a Zero Division Error with some images (Even though a lot of them work just fine) :
Here's the code :
image = skimage.io.imread('test.png', False)
image_gray = skimage.io.imread('test.png', True)
blurred = cv2.GaussianBlur(img_as_ubyte(image_gray), (5, 5), 0)
thresh = threshold_li(blurred)
binary = blurred > thresh
binary_cv2 = img_as_ubyte(binary)
# find contours in the thresholded image
cnts = cv2.findContours(binary_cv2.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]
# loop over the contours
for c in cnts:
# compute the center of the contour
M = cv2.moments(c)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
# draw the contour and center of the shape on the image
cv2.drawContours(img_as_ubyte(image), [c], -1, (0, 255, 0), 2)
cv2.circle(img_as_ubyte(image), (cX, cY), 7, (255, 255, 255), -1)
cv2.putText(img_as_ubyte(image), "center", (cX - 20, cY - 20),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
viewer = ImageViewer(image)
viewer.show()
Traceback (most recent call last):
File "Center.py", line 26, in <module>
cX = int(M["m10"] / M["m00"])
ZeroDivisionError: float division by zero
Thanks in advance!
Error is self-evident. You cannot divide a number by zero. If M["m00"] is zero, then you need to handle it appropriately. Check for 0 values in M["m00"].
if M["m00"] != 0:
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
else:
# set values as what you need in the situation
cX, cY = 0, 0
Probably you have bad contours
Note Since the contour moments are computed using Green formula, you
may get seemingly odd results for contours with self-intersections,
e.g. a zero area (m00) for butterfly-shaped contours.
Calculate the the center of mass, e.g.:
cx = 0
cy = 0
for p in contour:
cx += p[0][0]
cy += p[0][1]
cx = int(cx/len(contour))
cy = int(cy/len(contour))
or look into boundingRect() (3.4.3).
Related: Finding the center of a contour using opencv and visual c++

wrong center of mass x direction calculation (openCV Python)

I try to calculate the center of mass of objects in a binary image with openCV and Python. I use cv2.findContours and cv2.moments but I always get a wrong x direction. It has always a positive offset of a few pixels and I don't get why. I think I did it exactly like in the openCV doc.
Here is a example. Green is the contour found with cv2.findContours. Red the calculated center of mass.
My code is:
import cv2
import numpy as np
img = cv2.imread('C:/Users/Arno/Documents/Masterarbeit/Matlab/rect2.png', 0)
cimg = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
contours = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnt1 = contours[0]
cnt2 = contours[1]
cv2.drawContours(cimg, cnt2, -1, (0, 255, 0), 2)
M = cv2.moments(cnt1)
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
cv2.circle(cimg, (cx, cy), 1, (0, 0, 255), 2)
cv2.imshow('center of mass', cimg)

Categories