I am trying to create a program to detect ellipsoid shapes from a real-time camera feed. The goal is to identify the rims of dishware (for example, a bowl or cup). After many OpenCV tutorials and documentation pages, I've tried FAST corner detection, Canny edge (with dialated contours of a minimum specified area), Sobel edge, and Hough circles. None of these seem to work even with tweaking paramters.
For reference, here is an imgur album of a single frame of a sample scene from each method https://imgur.com/a/A7d7UxI
Poly approximation for countours relies on the number of corners, but any complex shape with more than 4 corners seems to be flagged as "circlular or ellipsoid". Likewise, pure circle detection creates repeated findings where each tangentially fit circle of an ellipsoid is marked. Corner detection is a bit of a failure because there are obviously no corners in curved shapes.
Honestly, I'm stumped. I have limited experience with OpenCV and do not know of if there is a way to detect and label ellipsoids (continious or broken) for the purposes of finding their edge positions on screen. Any direction or help would be appreciated (I can do some digging on my own), my biggest lead is trying to identify the strongest visible contours from the Sobel detection, but have no way to verify their curvature or identify these lines.
While not explicitly relevant, here is the WIP code I use to display each of these from a camera feed.
import numpy as np
import cv2
def empty():
pass
def getContours(img,imgContour):
contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
for cnt in contours:
area = cv2.contourArea(cnt)
if area > 1000:
cv2.drawContours(imgContour, cnt, -1, (255, 0, 255), 7)
peri = cv2.arcLength(cnt, False)
approx = cv2.approxPolyDP(cnt, 0.02 * peri, False)
if len(approx) > 5:
x, y, w, h = cv2.boundingRect(approx)
cv2.rectangle(imgContour, (x, y), (x + w, y + h), (0, 255, 0), 5)
# Capturing from the video input
# Use VideoCapture(0) for default webcam
# I use a feed from my phone via USB, which is webcam 2 that uses VideoCapture(1)
cap = cv2.VideoCapture(1)
"""Trackbar"""
cv2.namedWindow("Parameters")
cv2.createTrackbar("Threshold1_Canny", "Parameters", 150, 255, empty)
cv2.createTrackbar("Threshold2_Canny", "Parameters", 255, 255, empty)
while True:
# reading the frame
ret, frame = cap.read()
# flipping the frame
frame = cv2.flip(frame, 1)
if ret:
"""Image Preprocessing"""
img = cv2.GaussianBlur(frame, (21, 21), cv2.BORDER_DEFAULT)
imgContour = img.copy()
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
"""FAST Corner Detection"""
# Initiate FAST object with default values
fast = cv2.FastFeatureDetector_create()
# find and draw the keypoints
kp = fast.detect(img,None)
img2 = cv2.drawKeypoints(img, kp, None, color=(255,0,0))
# Disable nonmaxSuppression
fast.setNonmaxSuppression(0)
kp = fast.detect(img,None)
imgFAST = cv2.drawKeypoints(img, kp, None, color=(255,0,0))
"""Canny Edge Detection"""
threshold1 = cv2.getTrackbarPos("Threshold1_Canny", "Parameters")
threshold2 = cv2.getTrackbarPos("Threshold2_Canny", "Parameters")
edges = cv2.Canny(img, threshold1, threshold2)
kernal = np.ones((5, 5))
imgDil = cv2.dilate(edges, kernal, iterations=1)
getContours(imgDil,imgContour)
"""Hough Circles"""
#cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
#circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,100,
# param1=50,param2=30,minRadius=60,maxRadius=400)
#circles = np.uint16(np.around(circles))
"""Sobel Edge Detection"""
imgSobel = cv2.Sobel(img, cv2.CV_16S, 0, 1, ksize=-1)
imgSobel = np.absolute(imgSobel)
imgSobel = np.uint8(imgSobel)
"""Show All Processing"""
cv2.imshow('Raw', frame)
cv2.imshow('FAST', imgFAST)
cv2.imshow('Canny', imgDil)
cv2.imshow('Sobel', imgSobel)
#cv2.imshow('Hough', cimg)
"""Key Controls"""
# getting the input from the keyboard
k = cv2.waitKey(1) & 0xFF
# press 'q' to quit
if k == ord('q'):
cap.release()
break
cap.release()
cv2.destroyAllWindows()