Python OpenCV中的阈值未检测到我想要获取的完整对象。我怎样才能解决这个问题?

Python OpenCV中的阈值未检测到我想要获取的完整对象。我怎样才能解决这个问题?,python,opencv,Python,Opencv,我想从视频源中检测鸡蛋,当我尝试对其使用阈值时,它不会得到完整的鸡蛋 我尝试应用不同的阈值步骤 将阈值应用于不同的轮廓,下面是结果 ret, img = cap.read() gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) ret,th1 = cv2.threshold(gray,127,255,cv2.THRESH_BINARY) th2 = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_MEAN

我想从视频源中检测鸡蛋,当我尝试对其使用阈值时,它不会得到完整的鸡蛋

我尝试应用不同的阈值步骤

将阈值应用于不同的轮廓,下面是结果

ret, img = cap.read()
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

ret,th1 = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY,11,2)
th3 = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY,11,2)
ret2,th4 = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

blur = cv2.GaussianBlur(gray,(5,5),0)
ret3,th5 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

dummy,cnts,hier = cv2.findContours(th1,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
for c in cnts:
    M = cv2.moments(c)
    if M["m00"] != 0:
        cX = int(M["m10"] / M["m00"])
        cY = int(M["m01"] / M["m00"])
    else:
        cX, cY = 0, 0
    cv2.drawContours(img, [c], -1, (0, 255, 0), 2)
    cv2.circle(img, (cX, cY), 2, (0, 0, 0), -1)
cv2.imshow("Global",th1)
cv2.imshow("Adaptive Mean",th2)
cv2.imshow("Adaptive Gaussian",th3)
cv2.imshow("Otsu's",th4)
cv2.imshow("Otsu's after Blur",th5)

更新: 在使用了@Martin的答案后,我得出了这个结论

通过得到面积最大的轮廓线。但也有其他大面积的等高线。下一个问题是如何过滤掉下面的其他轮廓?我在考虑确定哪些轮廓有角或没有角,因为鸡蛋是椭圆形的。另一种方法是裁剪出图像,因为鸡蛋只在图像的上部,但我不知道如何

代码:


你没有得到满蛋的原因是因为门槛太高。你需要把它放低一点

比如:

不过,您的问题相当大,因为背景(鸡蛋所在的对象)与鸡蛋的颜色相同。您可能希望尝试边缘检测,而不是阈值

看看这个:

在播放您的图像时,我能够获得边缘(仅一半):

代码:

我能够准确地检测到鸡蛋,但不幸的是,也有很多噪音

代码:

导入cv2
将numpy作为np导入
img=cv2.imread('eBxV8IA.jpg')
灰色=cv2.CVT颜色(img,cv2.COLOR\U BGR2GRAY)
模糊=cv2.高斯模糊(灰色,(15,15),0)
lap=cv2.Laplacian(模糊,cv2.CV_64F)
模糊=cv2.高斯模糊(圈,(45,45),0)

模糊[blur]谢谢。我也一直在尝试这样做,正在搜索是否可以得到由鸡蛋组成的轮廓。你对此有什么建议吗?另外,如果我将背景颜色更改为较浅的颜色,会更容易吗?1)如果颜色不同,会更容易(你可以使用HSV过滤)或者,如果鸡蛋和背景有相反的浓度-蛋清,背景灰色或相反。2)我没有太多的建议来精确提取轮廓,我唯一的想法是鸡蛋是圆形的,所以我会以某种方式使用它。例如,我会尝试通过所有轮廓点,看看方向是否有任何径向变化(鸡蛋是圆的,所以没有根本性的变化,但正方形的角部的方向有根本性的变化)。你也可以用较小或过大的区域消除轮廓,模糊[模糊任何低于0的模糊值都将被指定为0。第二个值更难。模糊不是标准的8位图像…因此我必须将其转换为8位(黑色0,白色255)。如果您的问题已得到回答,请确保接受答案以供进一步参考。
dummy,cnts,hier = cv2.findContours(close.astype(np.uint8),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#print (len(cnts))

for c in cnts:
    M = cv2.moments(c)
    area = cv2.contourArea(c)
    print (area)
    if area >46000:
        if M["m00"] != 0:
            cX = int(M["m10"] / M["m00"])
            cY = int(M["m01"] / M["m00"])
        else:
            cX, cY = 0, 0
        cv2.drawContours(img, [c], -1, (0, 255, 0), 2)
        cv2.circle(img, (cX, cY), 2, (0, 0, 0), -1)
cv2.imshow("th5",img)
limit = 100 # possible lower
ret,th1 = cv2.threshold(gray,limit,255,cv2.THRESH_BINARY)
import cv2
import numpy as np
img = cv2.imread('eBxV8IA.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray,(15,15),0)
lap = cv2.Laplacian(blur,cv2.CV_64F)
blur = cv2.GaussianBlur(lap,(45,45),0)
cv2.imshow("Global",blur)
import cv2
import numpy as np
img = cv2.imread('eBxV8IA.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray,(15,15),0)
lap = cv2.Laplacian(blur,cv2.CV_64F)
blur = cv2.GaussianBlur(lap,(45,45),0)
blur[blur<0]=0
blur = 255.*blur/np.amax(blur)


dummy,cnts,hier = cv2.findContours(blur.astype(np.uint8),cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
for c in cnts:
    M = cv2.moments(c)
    if M["m00"] != 0:
        cX = int(M["m10"] / M["m00"])
        cY = int(M["m01"] / M["m00"])
    else:
        cX, cY = 0, 0
    cv2.drawContours(img, [c], -1, (0, 255, 0), 2)
    cv2.circle(img, (cX, cY), 2, (0, 0, 0), -1)
cv2.imshow("Global",img)