NumPy 数组与矩阵基础

参考:《计算机视觉开发实践》朱文伟 李建英 著

前言

在 OpenCV 中:

import cv2 as cv
img = cv.imread("test.jpg")
  • img 的类型是 numpy.ndarray(数组),包含每个像素点的数据。
  • 熟悉 NumPy 是操作图像数据的基础。它极大简化了向量/矩阵运算,是数据分析、机器学习和科学计算的基石。
  • 又要开始掏出那本线性代数

4.1 NumPy 概述

NumPy 是一个高性能的数学库,核心能力:

  • 强大的 N 维数组对象 ndarray
  • 广播(Broadcasting)
  • 与 C/C++/Fortran 互操作
  • 线性代数、傅里叶变换、随机数

NumPy 常与 SciPy(科学计算)和 Matplotlib(可视化)搭配使用,常见于替代 MATLAB 的技术计算场景。NumPy 是开源项目。

为什么使用 NumPy?

  • Python 的 list 保存的是“对象指针”,如 [1,2,3,4] 需要 4 个指针和 4 个整数对象,运算开销大。
  • array 模块的 array 能直接保存数值,但不支持多维数组,也缺乏数值计算相关函数。
  • NumPy 提供:
  • ndarray(同类型、多维数组,高效存储与运算)
  • 通用函数(ufunc,向量化计算)

4.2 ndarray 对象

4.2.1 简介

ndarray 是同类型元素的多维数组,内部包含:

  • 指向数据(内存或内存映射)的指针
  • 数据类型 dtype(描述固定大小元素)
  • 形状 shape(各维度大小的元组)
  • 跨度 stride(到同维度下一个元素需跨过的字节数)

4.2.2 创建 ndarray

函数原型:

numpy.array(object, dtype=None, copy=True, order=None, subok=False, ndmin=0)

参数要点:

  • object:数组或嵌套序列
  • dtype:元素数据类型
  • copy:是否复制
  • order:内存布局,”C” 行优先,”F” 列优先,”A” 自动
  • subok:是否保持子类
  • ndmin:最小维度

4.3 NumPy 的数据类型

4.3.1 类型概览

  • 布尔:bool(True/False)
  • 整数:int8、int16、int32、int64
  • 无符号整数:uint8、uint16、uint32、uint64
  • 浮点:float16、float32、float64
  • 复数:complex64、complex128
  • 字符串:str(字节串 S 或 Unicode U)
  • 对象:object

4.3.2 numpy.dtype()

函数原型:

numpy.dtype(object, align=False, copy=False)

示例:

import numpy as np

dt = np.dtype(np.int32)    # int32
print(dt)

dt = np.dtype('i4')        # int32 的别名
print(dt)

dt = np.dtype([('age', np.int8)])
print(dt)                  # [('age', 'i1')]

dt = np.dtype([('age', np.int8), ('name', 'S20')])
print(dt)                  # 结构化 dtype

dt = np.dtype([('age', np.int8), ('name', 'S20')], align=True)
print(dt)

4.4 数组属性

4.4.1 轴与维度(axis)

在 NumPy 中,每一条“线性方向”称为一个轴(axis)。

二维数组示例:

import numpy as np

a = np.array([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])
# shape = (3, 3)

print(np.sum(a, axis=0))  
# 列方向相加
[ (1+4+7), (2+5+8), (3+6+9) ] -> [12 15 18]

print(np.sum(a, axis=1))  
# 行方向相加
[ (1+2+3), (4+5+6), (7+8+9) ] -> [ 6 15 24]

可视化理解:

```
                  axis=1 →
              ┌────────────┐
              │ 1   2   3  │  axis=0 
              │ 4   5   6  │    ↓           
              │ 7   8   9  │
              └────────────┘
```

三维数组示例:

a = np.array([
    [
        [1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]
    ],
    [
        [9, 8, 7],
        [6, 5, 4],
        [3, 2, 1]
    ]
])
# shape = (2, 3, 3)

axis=0 ↓   (矩阵层的方向)
 ┌──────────┐       ┌──────────┐
 │ 1  2  3  │       │ 9  8  7  │
 │ 4  5  6  │       │ 6  5  4  │
 │ 7  8  9  │       │ 3  2  1  │
 └──────────┘       └──────────┘
     axis=1 ↓                 axis=1 ↓
     行方向                    行方向
     axis=2 →                 axis=2 →
     列方向                    列方向

 np.sum(a, axis=0)
 对应位置相加:
 [                                        [
   [ (1+9), (2+8), (3+7) ],                 [10, 10, 10],
   [ (4+6), (5+5), (6+4) ]       →         [10, 10, 10], 
   [ (7+3), (8+2), (9+1) ]                  [10, 10, 10]
 ]                                        ]
 np.sum(a, axis=1)
 对每个2D矩阵的行进行相加:
 [                                        [
   [ (1+4+7), (2+5+8), (3+6+9) ],     →    [12, 15, 18],
   [ (9+6+3), (8+5+2), (7+4+1) ]            [18, 15, 12]
 ]                                        
 np.sum(a, axis=2)
 对每个2D矩阵的列进行相加:
 [                                        [
   [ (1+2+3), (4+5+6), (7+8+9) ],     →     [6, 15, 24],
   [ (9+8+7), (6+5+4), (3+2+1) ]             [24, 15, 6]
 ]                                        ]

总结:axis 的编号,就是告诉 numpy “在哪一维上压缩”。数越小,维度越外层(0 最外层,2 最内层)。

4.4.2 ndarray 常用属性

import numpy as np

a = np.arange(24)
b = a.reshape(2, 4, 3)

print(a.ndim, b.ndim)   # 维度:1, 3
print(a.shape, b.shape) # 形状:(24,), (2, 4, 3)
print(a.size, b.size)   # 元素总数:24, 24
print(a.dtype, b.dtype) # 数据类型:int32, int32(随平台而异)
print(a.itemsize)       # 每个元素占字节数,例如 4

# OpenCV 图像就是 ndarray
import cv2
img = cv2.imread("test.jpg")
print(type(img))  # <class 'numpy.ndarray'>
print(img.ndim)   # 3(H, W, C)
print(img.shape)  # (高度, 宽度, 通道数)
print(img.size)   # 像素总数 * 通道数
print(img.dtype)  # 常见为 uint8

4.5 新建数组

常用方式:

import numpy as np

# 1) 由列表/元组创建
a = np.array([1, 2, 3, 4, 5])
b = np.array([[1, 2, 3], [4, 5, 6]])

# 2) 等差序列
ar = np.arange(0, 10, 2)            # [0 2 4 6 8]

# 3) 等间隔序列
ls = np.linspace(0, 1, 5)           # [0.   0.25 0.5 0.75 1.  ]

# 4) 全零 / 全一
z = np.zeros((3, 4))
o = np.ones((2, 3))

# 5) 单位矩阵
I = np.eye(3)

# 6) 随机数组([0,1))
r = np.random.rand(2, 3)

# 7) empty(未初始化,值未定义)
e = np.empty((2, 2))

参数说明:

  • order 有 “C” 和 “F” 两种(行优先/列优先),影响内存布局和部分运算性能。

4.5 数组切片和索引

NumPy 支持类似 Python 列表的切片/索引,并扩展到多维。

一维示例:

import numpy as np

a = np.array([10, 20, 30, 40, 50])
print(a[0])     # 10(第一个元素)
print(a[1:4])   # [20 30 40](左闭右开)

a[2] = 99
print(a)        # [10 20 99 40 50]

二维示例:

b = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(b[0, 1])        # 2(第 1 行第 2 列)
print(b[1:3, 0:2])    # [[4 5]
                       #  [7 8]]

b[2, 2] = 99
print(b)

切片语义:

  • [2]:返回单个元素
  • [2:]:从索引 2 开始到末尾
  • [2:7]:索引 [2, 7) 的切片(不含 7)

4.6 迭代数组

4.6.1 nditer

numpy.nditer(op, flags=None, op_flags=None, order='K', casting='safe', itershape=None, buffersize=0)
  • op:要迭代的数组/数组序列
  • flags:迭代器工作方式
  • op_flags:每个操作数读写权限
  • order:迭代顺序
  • casting:类型转换规则
  • itershape:迭代器形状
  • buffersize:缓冲区大小

4.6.2 基本迭代

import numpy as np

a = np.array([[1, 2, 3], [4, 5, 6]])
for x in np.nditer(a):
    print(x, end=' ')
# 1 2 3 4 5 6

4.6.3 修改元素

a = np.array([[1, 2, 3], [4, 5, 6]])
for x in np.nditer(a, op_flags=['readwrite']):
    x[...] = x * 2
print(a)
# [[ 2  4  6]
#  [ 8 10 12]]

4.6.4 多数组迭代

a = np.array([[1, 2, 3], [4, 5, 6]])
b = np.array([[10, 20, 30], [40, 50, 60]])
for x, y in np.nditer([a, b]):
    print(f'a: {x}, b: {y}')
# a: 1, b: 10
# a: 2, b: 20
# a: 3, b: 30
# a: 4, b: 40
# a: 5, b: 50
# a: 6, b: 60

4.7 数组形状操作

4.7.1 重塑 reshape

import numpy as np

a = np.arange(12)
b = a.reshape((3, 4))
print(b)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]
  • order:’C’ 按行优先,’F’ 按列优先,’A’ 遵循原数组顺序

4.7.2 扁平化 flatten

a = np.array([[1, 2, 3], [4, 5, 6]])
b = a.flatten()  # [1 2 3 4 5 6]

4.7.3 转置 transpose

a = np.array([[1, 2, 3], [4, 5, 6]])
b = np.transpose(a)
print(b)
# [[1 4]
#  [2 5]
#  [3 6]]

小结

  • OpenCV 读入的图像就是一个 dtype 通常为 uint8 的三维 ndarray。
  • 熟悉 dtype、shape、ndim、stride 能帮助你写出更高效的图像算法。
  • 掌握切片、广播、迭代与形状变换,可以用极少代码完成复杂的数据处理。
暂无评论

发送评论 编辑评论


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