使用Python和OpenCV简单而有效的硬币分割

随着社区的辛勤工作,新一代的OpenCV Python绑定变得越来越好。新的绑定称为“cv2”,是旧的“cv”绑定的替代品;在新一代绑定中,几乎所有操作现在都返回原生Python对象或Numpy对象,这非常好,因为它简化了很多,而且由于您现在还可以使用Numpy中的优化操作,并且还支持与其他框架(如scikit图像它还使用Numpy数组来表示图像。

在这个例子中,我将展示如何用一种简单的方法分割图像中的硬币,甚至是实时视频捕获,方法是使用阈值、形态算子和轮廓近似。这种方法比使用Otsu阈值和分水岭分割的方法简单得多这里是OpenCV Python教程,我强烈建议你阅读,因为它的稳健性。不幸的是,使用大津的阈值的方法是高度依赖于照明正常化。人们可以提取图像的小补丁来实现类似的自适应大津的二进制的东西(像在Letptonica实现 - 由正方体OCR使用的框架)来解决这个问题,但让我们看到另一种方法。为了参考,见使用具有我与一个非归一化照明的摄像头所拍摄的图像的大津的阈值的输出:

原始图像与Otsu二值化
原始图像与Otsu二值化

1.设置视频捕获配置

使用Python绑定创建实时视频捕获的第一步是实例化Video Capture类,设置属性,然后开始从相机读取帧:

导入cv2 cap = cv2. videocapture (0) cap.set(cv2.cv)CV_CAP_PROP_FRAME_WIDTH, 1280) cap.set (cv2.cv。CV_CAP_PROP_FRAME_HEIGHT, 720)

在新版本(尚未发行),该常数CV_CAP_PROP_FRAME_宽度现在在cv2模块,现在,我们只用cv2.cv模块。

2.阅读图像帧

下一步是使用VideoCapture对象读取帧,然后将其转换为灰色(我们不打算使用颜色信息来分割硬币):

当为True时:ret,frame=读帽(roi=帧[0:500,0:500]灰色=cv2.CVT颜色(roi,cv2.COLOR_bgr2;灰色)

请注意,我在这里提取完整的图像(如硬币的位置)的一小部分,但你没有这样做,如果你有你的图像上只有硬币。在这个时刻,我们有以下的灰度图像:

灰原图像捕捉。
灰原图像捕捉。

三。应用自适应阈值

在这一步中,我们将在应用高斯模糊核之后应用自适应阈值,以消除图像中的噪声:

灰度模糊=cv2.GAUSSIAN blur(灰度,(15,15),0)阈值=cv2.adaptiveThreshold(灰度模糊,255,cv2.ADAPTIVE thresh高斯,cv2.thresh二进制,11,1)

如图中高斯核的效果:

原始灰度图像和应用高斯核后的图像。
原始灰度图像和应用高斯核后的图像。

现在是自适应阈值与模糊图像的效果:

自适应阈值化对模糊图像的影响

请注意,在那一刻,我们已经把硬币分割了,除了硬币中心和周围的一些地方的小噪音。

四。形态学

形态算子用于对图像像素进行放大、侵蚀和其他操作。在这里,由于相机有时会呈现一些器物,我们会使用闭合的形态学操作来确保硬币的边界始终是闭合的,否则,我们可能会发现一枚带有半圆之类的硬币。要了解关闭操作(即已放大像素的侵蚀操作)的效果,请参见下图:

形态学关闭

你可以看到,在一些操作迭代后,圆圈开始变得充满。要使用闭合操作,我们将使用morphologyEx函数从OpenCV Python绑定:

内核= np。one ((3,3), np.uint8)关闭= cv2。cv2 morphologyEx(打。MORPH_CLOSE、内核、迭代= 4)

现在看看关闭操作对我们硬币的影响:

在硬币关闭操作

形态学运算符的操作非常简单,主要原理是将一个元素(在我们的例子中,我们有一个区块元素3×3)亚洲金博宝应用到图像的像素中。如果你想了解它,请看看这个动画解释了侵蚀的运作

5个。轮廓检测与滤波

应用形态学算后,将所有我们要做的是找到每个硬币的轮廓,然后筛选具有面积比一枚硬币面积更小或更大的轮廓。你能想象在OpenCV中发现的轮廓为寻找连接组件及其边界的操作过程。为了做到这一点,我们将使用的OpenCV芬兰巨蜥功能。

cont_img = close .copy()等高线,hierarchy = cv2findContours (cont_img cv2。RETR_EXTERNAL,cv2。CHAIN_APPROX_SIMPLE)

注意,我们复制了关闭图像,因为函数find等值线将更改作为第一个参数传递的图像,我们还使用RETR_EXTERNAL标志,这意味着返回的轮廓只是极端的外部轮廓。的参数CHAIN_APPROX_SIMPLE还将返回轮廓的紧凑表示,以获取更多信息看这里

找到等高线后,我们需要迭代每个等高线,检查等高线的面积,筛选大于或小于硬币面积的等高线。我们还需要拟合一个椭圆等高线找到。我们本可以用最小围圆来做这个,但是因为我的相机没有完全在硬币上面,硬币看起来有一个描述椭圆的小倾角。

对于CNT在轮廓:面积= cv2.contourArea(CNT)如果区域<2000或面积> 4000:继续如果len(CNT)<5:继续椭圆= cv2.fitEllipse(CNT)cv2.ellipse(ROI,椭圆,(0255,0),2)

注意,在上面的代码中,我们在每个等高线上迭代,过滤面积小于2000或大于4000的硬币(这些是我在相机这个距离处为巴西硬币找到的硬编码值),然后我们检查等高线的点数,因为函数fitEllipse需要大于或等于5的点数,最后我们使用椭圆函数来绘制在绿色椭圆比原始图像。

为了显示带有轮廓的最终图像,我们只需使用imshow函数来显示带有该图像的新窗口:

cv2。imshow(“最终结果”,roi)

最后,这是上述所有步骤结束时的结果:

最后的图像与轮廓检测
最后的图像与轮廓检测

完整的源代码:

进口numpy的作为NP进口CV2 DEF run_main():帽= cv2.VideoCapture(0)cap.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH,1280)cap.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT,720),而(真):RET,帧= cap.read()ROI =帧[0:500,0:500]灰色= cv2.cvtColor(ROI,cv2.COLOR_BGR2GRAY)gray_blur = cv2.GaussianBlur(灰色,(15,15),0)= THRESH CV2。adaptiveThreshold(gray_blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 1) kernel = np.ones((3, 3), np.uint8) closing = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=4) cont_img = closing.copy() contours, hierarchy = cv2.findContours(cont_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for cnt in contours: area = cv2.contourArea(cnt) if area < 2000 or area > 4000: continue if len(cnt) < 5: continue ellipse = cv2.fitEllipse(cnt) cv2.ellipse(roi, ellipse, (0,255,0), 2) cv2.imshow("Morphological Closing", closing) cv2.imshow("Adaptive Thresholding", thresh) cv2.imshow('Contours', roi) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows() if __name__ == "__main__": run_main()

“使用Python和OpenCV实现简单有效的硬币分割”的26点思考

    1. 嗨,这是一个伟大的演示,因为只有白色背景。
      你觉得我们可以得到硬币的非常精确的边缘上一个强大的背景?亚洲金博宝
      我讲的是一个专业的应用...

  1. 我才意识到,几周前我读这篇文章是为了更好地理解OpenCV中的图像分割,而现在我要测试PyEvolve。小世界?伟大的工作。

  2. 亚洲金博宝非常好的教程!!!

    有什么方法可以用这个来测量硬币吗?

    致以最亲切的问候

  3. 你好

    我试过这个程序,但出现了一个错误,你能帮助我吗?

    回溯(最近一次呼叫):
    文件“C:/Python27/Scripts/CountoursF.py公司“,第15行,英寸
    ret,框架=读帽()
    名称错误:名称“cap”未定义

    又犯了错误

    如果cv2.waitKey(1) & 0xFF == ord(' q '):
    打破

  4. 嗨,
    很好的教程!!!
    你能告诉我,如何找到轮廓后提取的矩形,而不是椭圆形?如果我们有一个形象在许多矩形以及如何提取大吗?
    谢谢。
    问候

  5. 嗨,
    亚洲金博宝很不错的教程。你能告诉我如何显示有内部的所有硬币边框?我的意思是所有的论文硬币是在一个大长方形感谢。

    问候

  6. 你好。
    优秀的教程中,我开始用的OpenCV的Python程序,并有一个问题。
    如何数出图片中硬币的数量?
    非常感谢你亚洲金博宝

  7. 你好。
    优秀的教程中,我开始用的OpenCV的Python程序,并有一个问题。
    如何数出图片中硬币的数量?
    非常感谢你亚洲金博宝

  8. 你好,克里斯蒂安。
    谢谢你分享这个,非常有帮助。亚洲金博宝
    快问:我对数硬币的数目感兴趣。你的代码也能做到吗?(很抱歉,我已经9年没有编程了)。

    -rafi-

  9. 你好
    我在Android上尝试这种

    new ArrayList();
    Imgproc。find等值线(关闭,等值线,新Mat(), Imgproc。RETR_LIST Imgproc.CHAIN_APPROX_SIMPLE);
    for (int idx = 0;idx < contours.size ();idx + +) {

    MatOfPoint2f temp=新的MatOfPoint2f(轮廓。获取(idx).toArray());
    RotatedRect elipse1 = Imgproc.fitEllipse(温度);
    Imgproc.ellipse(originalMat,elipse1,新标量(0,255,0),2);
    }
    什么也不显示。我错过了什么?

  10. 你的代码令人难以置信。但我有个问题。你怎么能认出除了圆圈以外的其他几何形状呢?谢谢,我对谷歌上的英语节目感到抱歉。

  11. 当我试图显示它时,roi是没有定义的。一亚洲金博宝切运行,包括for循环,但由于某种原因,当我试图显示roi时,它抛出了一个错误。有什么建议吗?

留下回信

您的电子邮件地址不会被公开。

这个网站使用Akismet来减少垃圾邮件。了解如何处理评论数据