今天,我们将开始由3部分构成的形状检测分析系列教程。
通过此系列教程,我们将学到如何:
- 计算轮廓/形状的中心;
- 仅使用轮廓特征识别出不同的形状,如:圆、正方形、长方形、三角形和五角形。
- 标记形状颜色
尽管今天的内容比较基础(相对于最近 PyImageSearch 博客讨论的更加高级的概念来说),但是也经常有人问我下边这个问题:
如何用 Python 和 OpenCV 计算轮廓的中心?
在今天的教程中,我将会回答这个问题。
在以后的教程中,我们将在轮廓知识的基础上进行图像的形状识别。
使用 OpenCV 计算轮廓中心
从上图中,你能看见几种不同的由图画纸裁出的形状。注意,这些形状并不完美——矩形不够方,圆形不够圆。它们都是先经手工描画然后再裁出来的,这意味着每种形状都存在着偏差。
明确了这一点之后,今天教程的目标是:(1)检测出图像中的每一种形状的轮廓(2)计算轮廓的中心——也叫形心。
为了达成以上目标,我们需要对图像进行以下预处理:
- 转换成灰度图;
- 滤波以减少高频噪声,使轮廓检测更加精确;
- 图像二值化。边缘检测和阈值化经常被用于此过程,本教程采用阈值化。
开始写代码之前,请确保你的系统已经安装了 imutils Python 包[ 译注:该包为作者开发的一系列用 OpenCV 执行基本图像处理操作的简便函数]。
1 |
$ pip install imutils |
让我们继续!
新建一个文件,命名为 center_of_shape.py
,然后开始写代码吧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# import the necessary packages import argparse import imutils import cv2 # construct the argument parse and parse the arguments ap = 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 it image = 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行)。
阈值化操作后的输出如下图所示
注意阈值化后形状被表示成黑色背景上的白色前景。
下一步是使用轮廓检测去定位这些白色区域。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# import the necessary packages import argparse import imutils import cv2 # construct the argument parse and parse the arguments ap = 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 it image = 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 image cnts = 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)才是轮廓列表]
我们已经准备去处理每一条轮廓:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# import the necessary packages import argparse import imutils import cv2 # construct the argument parse and parse the arguments ap = 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 it image = 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 image cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = cnts[0] if imutils.is_cv2() else cnts[1] # loop over the contours for 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 |
运行结果如下图所示:
注意每一个形状都被成功地检测到,然后计算出轮廓中心并绘制在图像上。
总结
在这次教程中,我们学习了如何使用 OpenCV 和 Python 去计算轮廓的中心。
此教程是由三部分构成的形状分析系列教程的第一部分。
在下周的教程中,我们将学习如何识别图像中的形状。
然后,在两周以后,我们将学习如何分析每一个形状的颜色并将其标记在形状上(即标记“红”、“绿”、“蓝”等等)。
为了确保这些教程写成的时候您能被通知到,请按照以下形式输入您的邮箱地址![译注:原博客提供代码下载和邮件提醒功能。戳我访问原文。]