0

I was trying to draw a contour, over a circular object present in the image and find its area and centroid. But I wasn't able to do it, because the contour was drawn all over the image as shown in the figure. I want to draw contour only over the circular white object as shown in the figure.

enter image description here

Expected Result:

I want to draw the circular contour only over this white object shown in the image and show its centroid and area. OpenCV, ignore rest of the part.

Below is the code attached.

Code:

import cv2 import numpy as np import imutils cap = cv2.VideoCapture(0) cap.set(3,640) cap.set(4,480) while True: _,frame = cap.read() hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) lower_blue = np.array([90,60,0]) upper_blue = np.array([121,255,255]) mask = cv2.inRange(hsv, lower_blue, upper_blue) cnts = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) cnts= imutils.grab_contours(cnts) for c in cnts: area = cv2.contourArea(c) if area > 1500: cv2.drawContours(frame, [c], -1, (0,255,0), 3) M = cv2.moments(c) cx = int(M["m10"] / M["m00"]) cy = int(M["m01"] / M["m00"]) cv2.circle(frame, (cx, cy), 7, (255, 255, 255), -1) cv2.putText(frame, "Centre", (cx - 20, cy - 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) cv2.imshow("frame", frame) print("area is ...", area) print("centroid is at ...", cx, cy) k=cv2.waitKey(1000) if k ==27: break cap.release() cv2.destroyAllWindows() 

Any help would be appreciated. Thanks in advance.

3
  • Perhaps you should filter the contours against shape analysis features that measure circularity or use HoughCircle detection. See www2.humusoft.cz/www/papers/tcb10/040_horejs.pdf or opencvpython.blogspot.com/2012/04/contour-features.html Commented Jan 7, 2020 at 7:13
  • It's fine to use screen-grabs with blue frames around them and green annotations inside them to show results, but please also provide an un-annotated, un-framed input image for folks to try their own algorithms on. Commented Jan 7, 2020 at 8:57
  • Why don't you use color-based methods like thresholding? Commented Jan 7, 2020 at 9:06

1 Answer 1

1

This can be done in many ways depending on the need. One simple way can be:

Firstly, filter the ROI. So we know 3 things, ROI is white, is a circle and we know its approx area.

For white color:

def detect_white(img): gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) _, thresh = cv2.threshold(gray, 220, 255, cv2.THRESH_BINARY) return thresh 

Although you would need to play with white detection algorithm as per your need. Some good ways for white detection would be with threshold(like above), using HSL colorspace as whiteness is closely dependent on lightness(cv2.cvtColor(img, cv2.COLOR_BGR2HLS) etc.


So in the code below, first we filter out the ROI by white color, then by the shape and area of those white contours.

image = cv2.imread("path/to/your/image") white_only = detect_white(image) contours, hierarchy = cv2.findContours(white_only, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) circles = [] for contour in contours: epsilon = 0.01 * cv2.arcLength(contour, True) approx = cv2.approxPolyDP(contour, epsilon, True) area = cv2.contourArea(contour) if len(approx) > 12 and area > 1000 and area < 3000: circles.append(contour) # Now the list circles would have all such # contours satisfying the above conditions # If len(circles) != 1 or isn't the circle you # desire, more filtering is required cv2.drawContours(image, circles, -1, (0, 255, 0), 3) 

Choosing the contour relies upon area and vertices(as returned by cv2. approxPolyDP()).

As in your image, the big white circle has a nice amount of area and is very close to a circle, I checked for it like: len(approx) > 12 and area > 1000 and area < 3000:. Tweak with this line according to your scenario and tell me if it solves your problem. If it doesn't, we can discuss some more nicer ways or play with this one to make it more accurate.

Sign up to request clarification or add additional context in comments.

7 Comments

Thanks @Mihir. I think this applies to image files. In the code above I am dealing with the Opencv Video frames. cap = cv2.VideoCapture(0) How to achieve it with the realtime videos?
@shantmanu See, a video is a sequence of pictures or call it frames. See this link for example(cap.read() extracts a frame or call it an image). If your video is of objects in motion, consider removing motion blur from the captured frame. If you don't get good results from a particular frame, apply your algorithm on the next frame.
You can change the frequency at which frames are extracted by cap.set()
Here are some nice tricks while dealing with videos. Also for basics, see this link.
I have used cap.set(3,640) & cap.set(4,480) to set the frequency.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.