OpenCV - 矩阵操作 Part 3

本文最后更新于:2022年7月4日 上午

OpenCV 自带大量矩阵处理函数,本文记录相关内容。

简介

  • OpenCV 矩阵类的成员函数可以进行很多基本的矩阵操作,本文基于 《学习 OpenCV3 》中第五章的内容整理 Python OpenCV 矩阵操作函数。

内容列表

序号 函数 描述
1 cv2.phase() 计算二维向量的方向
2 cv2.polarToCart() 已知角度和幅度,求出对应的二维向量
3 cv2.pow() 对矩阵内的每个元素求幂
4 cv2.randu() 用均匀分布的随机数填充给定的矩阵
5 cv2.randn() 用正态分布的随机数填充给定的矩阵
6 cv2.randShuffle() 随机打乱矩阵元素
7 cv2.reduce() 通过特定的操作将二维矩阵缩减为向量
8 cv2.repeat() 将一个矩阵的内容复制到另一个矩阵
9 cv2.setIdentity() 将矩阵中对角线上的元素设为1,其他置0
10 cv2.solve() 求出线性方程组的解
11 cv2.solveCubic() 找到三次方程的实根
12 cv2.solvePoly() 找到多项式方程的复根
13 cv2.sort() 在矩阵中排序任意行或列的元素
14 cv2.sortIdx() cv2.sort() 的目的相同,除了矩阵是未修改的,并返回索引
15 cv2.split() 将一个多通道矩阵分割成多个单通道矩阵
16 cv2.sqrt() 计算矩阵逐元素的平方根
17 cv2.subtract() 实现两个矩阵逐元素相减
18 cv2.trace() 计算一个矩阵的迹
19 cv2.transform() 在矩阵的每个元素上应用矩阵变换
20 cv2.transpose() 矩阵的转置运算

矩阵操作

0. 基础引用

  • 之后对上述函数进行示例演示
  • 所有代码默认引用如下包
1
2
3
4
import cv2
import numpy as np
import mtutils as mt
from mtutils import PIS
  • 示例图片 img1.jpgimg2.jpg

  • 查看 opencv 某函数 func 文档可以运行:
1
print(cv2.<func>.__doc__)

1. cv2.phase()

计算二维向量的方向

  • 函数使用
1
cv2.phase(x, y)  --> dst

对二维矢量场计算笛卡尔一极坐标转换的方位角(角度)部分。该矢量场是由两个独立的单通道矩阵组成。当然这两个输入矩阵的尺寸相同。(如果你有一个二通道的矩阵,那么调用cv2.phase()将会做你所需要的。)然后,dst中的每一个元素都从xy的相应元素中计算两者的反正切值得到。

  • 代码示例
1
2
3
4
5
6
7
8
9
x = np.array([1, 0, -1], dtype='float32')
y = np.array([1, -1, 1], dtype='float32')
res = cv2.phase(x, y)

-->
res
array([[0.7852316],
[4.712389 ],
[2.3563612]], dtype=float32)

上述结果分别为 $\frac{\pi}{4}$, $\frac{3\pi}{2}$, $\frac{3\pi} { 4 }$

2. cv2.polarToCart()

已知角度和幅度,求出对应的二维向量

  • 函数使用
1
cv2.polarToCart(magnitude, angle, angleInDegrees=False) 
$$ \begin{array}{c} x_{i}= magnitude _{i} \cos \left(\right. angle \left._{i}\right) \\ y_{i}= magnitude _{i} \sin \left(\right. angle \left._{i}\right) \end{array} $$

cv2.polarToCart() 从向量场的极坐标中计算笛卡尔坐标(x,y)。输入具有相同尺寸和类型的两个矩阵:幅度和角度,指定每个点处向量的幅度和角度。输出类似的两个矩阵,它们与输入具有相同的尺寸和类型,并且将包含每个点处向量的xy投影。附加标志angleInDegrees将使角度矩阵中的数值以度为单位,而不是弧度。

  • 代码示例
1
2
3
4
5
6
7
8
mag = np.array(2**0.5)
angle = np.array(np.pi/4)
res = cv2.polarToCart(mag, angle)


-->
res
(array([[1.]]), array([[1.]]))

3. cv2.pow()

对矩阵内的每个元素求幂

1
2
3
4
5
6
7
8
9
10
data = np.reshape(np.arange(20), [4, 5])
res = cv2.pow(data, 2)


-->
res
array([[ 0, 1, 4, 9, 16],
[ 25, 36, 49, 64, 81],
[100, 121, 144, 169, 196],
[225, 256, 289, 324, 361]], dtype=int32)

4. cv2.randu()

用均匀分布的随机数填充给定的矩阵

注意: 该函数内联修改,输入数据会直接变为随机矩阵

  • 函数使用
1
cv2.randu(data, low, high) 

内联产生 low high 之间的均匀分布随机数矩阵

  • 示例代码
1
2
3
4
5
6
7
8
9
10
data = np.zeros([5, 5])
cv2.randu(data, low=2, high=3)

-->
data
array([[2.16117805, 2.03818934, 2.42586133, 2.84612762, 2.88760448],
[2.26471239, 2.27078305, 2.95266639, 2.6751313 , 2.81021636],
[2.18396021, 2.0944562 , 2.81590329, 2.52451766, 2.38083885],
[2.41199476, 2.25553534, 2.9448959 , 2.90012348, 2.45789156],
[2.84130697, 2.28030013, 2.3854357 , 2.45190146, 2.87543355]])

5. cv2.randn()

用正态分布的随机数填充给定的矩阵

注意: 该函数内联修改,输入数据会直接变为随机矩阵

  • 函数使用
1
cv2.randn(data, mean, stddev) 

内联产生以mean为均值,stddev 为标准差的正态分布随机数矩阵

  • 示例代码
1
2
3
4
5
6
7
8
9
10
data = np.zeros([5, 5])
cv2.randn(data, mean=5, stddev=1)

-->
data
array([[6.27751625, 6.43329835, 4.49584228, 3.92785478, 6.10956049],
[5.49447021, 4.10116905, 4.46068269, 4.88458967, 4.05134571],
[5.52288508, 5.11468363, 5.03454646, 4.02846879, 5.8627224 ],
[6.25682068, 4.23800135, 5.5566175 , 7.2824192 , 7.58638453],
[6.67061222, 4.90155111, 6.18168759, 3.01809192, 6.19408202]])

6. cv2.randShuffle()

随机打乱矩阵元素

1
2
3
4
5
6
7
8
9
10
data = np.reshape(np.arange(25), [5, 5])
cv2.randShuffle(data)

-->
data
array([[14, 5, 1, 13, 2],
[23, 20, 21, 3, 8],
[22, 4, 16, 7, 6],
[18, 17, 19, 24, 15],
[10, 11, 9, 12, 0]])

7. cv2.reduce()

通过特定的操作将二维矩阵缩减为向量

  • 函数使用
1
cv2.reduce(src, dim, reduceOp=cv2.REDUCE_SUM) --> vec

简化是指使用一些reduceOp所代表的组合规则,对输入矩阵src的每一行(或列)进行系统的转化,直到只剩一行(或列)为止,使之成为向量vec。参数dim决定如何进行简化。

  • 参数说明

src

接受参数为 float 类型的一维、二维数据

reduceOp

参数 含义
cv2.REDUCE SUM 计算向量的总和
cv2.REDUCE AVG 计算向量的平均值
cv2.REDUCE MAX 计算向量中的最大值
cv2.REDUCE MIN 计算向量中的最小值
dim
参数 含义
0 合并为1行
1 合并为1列
  • 示例代码
1
2
3
4
5
6
7
data = np.reshape(np.arange(25, dtype='float32'), [5, 5])
res = cv2.reduce(data, 0, rtype=cv2.REDUCE_SUM)


-->
res
array([[50., 55., 60., 65., 70.]], dtype=float32)

8. cv2.repeat()

将一个矩阵的内容复制到另一个矩阵

  • 函数使用
1
cv2.repeat(src, nx, ny)

将src 数据 x 方向重复 nx 次, y 方向重复 ny 次

  • 示例代码
1
2
3
4
5
6
7
8
9
data = np.reshape(np.arange(4, dtype='float32'), [2, 2])
res = cv2.repeat(data, 2, 3)

-->
res
array([[0., 1., 0., 1., 0., 1.],
[2., 3., 2., 3., 2., 3.],
[0., 1., 0., 1., 0., 1.],
[2., 3., 2., 3., 2., 3.]], dtype=float32)

9. cv2.setIdentity()

将矩阵中对角线上的元素设为1,其他置0

1
2
3
4
5
6
7
8
9
10
mtx = np.random.random([5,6])
res = cv2.setIdentity(mtx)

-->
res
array([[1., 0., 0., 0., 0., 0.],
[0., 1., 0., 0., 0., 0.],
[0., 0., 1., 0., 0., 0.],
[0., 0., 0., 1., 0., 0.],
[0., 0., 0., 0., 1., 0.]])

10. cv2.solve()

求出线性方程组的解

  • 函数用法
1
cv2.solve(src1, src2, flags) 
$$ C=\operatorname{argmin}_{X}\|\quad A \cdot X-B\| $$
  • 其中 src1 为 $A$, src2 为 $B$
  • flags
取值 含义
cv2.DECOMP_LU 高斯消元法(LU分解)
cv2.DECOMP_SVD 奇异值分解(SVD)
cv2.DECOMP_CHOLESKY 对于对称正定矩阵
cv2.DECOMP_EIG 特征值分解,只用于对称矩阵
cv2.DECOMP_OR QR因式分解
cv2.DECOMP_NORMAL 可选附加标志;表示要求解标准方程

表中的前五个参数是互斥的,但最后一个参数cv2.DECOMP_NORMAL可以与前五个中的任何一个组合(例如,通过逻辑OR)。如果使用该参数,那么cv2.solve() 将尝试解决标准方程:$hsT·Ihs·dst=lhsT·rhs$, 而不是一般方程$Ihs·dst=rhs$。

  • 示例代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
A = np.array([[1,2], [2,1]], dtype='float32')
B = np.array([[0], [1]], dtype='float32')
res = cv2.solve(A, B)

-->
res
(True, array([[ 0.6666667 ]...e=float32))
special variables
function variables
0:True
1:array([[ 0.6666667 ],
[-0.33333334]], dtype=float32)
special variables
[0:2] :[array([0.6666667], d...e=float32), array([-0.33333334],...e=float32)]
dtype:dtype('float32')

解方程成功, $x = \frac {2}{3}, y=-\frac{1}{3}$

11. cv2.solveCubic()

找到三次方程的实根

  • 函数用法
1
cv2.solveCubic(coeffs)

给定由三或四个元素向量系数表示的三次多项式,cv2.solveCubic()将计算该多项式的实根。如果coeffs有四个元素,则计算以下多项式的根:

$$ \operatorname{coeffs}_{0} x^{3}+\operatorname{coeffs}_{1} x^{2}+\operatorname{coeffs}_{2} x+\operatorname{coeffs}_{3}=0 $$

如果coeffs只有三个元素,则计算以下多项式的根:

$$ x^{3}+\operatorname{coeffs}_{0} x^{2}+\operatorname{coeffs}_{1} x+\operatorname{coeffs}_{2}=0 $$

返回结果将具有一个或三个元素,具体取决于多项式具有多少个实根。

  • 示例代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
coeffs = np.array([1,1,-12,0], dtype='float32')
res = cv2.solveCubic(coeffs)


-->
res
(3, array([[-4.0000000e+...e=float32))
special variables
function variables
0:3
1:array([[-4.0000000e+00],
[ 3.0000000e+00],
[ 8.3266727e-16]], dtype=float32)
special variables
[0:3] :[array([-4.], dtype=float32), array([3.], dtype=float32), array([8.3266727e-16...e=float32)]
special variables
function variables

得到 $x3+x2-12x=0$ 的三个解 ${-4, 3, 0}$

12. cv2.solvePoly()

找到多项式方程的复根

  • 函数使用
1
cv2.solvePoly(coeffs)

给定以系数向量表示的任意阶数的多项式,cv2.solvePoly()将尝试计算该多项式的根。给定系数矩阵,计算以下多项式的根:

$$ \operatorname{coeffs}_{n} x^{n}+\operatorname{coeffs}_{n-1} x^{n-1}+\cdots+\operatorname{coeffs}_{1} x+\operatorname{coeffs}_{0}=0 $$
  • 示例代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
coeffs = np.array([4, 0, 1], dtype='float32')
res = cv2.solvePoly(coeffs)


-->
res
(0.0, array([[[ 0., -2.]],...e=float32))
special variables
function variables
0:0.0
1:array([[[ 0., -2.]],

[[ 0., 2.]]], dtype=float32)
special variables
[0:2] :[array([[ 0., -2.]], ...e=float32), array([[0., 2.]], dt...e=float32)]
special variables

解得 $x^2+4=0$ 方程的解为虚数 $2j,-2j$

13. cv2.sort()

在矩阵中排序任意行或列的元素

  • 函数使用
1
cv2.sort(src, flags)

可以通过使用cv2.SORT_EVERY_ROWcv2.SORT_EVERY_COLUMN 标志对每一行或每一列进行排序。排序可以是升序或者降序,分别由cv2.SORT_ASCENDINGcv2.SORT_DESCENDING标志指定。需要从每一组中各选一个标志。

  • 示例代码
1
2
3
4
5
6
7
8
9
10
11
data = cv2.randShuffle(np.reshape(np.arange(36), [6,6]))
res = cv2.sort(data, flags=cv2.SORT_EVERY_ROW)

-->
res
array([[ 1, 4, 8, 12, 30, 35],
[ 0, 5, 10, 11, 15, 22],
[ 3, 7, 16, 20, 25, 29],
[19, 21, 23, 24, 31, 34],
[ 9, 14, 18, 28, 32, 33],
[ 2, 6, 13, 17, 26, 27]], dtype=int32)

14. cv2.sortIdx()

cv2.sort() 的目的相同,除了矩阵是未修改的,并返回索引

1
2
3
4
5
6
7
8
9
10
11
12
data = cv2.randShuffle(np.reshape(np.arange(36), [6,6]))
res = cv2.sortIdx(data, flags=cv2.SORT_EVERY_ROW)


-->
res
array([[0, 1, 3, 2, 5, 4],
[3, 2, 4, 5, 1, 0],
[0, 2, 4, 5, 3, 1],
[1, 5, 3, 2, 0, 4],
[4, 1, 3, 0, 2, 5],
[1, 2, 0, 5, 4, 3]], dtype=int32)

15. cv2.split()

将一个多通道矩阵分割成多个单通道矩阵

image = mt.cv_rgb_imread('img1.jpg')
res = cv2.split(image)
PIS(image, *res)

16. cv2.sqrt()

计算矩阵逐元素的平方根

1
2
3
4
5
6
7
8
9
data = cv2.randShuffle(np.reshape(np.arange(16, dtype='float32'), [4, 4]))
res = cv2.sqrt(data)

-->
res
array([[3.3166249, 3. , 2.6457512, 1.4142135],
[2.4494898, 3.6055512, 2. , 1.7320508],
[3.4641016, 1. , 0. , 3.1622777],
[2.828427 , 3.7416575, 2.236068 , 3.8729835]], dtype=float32)

17. cv2.subtract()

实现两个矩阵逐元素相减

1
2
3
4
5
6
7
8
9
10
11
mat_1 = np.ones([3,3])
mat_2 = np.zeros([3,3])
cv2.setIdentity(mat_2)
res = cv2.subtract(mat_1, mat_2)


-->
res
array([[0., 1., 1.],
[1., 0., 1.],
[1., 1., 0.]])

18. cv2.trace()

计算一个矩阵的迹

1
2
3
4
5
6
mat_1 = np.ones([3,4], dtype='float32')
res = cv2.trace(mat_1)

-->
res
(3.0, 0.0, 0.0, 0.0)

19. cv2.transform()

在矩阵的每个元素上应用矩阵变换

  • 函数使用
1
cv2.transform(src, mtx)

函数cv2.transform()可用于计算任意线性图像变换。它将多通道输入矩阵src视为向量的集合,你可以将其视为“通道空间”,然后将这些向量乘以“小”矩阵mt×,以实现此通道空间中的转换。

$$ d s t _ { c , i ,j} = \sum m t x _ {c,c'} s r c _ { c ',i,j} $$
  • 示例代码
1
2
3
4
image = mt.cv_rgb_imread('img1.jpg')
mtx = cv2.flip(cv2.setIdentity(np.zeros([3, 3], dtype='float32')), flipCode=0)
gbr = cv2.transform(image, mtx)
PIS(image, gbr)

20. cv2.transpose()

矩阵的转置运算

1
2
3
4
5
6
7
8
9
mat = np.reshape(np.arange(16, dtype='float32'), [4, 4])
res = cv2.transpose(mat)

-->
res
array([[ 0., 4., 8., 12.],
[ 1., 5., 9., 13.],
[ 2., 6., 10., 14.],
[ 3., 7., 11., 15.]], dtype=float32)

示例源码

参考资料

  • 《学习 OpenCV3》 第五章

OpenCV - 矩阵操作 Part 3
https://www.zywvvd.com/notes/study/image-processing/opencv/opencv-matrix-op/opencv-matrix-op-part3/
作者
Yiwei Zhang
发布于
2022年3月6日
许可协议