今天,我们将开始由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 去计算轮廓的中心。
此教程是由三部分构成的形状分析系列教程的第一部分。
在下周的教程中,我们将学习如何识别图像中的形状。
然后,在两周以后,我们将学习如何分析每一个形状的颜色并将其标记在形状上(即标记“红”、“绿”、“蓝”等等)。
为了确保这些教程写成的时候您能被通知到,请按照以下形式输入您的邮箱地址![译注:原博客提供代码下载和邮件提醒功能。戳我访问原文。]