掌握OpenCV的基石:NumPy入门教程(为计算机视觉打下坚实基础)

欢迎来到计算机视觉的世界!如果你正准备踏上OpenCV的学习之旅,那么你一定听说过NumPy。它不仅仅是一个普通的Python库,更是OpenCV在Python中进行图像处理、数据操作的基石。可以说,不理解NumPy,就很难真正掌握OpenCV的精髓。

这篇博客带你快速入门NumPy,了解其核心概念和常用操作,为后续学习OpenCV扫清障碍。

为什么先学NumPy?

在OpenCV中,图像被表示为多维NumPy数组:

  • 灰度图像:一个二维数组(高度✖宽度)
  • 彩色图像:一个三维数组(高度✖宽度✖通道数),例如BGR(蓝绿红)图像的通道数为3。

NumPy提供了高效的数组操作,这对于处理包含成千上万甚至数百万像素的图像至关重要。Python原生的列表(list)在处理大规模数值运算时效率较低,而NumPy底层由C语言实现,能进行快速的向量化运算。

本教程将涵盖:

1.什么是NumPy数组?

2.如何创建NumPy数组?
3.数组的属性(形状、数据类型等)

4.数组的索引与切片

5.基本的数组运算

6.常用的NumPy函数

准备工作

首先,确保你已经安装了Python。然后,通过pip安装NumPy:

pip install numpy

在你的Python脚本或jupyter Notebook中,我们通常这样导入numPy:

import numpy as np

np是NumPy的标准别名,你会发现几乎所有的NumPy用户都这么做。


1.什么是NumPy数组(ndarray)?

NumPy的核心是ndarray对象。它是一个多维数组,用于存储同类型的元素(通常是数字),比如整数(int)或浮点数(float)。

与Python列表的区别:

类型统一:NumPy数组中的所有元素必须是相同的数据类型,这使得存储和计算更高效。

性能:NumPy数组操作通常比等效的Python列表操作快得多,尤其是在大数据集上。

功能:NumPy提供了大量针对数组优化的数学函数。

2.如何创建NumPy数组?

有多种方法可以创建NumPy数组:

a.从Python列表或元组创建

#一维数组
arrld = np.array([1,2,3,4,5])
print("一维数组:")
print(arr1d)

# 二维数组 
arr2d = np.array([[1, 2, 3], [4, 5, 6]])
print("n二维数组:")
print(arr2d)

# 三维数组 
arr3d = np.array([[[1,2,3], [4,5,6]], [[7,8,9], [10,11,12]]])
print("n三维数组:")
print(arr3d)

b.使用NumPy内置函数创建

  • np.zeros(): 创建全零数组。
  • np.ones(): 创建全一数组。
  • np.arange(): 类似于 Python 的 range(),但返回一个数组。
  • np.linspace(): 创建等差数列。
  • np.random.rand() / np.random.randn() / np.random.randint(): 创建随机数组。
# 创建一个 2x3 的全零数组 (常用于初始化)
zeros_arr = np.zeros((2, 3))
print("n全零数组:")
print(zeros_arr)

# 创建一个 3x2 的全一数组,数据类型为整数
ones_arr = np.ones((3, 2), dtype=np.int16)
print("n全一数组 (整数类型):")
print(ones_arr)

# 创建从 0 到 9 的数组
range_arr = np.arange(10)
print("n0到9的数组:")
print(range_arr)

# 创建从 0 到 10,包含 5 个等间距元素的数组
linspace_arr = np.linspace(0, 10, 5)
print("n等差数组:")
print(linspace_arr)

# 创建一个 2x2 的,元素在 [0, 1) 之间均匀分布的随机数组
random_arr = np.random.rand(2, 2)
print("n随机数组 [0,1):")
print(random_arr)

# 创建一个 3x3 的,[0, 10) 之间的随机整数数组
random_int_arr = np.random.randint(0, 10, size=(3,3))
print("n随机整数数组 [0,10):")
print(random_int_arr)

注意 dtype 参数: 在创建数组时,可以指定数据类型。对于图像处理,np.uint8 (0-255 的无符号整数) 是非常常见的数据类型。

3.数组的属性

了解数组的属性对于操作它们至关重要:

  • ndarray.ndim: 数组的轴(维度)的个数。
  • ndarray.shape: 数组的维度。这是一个整数元组,表示每个维度中数组的大小。例如,一个 n 行 m 列的矩阵,它的 shape 将是 (n, m)。对于一个彩色图像,可能是 (height, width, 3)。
  • ndarray.size: 数组元素的总个数。等于 shape 属性中元组元素的乘积。
  • ndarray.dtype: 一个描述数组中元素类型的对象。例如 numpy.int32, numpy.float64, numpy.uint8。
  • ndarray.itemsize: 数组中每个元素的字节大小。
img_array = np.random.randint(0, 256, size=(100, 200, 3), dtype=np.uint8) # 模拟一个 100x200 的彩色图像

print(f"n模拟图像数组属性:")
print(f"维度数量 (ndim): {img_array.ndim}")
print(f"形状 (shape): {img_array.shape}") # (高度, 宽度, 通道数)
print(f"元素总数 (size): {img_array.size}")
print(f"数据类型 (dtype): {img_array.dtype}")
print(f"每个元素的字节大小 (itemsize): {img_array.itemsize}")

4.数组的索引与切片

这部分与 Python 列表的索引和切片非常相似,但可以扩展到多维。

a.一维数组索引与切片

arr = np.arange(10) # [0 1 2 3 4 5 6 7 8 9]
print(f"n一维数组: {arr}")

# 获取单个元素
print(f"元素在索引 3: {arr[3]}") # 输出 3

# 切片 [start:stop:step] (不包括 stop)
print(f"从索引 2 到 5: {arr[2:6]}") # 输出 [2 3 4 5]
print(f"所有元素,步长为 2: {arr[::2]}") # 输出 [0 2 4 6 8]

b.多维数组索引与切片

这是OpenCV中最常用的操作之一,例如提取图像的某个区域(ROI)

# 创建一个 3x4 的二维数组
matrix = np.array([[1, 2, 3, 4],
                   [5, 6, 7, 8],
                   [9, 10, 11, 12]])
print(f"n二维数组 matrix:n{matrix}")

# 获取单个元素 (row, column)
print(f"第 1 行, 第 2 列的元素 (0-indexed): {matrix[1, 2]}") # 输出 7

# 获取某一行
print(f"第 0 行: {matrix[0, :]}") # 输出 [1 2 3 4]  或者 matrix[0]
print(f"第 0 行 (另一种写法): {matrix[0]}")

# 获取某一列
print(f"第 1 列: {matrix[:, 1]}") # 输出 [ 2  6 10]

# 子区域切片 (ROI)
# 提取 matrix 的左上角 2x2 子矩阵
roi = matrix[0:2, 0:2]
print(f"ROI (左上角 2x2):n{roi}")
# 输出:
# [[1 2]
#  [5 6]]

# 对于三维数组 (如彩色图像),索引类似:arr[height_slice, width_slice, channel_slice]
# 例如,获取彩色图像的蓝色通道: blue_channel = img_array[:, :, 0] (假设 BGR 顺序)

重要: NumPy 切片返回的是原始数组的视图 (view),而不是副本。这意味着修改视图会直接影响原始数组。如果需要副本,请使用 .copy() 方法,例如 roi_copy = matrix[0:2, 0:2].copy()。

5.基本的数组运算

NumPy允许你对整个数组执行元素级运算,这非常高效。

a.标量运算:数组与单个数字(标量)的运算。

arr = np.array([[1, 2], [3, 4]])
print(f"n原始数组 arr:n{arr}")

print(f"arr + 5:n{arr + 5}")
print(f"arr * 2:n{arr * 2}")
print(f"arr / 2:n{arr / 2}")
print(f"arr ** 2 (平方):n{arr ** 2}")

b.数组间运算: 两个形状相同的数组之间的运算。

a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
print(f"n数组 a:n{a}")
print(f"数组 b:n{b}")

print(f"a + b:n{a + b}")
print(f"a * b (元素级乘法):n{a * b}")

注意: a * b 是元素级乘法,不是矩阵乘法。矩阵乘法使用 @ 运算符或 np.dot() 函数。

print(f"a @ b (矩阵乘法):n{a @ b}")
print(f"np.dot(a, b) (矩阵乘法):n{np.dot(a, b)}")

c. 广播:

当操作不同形状的数组时,NumPy 有一套广播规则,可以自动扩展较小数组的维度,使其与较大数组兼容。这是一个强大但有时也容易混淆的特性。
一个简单的例子:

arr = np.array([[1, 2, 3], [4, 5, 6]]) # shape (2, 3)
row_vector = np.array([10, 20, 30])    # shape (3,) -> 广播为 (1, 3)
print(f"n数组 arr:n{arr}")
print(f"行向量 row_vector:n{row_vector}")

# row_vector 会被广播到 arr 的每一行进行相加
print(f"arr + row_vector (广播):n{arr + row_vector}")
# 输出:
# [[11 22 33]
#  [14 25 36]]

6.常用的NumPy函数

NumPy函数提供了大量的数学函数,称为通用函数,它们可以直接作用于数组。

arr = np.array([-1, 0, 1, 2, 3, 4])
data = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(f"n数组 data:n{data}")

# 基本统计
print(f"data 中所有元素的和: {np.sum(data)}")
print(f"data 中所有元素的平均值: {np.mean(data)}")
print(f"data 中最大值: {np.max(data)}")
print(f"data 中最小值: {np.min(data)}")
print(f"data 标准差: {np.std(data)}")

# 沿轴操作 (axis=0 表示沿列操作,axis=1 表示沿行操作)
print(f"data 每列的和 (axis=0): {np.sum(data, axis=0)}") # [12 15 18]
print(f"data 每行的最大值 (axis=1): {np.max(data, axis=1)}") # [3 6 9]

# 其他常用函数
print(f"arr 的平方根 (负数会产生 nan): {np.sqrt(np.abs(arr))}") # np.abs取绝对值避免负数开方错误
print(f"arr 的指数: {np.exp(arr)}")
print(f"数组中大于2的元素: {data[data > 2]}") # 布尔索引

# 改变数组形状
flat_arr = data.flatten() # 将多维数组转换为一维数组
print(f"data 展平后: {flat_arr}")

reshaped_arr = data.reshape((1, 9)) # 重塑为 1x9 数组
print(f"data 重塑为 1x9:n{reshaped_arr}")

总结与展望

恭喜你!你已经了解了 NumPy 的基础知识,包括:

  • ndarray 对象及其与 Python 列表的区别。
  • 创建数组的多种方法。
  • 获取数组的关键属性,如形状、数据类型。
  • 强大的索引和切片能力,特别是对于多维数组。
  • 高效的元素级运算和广播机制。
  • 一些常用的数学和统计函数。

这些知识是你学习 OpenCV 的关键。当你开始用 OpenCV 加载图像时,你会发现 cv2.imread() 返回的就是一个 NumPy 数组。你将使用 NumPy 的切片来选取图像区域,使用 NumPy 的运算来修改像素值,使用 NumPy 的函数来进行各种图像分析。

下一步:

  • 多练习! 亲手敲代码是掌握 NumPy 最好的方法。尝试创建不同形状和数据类型的数组,并对它们进行各种操作。
  • 查阅官方文档: NumPy 的[官方文档](NumPy 文档 — NumPy v2.3 手册)非常全面,是深入学习的好资源。
  • 开始学习 OpenCV: 现在你已经准备好将 NumPy 的知识应用到实际的图像处理中了!

希望这篇入门教程对你有所帮助。在学习 OpenCV 的道路上,NumPy 将是你最忠实的伙伴。祝学习愉快!

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇