文章目录
- 一、实验目的
- 二、实验内容
- 三、实验过程
- Numpy
- 1.NumPy 操作
- 2.NumPy Ndarray 对象
- 3.NumPy 基本类型
- 4.NumPy 数组属性
- ndarray.ndim
- ndarray.shape
- ndarray.itemsize
- ndarray.flags
- 5.NumPy 创建数组
- numpy.empty
- numpy.zeros
- numpy.ones
- 6.NumPy 从已有的数组创建数组
- numpy.asarray
- numpy.frombuffer
- numpy.fromiter
- 7.NumPy 从数值范围创建数组
- numpy.arange
- numpy.linspace
- numpy.logspace
- 8.NumPy 切片和索引
- 9.NumPy 高级索引
- 整数数组索引
- 布尔索引
- 10.NumPy 迭代数组
- 修改数组中元素的值
- 使用外部循环
- 11.Numpy数组操作
- 修改数组形状
- numpy.reshape
- numpy.ndarray.flatten
- numpy.ravel
- numpy.transpose
- numpy.rollaxis
- numpy.swapaxes
- 准备工作
- 小插曲
- numpy包
- 图像处理
- 颜色转换
- 画矩形
- 画圆
- 画椭圆
- 画线段
- 画和填充多边形
- 绘制文字
- 为图像添加边框
- 轮廓检测和画出轮廓
- 四、实验结果
- 五、实验结论
一、实验目的
本实验是利用python中的numpy库中的函数,对数组进行各种各样的操作和对图像进行各种操作。对数组进行的操作包括熟悉numpy的基本操作——学习如何创建、访问和修改NumPy数组,了解数组的属性和方法;学习如何改变数组的形状,例如改变维度、转置数组、重塑数组等;还有学习如何使用NumPy的索引和切片操作,对数组进行元素的访问和修改。对图像的操作包括学习如何实现颜色变换、画基本图形、文字绘制、为图像添加边框以及在图像中查找轮廓。通过该实验,可以帮助我们掌握numpy的基本操作和常用函数,理解数组的概念和运算;同时可以深入了解OpenCV图像处理模块的功能和应用,并对不同的图像处理算法和技术有所了解,实验过程也可以帮助我更加熟悉OpenCV提供的函数和方法,为将来在计算机视觉和图像处理领域的实际应用中打下基础。
二、实验内容
1.numpy基本操作
2.基本图形的绘制
三、实验过程
Numpy
NumPy - 简介
NumPy 是一个 Python 包。 它代表 “Numeric Python”。 它是一个由多维数组对象和用于处理数组的例程集合组成的库。
Numeric,即 NumPy 的前身,是由 Jim Hugunin 开发的。 也开发了另一个包 Numarray ,它拥有一些额外的功能。 2005年,Travis Oliphant 通过将 Numarray 的功能集成到 Numeric 包中来创建 NumPy 包。 这个开源项目有很多贡献者。
1.NumPy 操作
使用NumPy,开发人员可以执行以下操作:
-
数组的算数和逻辑运算。
-
傅立叶变换和用于图形操作的例程。
-
与线性代数有关的操作。 NumPy 拥有线性代数和随机数生成的内置函数。
2.NumPy Ndarray 对象
NumPy 最重要的一个特点是其 N 维数组对象 ndarray,它是一系列同类型数据的集合,以 0 下标为开始进行集合中元素的索引。
ndarray 对象是用于存放同类型元素的多维数组。
ndarray 中的每个元素在内存中都有相同存储大小的区域。
ndarray 内部由以下内容组成:
-
一个指向数据(内存或内存映射文件中的一块数据)的指针。
-
数据类型或 dtype,描述在数组中的固定大小值的格子。
-
一个表示数组形状(shape)的元组,表示各维度大小的元组。
-
一个跨度元组(stride),其中的整数指的是为了前进到当前维度下一个元素需要"跨过"的字节数。
ndarray 的内部结构:
跨度可以是负数,这样会使数组在内存中后向移动,切片中 obj[::-1] 或 obj[:,::-1] 就是如此。
创建一个 ndarray 只需调用 NumPy 的 array 函数即可:
名称 | 描述 |
---|---|
object | 数组或嵌套的数列 |
dtype | 数组元素的数据类型,可选 |
copy | 对象是否需要复制,可选 |
order | 创建数组的样式,C为行方向,F为列方向,A为任意方向(默认) |
subok | 默认返回一个与基类类型一致的数组 |
ndmin | 指定生成数组的最小维度NumPy 数据类型 |
numpy 支持的数据类型比 Python 内置的类型要多很多,基本上可以和 C 语言的数据类型对应上,其中部分类型对应为 Python 内置的类型。下表列举了常用
3.NumPy 基本类型
名称 | 描述 |
---|---|
bool_ | 布尔型数据类型(True 或者 False) |
int_ | 默认的整数类型(类似于 C 语言中的 long,int32 或 int64) |
intc | 与 C 的 int 类型一样,一般是 int32 或 int 64 |
intp | 用于索引的整数类型(类似于 C 的 ssize_t,一般情况下仍然是 int32 或 int64) |
int8 | 字节(-128 to 127) |
int16 | 整数(-32768 to 32767) |
int32 | 整数(-2147483648 to 2147483647) |
int64 | 整数(-9223372036854775808 to 9223372036854775807) |
uint8 | 无符号整数(0 to 255) |
uint16 | 无符号整数(0 to 65535) |
uint32 | 无符号整数(0 to 4294967295) |
uint64 | 无符号整数(0 to 18446744073709551615) |
float_ | float64 类型的简写 |
float16 | 半精度浮点数,包括:1 个符号位,5 个指数位,10 个尾数位 |
float32 | 单精度浮点数,包括:1 个符号位,8 个指数位,23 个尾数位 |
float64 | 双精度浮点数,包括:1 个符号位,11 个指数位,52 个尾数位 |
complex_ | complex128 类型的简写,即 128 位复数 |
complex64 | 复数,表示双 32 位浮点数(实数部分和虚数部分) |
complex128 | 复数,表示双 64 位浮点数(实数部分和虚数部分) |
numpy 的数值类型实际上是 dtype 对象的实例,并对应唯一的字符,包括 np.bool_,np.int32,np.float32,等等。
4.NumPy 数组属性
本章节我们将来了解 NumPy 数组的一些基本属性。
NumPy 数组的维数称为秩(rank),秩就是轴的数量,即数组的维度,一维数组的秩为 1,二维数组的秩为 2,以此类推。
在 NumPy中,每一个线性的数组称为是一个轴(axis),也就是维度(dimensions)。比如说,二维数组相当于是两个一维数组,其中第一个一维数组中每个元素又是一个一维数组。所以一维数组就是 NumPy 中的轴(axis),第一个轴相当于是底层数组,第二个轴是底层数组里的数组。而轴的数量——秩,就是数组的维数。
很多时候可以声明 axis。axis=0,表示沿着第 0 轴进行操作,即对每一列进行操作;axis=1,表示沿着第1轴进行操作,即对每一行进行操作。
NumPy 的数组中比较重要 ndarray 对象属性有:
属性 | 说明 |
---|---|
ndarray.ndim | 秩,即轴的数量或维度的数量 |
ndarray.shape | 数组的维度,对于矩阵,n 行 m 列 |
ndarray.size | 数组元素的总个数,相当于 .shape 中 n*m 的值 |
ndarray.dtype | ndarray 对象的元素类型 |
ndarray.itemsize | ndarray 对象中每个元素的大小,以字节为单位 |
ndarray.flags | ndarray 对象的内存信息 |
ndarray.real | ndarray元素的实部 |
ndarray.imag | ndarray 元素的虚部 |
ndarray.data | 包含实际数组元素的缓冲区,由于一般通过数组的索引获取元素,所以通常不需要使用这个属性。 |
ndarray.ndim
ndarray.ndim 用于返回数组的维数,等于秩。
ndarray.shape
ndarray.shape 表示数组的维度,返回一个元组,这个元组的长度就是维度的数目,即 ndim 属性(秩)。比如,一个二维数组,其维度表示"行数"和"列数"。
ndarray.shape 也可以用于调整数组大小。
ndarray.itemsize
ndarray.itemsize 以字节的形式返回数组中每一个元素的大小。
例如,一个元素类型为 float64 的数组 itemsize 属性值为 8(float64 占用 64 个 bits,每个字节长度为 8,所以 64/8,占用 8 个字节),又如,一个元素类型为 complex32 的数组 item 属性为 4(32/8)。
ndarray.flags
ndarray.flags 返回 ndarray 对象的内存信息
5.NumPy 创建数组
ndarray 数组除了可以使用底层 ndarray 构造器来创建外,也可以通过以下几种方式来创建。
numpy.empty
numpy.empty 方法用来创建一个指定形状(shape)、数据类型(dtype)且未初始化的数组:
numpy.empty(shape, dtype = float, order = ‘C’)
参数说明:
参数 | 描述 |
---|---|
shape | 数组形状 |
dtype | 数据类型,可选 |
order | 有"C"和"F"两个选项,分别代表,行优先和列优先,在计算机内存中的存储元素的顺序。 |
numpy.zeros
创建指定大小的数组,数组元素以 0 来填充:
numpy.zeros(shape, dtype = float, order = ‘C’)
参数说明:
参数 | 描述 |
---|---|
shape | 数组形状 |
dtype | 数据类型,可选 |
order | ‘C’ 用于 C 的行数组,或者 ‘F’ 用于 FORTRAN 的列数组 |
numpy.ones
创建指定形状的数组,数组元素以 1 来填充:
numpy.ones(shape, dtype = None, order = ‘C’)
参数说明:
参数 | 描述 |
---|---|
shape | 数组形状 |
dtype | 数据类型,可选 |
order | ‘C’ 用于 C 的行数组,或者 ‘F’ 用于 FORTRAN 的列数组 |
6.NumPy 从已有的数组创建数组
本章节我们将学习如何从已有的数组创建数组。
numpy.asarray
numpy.asarray 类似 numpy.array,但 numpy.asarray 参数只有三个,比 numpy.array 少两个。
numpy.asarray(a, dtype = None, order = None)
参数说明:
参数 | 描述 |
---|---|
a | 任意形式的输入参数,可以是,列表, 列表的元组, 元组, 元组的元组, 元组的列表,多维数组 |
dtype | 数据类型,可选 |
order | 可选,有"C"和"F"两个选项,分别代表,行优先和列优先,在计算机内存中的存储元素的顺序。 |
numpy.frombuffer
numpy.frombuffer 用于实现动态数组。
numpy.frombuffer 接受 buffer 输入参数,以流的形式读入转化成 ndarray 对象。
numpy.frombuffer(buffer, dtype = float, count = -1, offset = 0)
**注意:**buffer 是字符串的时候,Python3 默认 str 是 Unicode 类型,所以要转成 bytestring 在原 str 前加上 b。
参数说明:
参数 | 描述 |
---|---|
buffer | 可以是任意对象,会以流的形式读入。 |
dtype | 返回数组的数据类型,可选 |
count | 读取的数据数量,默认为-1,读取所有数据。 |
offset | 读取的起始位置,默认为0。 |
numpy.fromiter
numpy.fromiter 方法从可迭代对象中建立 ndarray 对象,返回一维数组。
numpy.fromiter(iterable, dtype, count=-1)
参数 | 描述 |
---|---|
iterable | 可迭代对象 |
dtype | 返回数组的数据类型 |
count | 读取的数据数量,默认为-1,读取所有数据 |
7.NumPy 从数值范围创建数组
这一章节我们将学习如何从数值范围创建数组。
numpy.arange
numpy 包中的使用 arange 函数创建数值范围并返回 ndarray 对象,函数格式如下:
numpy.arange(start, stop, step, dtype)
根据 start 与 stop 指定的范围以及 step 设定的步长,生成一个 ndarray。
参数说明:
参数 | 描述 |
---|---|
start | 起始值,默认为0 |
stop | 终止值(不包含) |
step | 步长,默认为1 |
dtype | 返回ndarray 的数据类型,如果没有提供,则会使用输入数据的类型。 |
numpy.linspace
numpy.linspace 函数用于创建一个一维数组,数组是一个等差数列构成的,格式如下:
np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
参数说明:
参数 | 描述 |
---|---|
start | 序列的起始值 |
stop | 序列的终止值,如果endpoint 为true ,该值包含于数列中 |
num | 要生成的等步长的样本数量,默认为50 |
endpoint | 该值为 true 时,数列中包含stop 值,反之不包含,默认是True。 |
retstep | 如果为 True 时,生成的数组中会显示间距,反之不显示。 |
dtype | ndarray 的数据类型 |
numpy.logspace
numpy.logspace 函数用于创建一个于等比数列。格式如下:
np.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None)
base 参数意思是取对数的时候 log 的下标。
参数 | 描述 |
---|---|
start | 序列的起始值为:base ** start |
stop | 序列的终止值为:base ** stop。如果endpoint 为true ,该值包含于数列中 |
num | 要生成的等步长的样本数量,默认为50 |
endpoint | 该值为 true 时,数列中中包含stop 值,反之不包含,默认是True。 |
base | 对数 log 的底数。 |
dtype | ndarray 的数据类型 |
8.NumPy 切片和索引
ndarray对象的内容可以通过索引或切片来访问和修改,与 Python 中 list 的切片操作一样。ndarray 数组可以基于 0 - n 的下标进行索引,切片对象可以通过内置的 slice 函数,并设置 start, stop 及 step 参数进行,从原数组中切割出一个新数组。实例 import numpy as np a = np.arange(10) s = slice(2,7,2) # 从索引 2 开始到索引 7 停止,间隔为2 print (a[s])
输出结果为:
[2 4 6]
以上实例中,我们首先通过 arange() 函数创建 ndarray 对象。 然后,分别设置起始,终止和步长的参数为 2,7 和 2。
我们也可以通过冒号分隔切片参数 start:stop:step 来进行切片操作:实例 import numpy as np a = np.arange(10) b = a[2:7:2] # 从索引 2 开始到索引 7 停止,间隔为 2 print(b)
输出结果为:
[2 4 6]
冒号 : 的解释:如果只放置一个参数,如 [2],将返回与该索引相对应的单个元素。如果为 [2:],表示从该索引开始以后的所有项都将被提取。如果使用了两个参数,如 [2:7],那么则提取两个索引(不包括停止索引)之间的项。实例 import numpy as np a = np.arange(10) # [0 1 2 3 4 5 6 7 8 9] b = a[5] print(b)
输出结果为:5
9.NumPy 高级索引
NumPy 比一般的 Python 序列提供更多的索引方式。
除了之前看到的用整数和切片的索引外,数组可以由整数数组索引、布尔索引及花式索引。
NumPy 中的高级索引指的是使用整数数组、布尔数组或者其他序列来访问数组的元素。相比于基本索引,高级索引可以访问到数组中的任意元素,并且可以用来对数组进行复杂的操作和修改。
整数数组索引
整数数组索引是指使用一个数组来访问另一个数组的元素。这个数组中的每个元素都是目标数组中某个维度上的索引值。
以下实例获取数组中 (0,0),(1,1) 和 (2,0) 位置处的元素
实例 import numpy as np x = np.array([[1, 2], [3, 4], [5, 6]]) y = x[[0,1,2], [0,1,0]] print (y)
输出结果为:
[1 4 5]
布尔索引
我们可以通过一个布尔数组来索引目标数组。
布尔索引通过布尔运算(如:比较运算符)来获取符合指定条件的元素的数组。
以下实例获取大于 5 的元素:
实例 import numpy as np x = np.array([[ 0, 1, 2],[ 3, 4, 5],[ 6, 7, 8],[ 9, 10, 11]]) print (‘我们的数组是:’) print (x) print (‘\n’) # 现在我们会打印出大于 5 的元素 print (‘大于 5 的元素是:’) print (x[x > 5])
输出结果为:
我们的数组是:[[ 0 1 2] [ 3 4 5] [ 6 7 8] [ 9 10 11]]
大于 5 的元素是:[ 6 7 8 9 10 11]
10.NumPy 迭代数组
NumPy 迭代器对象 numpy.nditer 提供了一种灵活访问一个或者多个数组元素的方式。
迭代器最基本的任务的可以完成对数组元素的访问。
接下来我们使用 arange() 函数创建一个 2X3 数组,并使用 nditer 对它进行迭代。
实例 import numpy as np a = np.arange(6).reshape(2,3) print (‘原始数组是:’) print (a) print (‘\n’) print (‘迭代输出元素:’) for x in np.nditer(a): print (x, end=", " ) print (‘\n’)
输出结果 原始数组是: [[0 1 2] [3 4 5]] 迭代输出元素: 0, 1, 2, 3, 4, 5,
修改数组中元素的值
nditer 对象有另一个可选参数 op_flags。 默认情况下,nditer 将视待迭代遍历的数组为只读对象(read-only),为了在遍历数组的同时,实现对数组元素值的修改,必须指定 readwrite 或者 writeonly 的模式。
实例 import numpy as np a = np.arange(0,60,5) a = a.reshape(3,4) print (‘原始数组是:’) print (a) print (‘\n’) for x in np.nditer(a, op_flags=[‘readwrite’]): x[…]=2*x print (‘修改后的数组是:’) print (a)
输出结果为: 原始数组是:[[ 0 5 10 15] [20 25 30 35] [40 45 50 55]] 修改后的数组是:[[ 0 10 20 30] [ 40 50 60 70] [ 80 90 100 110]]
使用外部循环
nditer 类的构造器拥有 flags 参数,它可以接受下列值:
参数 | 描述 |
---|---|
c_index | 可以跟踪 C 顺序的索引 |
f_index | 可以跟踪 Fortran 顺序的索引 |
multi_index | 每次迭代可以跟踪一种索引类型 |
external_loop | 给出的值是具有多个值的一维数组,而不是零维数组 |
import numpy as np
a = np.arange(0,60,5)
a = a.reshape(3,4)
print ('原始数组是:')
print (a)
print ('\n')
print ('修改后的数组是:')
for x in np.nditer(a, flags = ['external_loop'], order = 'F'):
print (x, end=", " )
输出结果: 原始数组是: [[ 0 5 10 15] [20 25 30 35] [40 45 50 55]] 修改后的数组是: [ 0 20 40], [ 5 25 45], [10 30 50], [15 35 55],
11.Numpy数组操作
修改数组形状
函数 | 描述 |
---|---|
reshape | 不改变数据的条件下修改形状 |
flat | 数组元素迭代器 |
flatten | 返回一份数组拷贝,对拷贝所做的修改不会影响原始数组 |
ravel | 返回展开数组 |
numpy.reshape
numpy.reshape 函数可以在不改变数据的条件下修改形状,格式如下:
numpy.reshape(arr, newshape, order=‘C’)
arr
:要修改形状的数组newshape
:整数或者整数数组,新的形状应当兼容原有形状- order:‘C’ – 按行,‘F’ – 按列,‘A’ – 原顺序,‘k’ – 元素在内存中的出现顺序
numpy.ndarray.flatten
numpy.ndarray.flatten 返回一份数组拷贝,对拷贝所做的修改不会影响原始数组,格式如下:
ndarray.flatten(order=‘C’)
numpy.ravel
numpy.ravel() 展平的数组元素,顺序通常是"C风格",返回的是数组视图(view,有点类似 C/C++引用reference的意味),修改会影响原始数组。
该函数接收两个参数:
numpy.ravel(a, order=‘C’)
参数说明:
- order:‘C’ – 按行,‘F’ – 按列,‘A’ – 原顺序,‘K’ – 元素在内存中的出现顺序。
翻转数组
函数 | 描述 |
---|---|
transpose | 对换数组的维度 |
ndarray.T | 和 self.transpose() 相同 |
rollaxis | 向后滚动指定的轴 |
swapaxes | 对换数组的两个轴 |
numpy.transpose
numpy.transpose 函数用于对换数组的维度,格式如下:
numpy.transpose(arr, axes)
参数说明:
arr
:要操作的数组axes
:整数列表,对应维度,通常所有维度都会对换。
numpy.rollaxis
numpy.rollaxis 函数向后滚动特定的轴到一个特定位置,格式如下:
numpy.rollaxis(arr, axis, start)
参数说明:
arr
:数组axis
:要向后滚动的轴,其它轴的相对位置不会改变start
:默认为零,表示完整的滚动。会滚动到特定位置。
numpy.swapaxes
numpy.swapaxes 函数用于交换数组的两个轴,格式如下:
numpy.swapaxes(arr, axis1, axis2)
arr
:输入的数组axis1
:对应第一个轴的整数axis2
:对应第二个轴的整数
准备工作
安装pycharm和需要的软件包来进行代码的编辑
直接编辑代码导入,然后进行包的下载
小插曲
下载包的时候一直报错
去查询了一下报错原因pip安装报403错误 解决方法
于是我就把镜像地址又改了回来
pip config set global.index-url https://pypi.python.org/simple/
当然最后我检查了,大概不是清华园的问题(也可能是)
是pycharm本身的pip没有更新的问题
在这里更新完后就没有这个问题了,不用更改清华园的镜像
可以先更新一下项目pip,如果还是不对,就把镜像地址改回来
numpy包
这里numpy是在python处理大数据学过的一个库
对应OpenCv来说
使用Python运行OpenCV的程序时,OpenCV使用NumPy数组存储图像数据。基于NumPy可以很方便的执行基于数组的图像运算,比如图像的加法运算、加权加法运算和位运算等。
图像处理
颜色转换
cvtColor函数
dst=cv2.cvtColor(src,code[, dst[, dstCn]])
其中
dst(destination)就表示我们经过函数处理后得到的目的图像,此时是矩阵形式;
src(source)表示我们要进行转换的源图像对象,也是矩阵形式
code是opencv中色彩空间定义的宏常量,展示了我们要图像转换所要达到的结果,常用的有COLOR_BGR2GRAY、COLOR_GRAY2BGR、COLOR_BGR2HSV、COLOR_BGR2RGB等,但是实际上可以调用的参数多达247种。
dstCn为目标图像的通道数,如果设置为0,会自动从源图像计算目标图像的通道数;
以下是代码实例
from numpy import *
import numpy as np
import cv2
# 将图片转为灰度图
src_image = cv2.imread("test.jpg")
gray_imagee = cv2.cvtColor(src_image, cv2.COLOR_BGR2GRAY)
# 将图片转为HSV
hsv_image = cv2.cvtColor(src_image, cv2.COLOR_BGR2HSV)
# 展示一下
cv2.imshow("src_image", src_image)
cv2.imshow("gary_image", gray_imagee)
cv2.imshow("hsv_image", hsv_image)
cv2.waitKey(0)
src_iamge
hsv_image
gary_iamge
这样显示在显示器有点大,也可以写入
通过cv2.imwrite(“1.jpg”,hsv_iamge)函数来进行文件的保存然后查看会好一点
画矩形
rectangle()用法:
cv2.rectangle(img, pt1, pt2, color, thickness, lineType, shift)
参数说明:
-
img:在哪个图像上画线
-
pt1, pt2:开始点, 结束点:指定线的开始与结束位置
-
color:颜色
-
(0, 0, 255):红
-
(0, 255, 0):绿
-
(255, 0, 0):蓝
-
-
thickness:线宽
-
lineType:线型(可取值-1, 4, 8, 18), 默认为8
-
shift:坐标缩放比例
代码
# 画矩形
img = np.zeros((480, 640, 3), np.uint8)
cv2.rectangle(img, (20, 20), (400, 400), (0, 255, 0), 5)
cv2.imshow('draw', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果展示
画圆
circle()用法:
cv2.circle()(img, center, radius, color, thickness, lineType, shift)
参数说明:
-
img:在哪个图像上绘制圆
-
center:圆心坐标
-
radius:半径大小
-
color:颜色
-
thickness:线宽
-
lineType:线型
-
shift:坐标缩放比例
代码
# 画圆
img = np.zeros((480, 640, 3), np.uint8)
cv2.circle(img, (320, 240), 100, (255, 0, 0), 5, 16)
cv2.imshow('draw', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果展示
画椭圆
ellipse()用法:
cv2.ellipse(img, center, axes, angle, startAngle, endAngle, color, thickness, lineType, shift)
参数说明:
-
img:在哪个图像上绘制椭圆
-
center:中心点
-
axes:长宽的一半
-
angle:角度
-
startAngle:从哪个角度开始
-
endAngle:从哪个角度结束
-
color:颜色
-
thickness:线宽
-
lineType:线型
-
shift:坐标缩放比例
代码
# 画椭圆
img = np.zeros((480, 640, 3), np.uint8)
cv2.ellipse(img, (320, 240), (100, 50), 0, 0, 360, (255, 255, 255), 5, 16)
cv2.imshow('draw', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果展示
画线段
line()用法:
cv2.line(img, pt1, pt2, color, thickness, lineType, shift)
参数说明:
line()用法和rectangle()用法 完全一致。
代码
# 画线段
img = np.zeros((480, 640, 3), np.uint8)
# 划线, 坐标点(x, y)
cv2.line(img, (20, 20), (400, 400), (0, 0, 255), 5, 16)
cv2.imshow('draw', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果展示
画和填充多边形
polylines():绘制多边形
cv2.polylines(img, pts, isClosed, color, thickness, lineType, shift)
参数说明:
-
img:在哪个图像上绘制和填充多边形
-
pts:多边形的点集,必须是int32位
-
isClosed:是否闭合
-
color:颜色
-
thickness:线宽
-
lineType:线型
-
shift:坐标缩放比例
代码
img = np.zeros((480, 640, 3), np.uint8)
pts = np.array([(300, 10), (150, 100), (450, 100)], np.int32)
cv2.polylines(img, [pts], True, (0, 255, 255), 5, 16)
cv2.imshow('draw', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果展示
fillPoly
:填充多边形
cv2.fillPoly(img, pts, color)
fillPoly用法 和 polylines用法 完全一致。
代码
img = np.zeros((480, 640, 3), np.uint8)
pts = np.array([(300, 10), (150, 100), (450, 100)], np.int32)
cv2.fillPoly(img, [pts], (0, 255, 255), 16)
cv2.imshow('draw', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果展示
绘制文字
putText:绘制文字
putText(img,text,org,fontFace,fontScale,color,thickness,lineType,bottomLeftOrigin)
参数说明:
-
text要绘制的文字内容
-
org 文字在画布中的左下角坐标
-
fontFace 字体样式
-
fontScale 字体大小
-
lineType 线型
-
bottomLeftOrigin 绘制文字时的方向
代码
import numpy as np # 导入Python中的numpy模块
import cv2
# np.zeros():创建了一个画布
# (100, 300, 3):一个100 x 300,具有3个颜色空间(即Red、Green和Blue)的画布
# np.uint8:OpenCV中的灰度图像和RGB图像都是以uint8存储的,因此这里的类型也是uint8
canvas = np.zeros((100, 300, 3), np.uint8)
# 在画布上绘制文字“mrsoft”,文字左下角的坐标为(20, 70)
# 字体样式为FONT_HERSHEY_TRIPLEX
# 字体大小为2,线条颜色是绿色,线条宽度为5
cv2.putText(canvas, "sorry", (20, 70), cv2.FONT_HERSHEY_TRIPLEX, 2, (0, 255, 0), 5)
cv2.imshow("Text", canvas) # 显示画布
cv2.waitKey()
cv2.destroyAllWindows()
效果展示
为图像添加边框
copyMakeBorder:为图像添加边框
cv.copyMakeBorder(src, top, bottom, left, right, borderType, None, value)
参数说明:
-
src: 即将被扩充边界的原始图像
-
top, bottom, left, right: 在图像上、下、左、右分别要扩充的行(列)数
-
borderType: 扩充的边界类型
-
cv2.BORDER_CONSTANT: 用常数像素值填充扩充的边界(0或黑色)
-
cv2.BORDER_REPLICATE: 原始边缘的行或列被复制到扩充的边界
-
-
value: 当使用cv.BORDER_CONSTANT时,设置的要填充的像素值
代码
import cv2
import numpy as np
from matplotlib import pyplot as plt
BLUE = [255, 0, 0]
img1 = cv2.imread('test.jpg')
replicate = cv2.copyMakeBorder(img1, 100, 100, 100, 100, cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img1, 100, 100, 100, 100, cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img1, 100, 100, 100, 100, cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img1, 100, 100, 100, 100, cv2.BORDER_WRAP)
constant = cv2.copyMakeBorder(img1, 100, 100, 100, 100, cv2.BORDER_CONSTANT, value=BLUE)
plt.subplot(231), plt.imshow(img1, 'gray'), plt.title('ORIGINAL')
plt.subplot(232), plt.imshow(replicate, 'gray'), plt.title('REPLICATE')
plt.subplot(233), plt.imshow(reflect, 'gray'), plt.title('REFLECT')
plt.subplot(234), plt.imshow(reflect101, 'gray'), plt.title('REFLECT_101')
plt.subplot(235), plt.imshow(wrap, 'gray'), plt.title('WRAP')
plt.subplot(236), plt.imshow(constant, 'gray'), plt.title('CONSTANT')
plt.show()
效果展示
轮廓检测和画出轮廓
findContours:轮廓检测:
contours,hierarchy =cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]])
参数说明:
-
image:参数是寻找轮廓的图像;
-
mode:参数表示轮廓的检索模式,有四种(本文介绍的都是新的cv2接口):
-
cv2.RETR_EXTERNAL:表示只检测外轮廓
-
cv2.RETR_LIST:检测的轮廓不建立等级关系
-
cv2.RETR_CCOMP:建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
-
cv2.RETR_TREE:建立一个等级树结构的轮廓。
-
-
method:轮廓的近似办法:
-
cv2.CHAIN_APPROX_NONE:存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
-
cv2.CHAIN_APPROX_SIMPLE:压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
-
cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS:使用teh-Chinl chain 近似算法
-
返回值:
cv2.findContours()函数返回两个值,一个是轮廓本身,还有一个是每条轮廓对应的属性。
-
contour返回值: 返回一个list,list中每个元素都是图像中的一个轮廓,用numpy中的ndarray表示。
-
hierarchy返回值: 返回一个ndarray,其中的元素个数和轮廓个数相同,每个轮廓 c o n t o u r s [ i ] contours[i] contours[i]对应4个hierarchy元素 h i e r a r c h y [ i ] [ 0 ] h i e r a r c h y [ i ] [ 3 ] hierarchy[i][0] ~hierarchy[i][3] hierarchy[i][0] hierarchy[i][3],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,则该值为负数
drawContours:画出轮廓
drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None):
参数说明:
-
Image:输入原始的图像;
-
Contours:坐标点(这个根据查找轮廓函数即可得到);
-
contourIdx;设置轮廓的顺序号;-1表示绘制所有的轮廓;
-
Color:绘制使用的颜色;
-
Thickness:绘制使用的线宽;-1表示全部填充;
-
lineType:绘制使用的线类型;
-
Hierarchy:设置层级;
-
maxLevel:如果为0,则仅绘制指定的轮廓。
- 如果为1,则函数将绘制轮廓和所有嵌套轮廓。如果为2,则函数绘制等高线、所有嵌套等高线、所有嵌套到嵌套等高线,等等。这仅当存在可用的层次结构时,才考虑参数。
-
Offset:将所有绘制的轮廓移动指定的量。
代码
import cv2
img = cv2.imread('test.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 检测轮廓
contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
# 画轮廓
cv2.drawContours(img, contours, -1, (0, 0, 255), 3)
cv2.imshow("img", img)
cv2.waitKey(0)
效果展示
四、实验结果
实验结果已经在实验过程中写出,实验结果的所有截图均可在实验过程中查看,这里不做过多展示
五、实验结论
在本实验中,涵盖了NumPy数组操作和OpenCV图像处理两个重要方面。在NumPy数组操作部分,学到了如何使用 NumPy 创建各种类型的数组,包括一维数组、二维数组等,以及如何访问和修改数组中的元素,了解了数组对象的一些属性,比如形状、大小等,以及数组对象的一些方法,比如求和、平均值、最大值、最小值等,学习了如何改变数组的形状,包括改变维度、转置数组、重塑数组等操作,通过学习 reshape、transpose、rollaxis、swapaxes 等函数实现了这些操作,以及掌握了如何使用索引和切片对数组进行元素的访问和修改,包括基本索引、切片索引、布尔索引等方法。在opencv图像处理部分,了解了如何在OpenCV中实现图像的颜色空间转换,这对于图像处理中很多任务都是必不可少的;学习到如何在图像上绘制基本的几何图形,在图像上添加文字,以及如何为图像添加边框以及使用OpenCV查找图像中的轮廓,对OpenCV图像处理模块的功能和应用有了更深入的理解。通过本实验的学习,深入理解了 NumPy 数组的概念、数组的重塑和操作方法,加深了对数组运算和操作的理解。同时,还学习了OpenCV图像处理模块的功能和应用,掌握了实现颜色变换、绘制基本图形、文字绘制、为图像添加边框以及在图像中查找轮廓等技术。为后续更复杂的数据、图像处理和科学计算打下了良好的基础。