今天,我们将开始由3部分构成的形状检测分析系列教程。
通过此系列教程,我们将学到如何:
尽管今天的内容比较基础(相对于最近 PyImageSearch 博客讨论的更加高级的概念来说),但是也经常有人问我下边这个问题:
如何用 Python 和 OpenCV 计算轮廓的中心?
在今天的教程中,我将会回答这个问题。
在以后的教程中,我们将在轮廓知识的基础上进行图像的形状识别。
图1:包含不同形状的待计算轮廓中心的示例图像
从上图中,你能看见几种不同的由图画纸裁出的形状。注意,这些形状并不完美——矩形不够方,圆形不够圆。它们都是先经手工描画然后再裁出来的,这意味着每种形状都存在着偏差。
明确了这一点之后,今天教程的目标是:(1)检测出图像中的每一种形状的轮廓(2)计算轮廓的中心——也叫形心。
为了达成以上目标,我们需要对图像进行以下预处理:
开始写代码之前,请确保你的系统已经安装了 imutils Python 包[ 译注:该包为作者开发的一系列用 OpenCV 执行基本图像处理操作的简便函数]。
1 | $ pip install imutils |
让我们继续!
新建一个文件,命名为 center_of_shape.py
,然后开始写代码吧:
1234567891011121314151617 | # import the necessary packagesimport argparseimport imutilsimport cv2 # construct the argument parse and parse the argumentsap = argparse.ArgumentParser()ap.add_argument(\”-i\”, \”–image\”, required=True, help=\”path to the input image\”)args = vars(ap.parse_args()) # load the image, convert it to grayscale, blur it slightly,# and threshold itimage = cv2.imread(args[\”image\”])gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)blurred = cv2.GaussianBlur(gray, (5, 5), 0)thresh = cv2.threshold(blurred, 60, 255, cv2.THRESH_BINARY)[1] |
第2-4行代码导入必需的包,第7-10行代码解析命令行参数。此处只需要一个 --image
参数: 磁盘中待处理图像的路径。
随后程序从磁盘加载图像,然后进行预处理,执行灰度变换,5×5 内核的高斯平滑,最后阈值化(14-17行)。
阈值化操作后的输出如下图所示
图2:图像阈值化返回二值图像,其中形状被表示为黑色背景上的白块
注意阈值化后形状被表示成黑色背景上的白色前景。
下一步是使用轮廓检测去定位这些白色区域。
12345678910111213141516171819202122 | # import the necessary packagesimport argparseimport imutilsimport cv2 # construct the argument parse and parse the argumentsap = argparse.ArgumentParser()ap.add_argument(\”-i\”, \”–image\”, required=True, help=\”path to the input image\”)args = vars(ap.parse_args()) # load the image, convert it to grayscale, blur it slightly,# and threshold itimage = cv2.imread(args[\”image\”])gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)blurred = cv2.GaussianBlur(gray, (5, 5), 0)thresh = cv2.threshold(blurred, 60, 255, cv2.THRESH_BINARY)[1] # find contours in the thresholded imagecnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)cnts = cnts[0] if imutils.is_cv2() else cnts[1] |
第 20-21 行代码调用 cv2.findContours
函数,该函数返回图像上每一个白块对应的边界点集合(即轮廓)。第22行基于我们使用 OpenCV 2.4 版本还是3.0 版本而取不同的元组值。获取更多 cv2.findContours
函数返回签名在不同 OpenCV 版本间的改变,请移步此文。[译注:OpenCV 2.4 版本的 cv2.findContours
函数返回的是一个二元元组,元组的第一个元素(索引 0)是轮廓列表。而在 OpenCV 3.0 版本中,该函数返回的是一个三元元组,元组的第二个元素(索引 1)才是轮廓列表]
我们已经准备去处理每一条轮廓:
123456789101112131415161718192021222324252627282930313233343536373839 | # import the necessary packagesimport argparseimport imutilsimport cv2 # construct the argument parse and parse the argumentsap = argparse.ArgumentParser()ap.add_argument(\”-i\”, \”–image\”, required=True, help=\”path to the input image\”)args = vars(ap.parse_args()) # load the image, convert it to grayscale, blur it slightly,# and threshold itimage = cv2.imread(args[\”image\”])gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)blurred = cv2.GaussianBlur(gray, (5, 5), 0)thresh = cv2.threshold(blurred, 60, 255, cv2.THRESH_BINARY)[1] # find contours in the thresholded imagecnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)cnts = cnts[0] if imutils.is_cv2() else cnts[1] # loop over the contoursfor c in cnts: # compute the center of the contour M = cv2.moments(c) cX = int(M[\”m10\”] / M[\”m00\”]) cY = int(M[\”m01\”] / M[\”m00\”]) # draw the contour and center of the shape on the image cv2.drawContours(image, [c], –1, (0, 255, 0), 2) cv2.circle(image, (cX, cY), 7, (255, 255, 255), –1) cv2.putText(image, \”center\”, (cX – 20, cY – 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2) # show the image cv2.imshow(\”Image\”, image) cv2.waitKey(0) |
第25行开始遍历轮廓,然后在第27行计算轮廓区域图像的矩。
在计算机视觉和图像处理领域,图像的矩经常被用来描述图像中某个对象的形状。这些矩描述了形状的基本统计特征,包括对象的面积、形心(即对象的中心坐标 (x, y)
)、取向连同其他有用的特征。
我们只对图像的中心感兴趣,所以在第28-29行计算轮廓的中心。
随后,第32-34行完成以下任务:
cv2.drawContours
函数绘制包围当前形状的轮廓;(cX, cY)
处绘制一个白色的小圆;center
。要执行脚本,打开终端然后执行以下命令:
1 | $ python center_of_shape.py —image shapes_and_colors.png |
运行结果如下图所示:
图3:分别遍历每一个形状并计算每一个形状的中心 (x, y)。(点击图片有惊醒)
注意每一个形状都被成功地检测到,然后计算出轮廓中心并绘制在图像上。
在这次教程中,我们学习了如何使用 OpenCV 和 Python 去计算轮廓的中心。
此教程是由三部分构成的形状分析系列教程的第一部分。
在下周的教程中,我们将学习如何识别图像中的形状。
然后,在两周以后,我们将学习如何分析每一个形状的颜色并将其标记在形状上(即标记“红”、“绿”、“蓝”等等)。
为了确保这些教程写成的时候您能被通知到,请按照以下形式输入您的邮箱地址![译注:原博客提供代码下载和邮件提醒功能。戳我访问原文。]
上一篇:从源码编译 Python