如何解决使用 OpenCV 特征工具进行实时椭球检测
我正在尝试创建一个程序来从实时摄像头馈送中检测椭圆体形状。目标是识别餐具(例如碗或杯子)的边缘。在阅读了许多 OpenCV 教程和文档页面之后,我尝试了 FAST 角点检测、Canny 边缘(具有最小指定区域的拨号轮廓)、Sobel 边缘和 Hough 圆。即使调整参数,这些似乎都不起作用。
作为参考,这里是来自每种方法的示例场景的单帧图像集 https://imgur.com/a/A7d7UxI
countours 的多边形近似依赖于角的数量,但任何超过 4 个角的复杂形状似乎都被标记为“圆形或椭圆形”。同样,纯圆检测会创建重复发现,其中标记了椭圆体的每个切线拟合圆。拐角检测有点失败,因为曲线形状中显然没有拐角。
老实说,我很难过。我对 OpenCV 的经验有限,不知道是否有一种方法可以检测和标记椭球(连续的或破碎的),以便在屏幕上找到它们的边缘位置。任何方向或帮助将不胜感激(我可以自己做一些挖掘),我最大的优势是试图从 Sobel 检测中识别出最强的可见轮廓,但无法验证它们的曲率或识别这些线。
虽然没有明确的相关性,但这里是我用来显示来自相机提要的每一个的 WIP 代码。
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,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,empty)
cv2.createTrackbar("Threshold2_Canny",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))
# disable nonmaxSuppression
fast.setNonmaxSuppression(0)
kp = fast.detect(img,None)
imgFAST = cv2.drawKeypoints(img,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,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()
解决方法
OpenCV 提供了三种不同的函数来将一组点拟合到椭圆上:
这些函数对一系列点(即轮廓)进行操作,因此您可以将这些函数中的任何一个用于轮廓。我建议的方法是:
- 图像二值化
- 检测二值图像中的轮廓
- 只保留外部轮廓(即碗有很多椭圆,但实际上你只想要最外面的)
- 对于每个剩余的轮廓:
- 拟合椭圆
- 将检测到的轮廓与椭圆的轮廓进行比较(例如使用
matchShapes()
)。 - 阈值比较以说明轮廓是否为椭圆
这个过程只依赖于一个主要参数(比较阈值),可以根据标记数据来决定,所以作为一种算法还算不错。然而,这里的预处理步骤(Canny 或其他二值化)可能有很多变量,并且在给定光照等情况下可能会发生很大变化。
一般来说,像这样依赖图像处理的经典算法在受限环境(已知光照、固定相机位置等)中效果最好,因为您可能实际上可以找到效果很好的预处理参数(通常情况下不是这样)在这些工业环境中很难提供几个滑块来动态更改阈值)。但是,对于不受约束的环境,例如在任意灯光下挥动手机指向任何颜色的物体,ML 可能会更好地为您服务,使用您感兴趣的特定类训练物体或遮罩检测器。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。