本文最后更新于:2024年5月11日 下午

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.jpg 和 img2.jpg

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

1. cv2.phase()

计算二维向量的方向

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

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

  • 代码示例
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)。输入具有相同尺寸和类型的两个矩阵:幅度和角度,指定每个点处向量的幅度和角度。输出类似的两个矩阵,它们与输入具有相同的尺寸和类型,并且将包含每个点处向量的x和y投影。附加标志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_ROW或cv2.SORT_EVERY_COLUMN 标志对每一行或每一列进行排序。排序可以是升序或者降序,分别由cv2.SORT_ASCENDING或cv2.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》 第五章


文章链接:
https://www.zywvvd.com/notes/study/image-processing/opencv/opencv-matrix-op/opencv-matrix-op-part3/


“觉得不错的话,给点打赏吧 ୧(๑•̀⌄•́๑)૭”

微信二维码

微信支付

支付宝二维码

支付宝支付

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