OpenCV - 矩阵操作 Part 1

2022-08-09 14:12:35 浏览数 (1)

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

简介

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

序号

函数

描述

1

cv2.absdiff()

计算两个矩阵差值的绝对值

2

cv2.add()

实现两个矩阵逐元素相加

3

cv2.addWeighted()

实现两个矩阵逐元素加权求和(以为混合值)

4

cv2.bitwise_and()

计算两个矩阵逐元素按位与

5

cv2.bitwise_not()

按位非

6

cv2.bitwise_or()

计算两个矩阵逐元素按位或

7

cv2.bitwise_xor()

计算两个矩阵逐元素按位异或

8

cv2.calcCovarMatrix()

计算一组n维向量的协方差

9

cv2.cartToPolar()

计算二维向量的角度和幅度

10

cv2.checkRange()

检查矩阵的无效值

11

cv2.compare()

对两个矩阵中的所有元素应用所选择的比较运算符

12

cv2.completeSymm()

通过将一半元素复制到另一半来使矩阵对称

13

cv2.convertScaleAbs()

缩放矩阵,取绝对值,然后转换为8位无符号数

14

cv2.countNonZero()

计算矩阵中非零元素个数

15

cv2.cvtColor()

转换图像颜色空间

16

cv2.dct()

计算矩阵的离散余弦变换

17

cv2.determinant()

计算方阵的行列式

18

cv2.dft()

计算矩阵的离散傅里叶变换

19

cv2.divide()

实现两个矩阵逐元素相除

20

cv2.eigen()

计算方阵的特征值和特征向量

矩阵操作

0. 基础引用
  • 之后对上述函数进行示例演示
  • 所有代码默认引用如下包
代码语言:javascript复制
import cv2
import numpy as np
import mtutils as mt
from mtutils import PIS
  • 示例图片 img1.jpgimg2.jpg
1. cv2.absdiff()

计算两个矩阵差值的绝对值

代码语言:javascript复制
matrix_a = np.random.random([5,5])
matrix_b = np.random.random([5,5])

res = cv2.absdiff(matrix_a, matrix_b)
2. cv2.add()

实现两个矩阵逐元素相加

代码语言:javascript复制
matrix_a = np.random.random([5,5])
matrix_b = np.random.random([5,5])

res = cv2.add(matrix_a, matrix_b)
3. cv2.addWeighted()

实现两个矩阵逐元素加权求和(以为混合值)

  • 函数使用
代码语言:javascript复制
addWeighted(src1, alpha, src2, beta, gamma)

参数说明src1图像1alpha图像1 权重 (例如 0.5)src2图像2beta图像2 权重 (例如 0.5)gamma附加偏置

  • 函数实现功能 $dst = src1alpha src2beta gamma$
  • 使用示例
代码语言:javascript复制
image_1 = mt.cv_rgb_imread('img1.jpg')
image_1 = mt.image_resize(image_1, [300, 300])
image_2 = mt.cv_rgb_imread('img2.jpg')
image_2 = mt.image_resize(image_2, [300, 300])

res1 = cv2.addWeighted(image_1, 0.8, image_2, 0.3, 5)
res2 = cv2.addWeighted(image_1, 0.5, image_2, 0.5, 5)
PIS(image_1, image_2, res1, res2)
4. cv2.bitwise_and()

对应像素按位与

代码语言:javascript复制
image_1 = mt.cv_rgb_imread('img1.jpg')
image_2 = mt.cv_rgb_imread('img2.jpg')

image_1 = mt.image_resize(image_1, [300, 300])
image_2 = mt.image_resize(image_2, [300, 300])

res = cv2.bitwise_and(image_1, image_2)
PIS(res)
  • 相当于所有数据分别按位与后的结果
代码语言:javascript复制
(cv2.bitwise_and(image_1, image_2) == image_1 & image_2).all()

->
True
5. cv2.bitwise_not()

按位非

代码语言:javascript复制
image_1 = mt.cv_rgb_imread('img1.jpg')
image_2 = mt.cv_rgb_imread('img2.jpg')

image_1 = mt.image_resize(image_1, [300, 300])
image_2 = mt.image_resize(image_2, [300, 300])

res = cv2.bitwise_not(image_1)
PIS(res)
6. cv2.bitwise_or()

计算两个矩阵逐元素按位或

代码语言:javascript复制
image_1 = mt.cv_rgb_imread('img1.jpg')
image_2 = mt.cv_rgb_imread('img2.jpg')

image_1 = mt.image_resize(image_1, [300, 300])
image_2 = mt.image_resize(image_2, [300, 300])

res = cv2.bitwise_or(image_1, image_2)
PIS(res)
7. cv2.bitwise_xor()

计算两个矩阵逐元素按位异或

代码语言:javascript复制
image_1 = mt.cv_rgb_imread('img1.jpg')
image_2 = mt.cv_rgb_imread('img2.jpg')

image_1 = mt.image_resize(image_1, [300, 300])
image_2 = mt.image_resize(image_2, [300, 300])

res = cv2.bitwise_xor(image_1, image_2)
PIS(res)
8. cv2.calcCovarMatrix()

给定一些向量,假设这些向量表示的点是近似高斯分布的,cv2.calcCovarMatrix() 将计 算这些点的均值和协方差矩阵。

  • 函数使用
代码语言:javascript复制
cv2.calcCovarMatrix(samples, flags[, covar[, mean[, ctype]]]) → covar, mean
  • 官方文档
  • flags 定义

Flags

含义

CV_COVAR_SCRAMBLED

快速PCA“scrambled”协方差,转置位置不同的计算方式,与 CV_COVAR_NORMAL 互斥

CV_COVAR_NORMAL

计算均值和协方差,正常计算协方差,与 CV_COVAR_SCRAMBLED 互斥

CV_COVAR_USE_AVG

输入均值而不是计算均值(在均值已知情况下减少运算时间)

CV_COVAR_SCALE

重新缩放输出的协方差矩阵

CV_COVAR_ROWS

使用样本的行作为输入向量(如输入向量为 m * n 则需要指定)

CV_COVAR_COLS

使用样本的列作为输入向量(如输入向量为 m * n 则需要指定)

代码语言:javascript复制
vector = np.array([[1,2,3], [4,5,6], [7, 8, 9]]).astype('float32')
covar, mean = cv2.calcCovarMatrix(vector, None, flags=cv2.COVAR_NORMAL | cv2.COVAR_COLS )

-->
covar
array([[2., 2., 2.],
       [2., 2., 2.],
       [2., 2., 2.]])

mean
array([[2.],
       [5.],
       [8.]])
9. cv2.cartToPolar()

计算二维向量的角度和幅度,笛卡尔坐标转极坐标

  • 函数使用
代码语言:javascript复制
magnitude, angle = cv2.cartToPolar(x, y)
  • 输入维度相同的 X, Y 向量 (float32 或 float64),返回相同维度的坐标转换结果
代码语言:javascript复制
vector = np.array([[1,1,1],[1,1,1]]).astype('float32')
X =vector
Y = vector
mag, ang = cv2.cartToPolar(X, Y)

-->
mag
array([[1.4142135, 1.4142135, 1.4142135],
       [1.4142135, 1.4142135, 1.4142135]], dtype=float32)
ang
array([[0.7852316, 0.7852316, 0.7852316],
       [0.7852316, 0.7852316, 0.7852316]], dtype=float32)
10. cv2.checkRange()

函数 cv2.checkRange() 检查输入矩阵src的每个元素,并确定该元素是否在给定范围内。范围由minValmaxVal设置,但任何NaN或inf值也被认为超出范围。如果找到超出范围的值,除非将quiet设置为true,否则抛出异常。在这种情况下,如果所有值都在范 围内,返回值就为true;如果有任何值超出范围,返回值则为false。

代码语言:javascript复制
image_1 = mt.cv_rgb_imread('img1.jpg')
cv2.checkRange(image_1, False, 0, 255)
11. cv2.compare()

该函数在两个矩阵src1src2中的对应元素之间进行逐元素比较,并将结果放在图像dst中。cv2.compare() 将最后一个参数作为比较运算符。在每种情况下,结果dst的每个像素都是一个8位序列,匹配的像素被标记为255,不匹配的像素被设置为0。 通过 numpy 的矩阵运算也完全可以实现。

  • 函数使用
代码语言:javascript复制
cv2.compare(src1, src2, cmpop)
  • cmpop 参数说明

cmp_op

比较操作

cv2.CMP_EQ

src1i == src2i

cv2.CMP_GT

src1i > src2i

cv2.CMP_GE

src1i >= src2i

cv2.CMP_LT

src1i < src2i

cv2.CMP_LE

src1i <= src2i

cv2.CMP_NE

src1i != src2i

  • 代码示例
代码语言:javascript复制
vector_1 = np.random.random([5,5,5,5])
vector_2 = np.random.random([5,5,5,5])

res = cv2.compare(vector_1, vector_2, cmpop=cv2.CMP_GE)
    
-->
res
array([[[[  0,   0,   0, 255, 255],
         [  0,   0, 255, 255, 255],
         [  0, 255, 255, 255, 255],
         [255, 255,   0, 255,   0],
         [  0, 255,   0,   0, 255]],
         
         ...

res.shape
(5, 5, 5, 5)
12. cv2.completeSymm()

给定一个(二维)矩阵 mtx, cv2.completeSymm() 通过复制来使矩阵对称注1。具体来说,来自上三角形的所有元素都被复制到它们在矩阵下三角形对应的转置位置。tx的对角元素保持不变。如果标志 lowerToUpper 设置为true,则来自下三角形的元素将被复制到上三角形中。

代码语言:javascript复制
vector_1 = np.random.random([5,5])
res = cv2.completeSymm(vector_1, lowerToUpper=False)

-->
res
array([[0.2604316 , 0.57123429, 0.24625302, 0.51625787, 0.53749169],
       [0.57123429, 0.2294393 , 0.17753148, 0.29501751, 0.34551   ],
       [0.24625302, 0.17753148, 0.08954819, 0.3061089 , 0.57356678],
       [0.51625787, 0.29501751, 0.3061089 , 0.54457652, 0.61120996],
       [0.53749169, 0.34551   , 0.57356678, 0.61120996, 0.03919279]])
13. cv2.convertScaleAbs()

缩放矩阵,取绝对值,然后转换为8位无符号数 函数cv2.convertScaleAbs() 实际上融多种功能于一体。它将按顺序执行四个操作。第一个操作是通过因子alpha来重新调整源图像,第二个操作是通过(加)因子beta来偏移,第三个操作是计算上述所求和的绝对值,第四个操作是将该结果(饱和)映射到一个无符号字符型(8位)。

代码语言:javascript复制
cv2.convertScaleAbs(src, alpha=1.0, beta=0.0)  
d s t_{i}= saturate {u c h a r}left(left|alpha^{*} s r c{i} betaright|right)
代码语言:javascript复制
vector = np.random.random([100, 100]) * 200
res = cv2.convertScaleAbs(vector, alpha=1.0, beta=0.0)

-->
res
array([[ 22, 155,  35, ..., 123,  98, 187],
       [137, 191, 163, ...,  19,  65, 105],
       [176, 128, 137, ...,  56,  44,  85],
       ...,
       [130,  47, 113, ..., 165,  60, 174],
       [169, 172,  47, ...,  97, 107, 144],
       [ 66,  78,  86, ..., 154, 113,  82]], dtype=uint8)
14. cv2.countNonZero()

计算矩阵中非零元素个数

代码语言:javascript复制
vector = np.random.random([100, 100]) 
vector = np.clip(vector - 0.3, 0, 1)

num = cv2.countNonZero(vector)

-->
num
7007
15. cv2.cvtColor()

cv2.cvtColor() 函数用于将图像在保留相同数据类型的同时从一个颜色空间(通道数)转换到另一个颜色空间。

  • 函数使用
代码语言:javascript复制
dst = cv2.cvtColor(src, code, dstCn=0) 

输入矩阵src可以是8位矩阵,16位无符号矩阵或32位浮点矩阵。输出矩阵dst将具有与输入矩阵相同的尺寸和深度。要完成的转换操作由编码参数指定。最终参数dstCn是目标图像中所需的通道数。如果给出默认值0,则通道数由src中的通道数和转换编码确定。

  • 示例代码
16. cv2.dct()

计算矩阵的离散余弦变换

  • 函数使用 该函数根据flags参数的值执行离散余弦变换或离散余弦逆变换。源矩阵src必须是一维或二维的,并且尺寸应该是偶数(如果需要,可以填充矩阵)。结果矩阵dst将具有与src相同的类型和尺寸。参数flags是一个位域值,可以设置为cv2.DCT_INVERSEcv2.DCT_ROWS中的一个或两个。
代码语言:javascript复制
cv2.dct(src, flags) --> dst

  • 参数说明
    • src 需要为一维或二维的 float32 或 float64 数据
    • flags 不设置默认正向变换
    • flags 如果设置为cv2.DCT_INVERSE,则实现逆变换而不是前向变换。
    • flags 如果设置标志为cv2.DCT_ROWS,则将二维n×m的输入视为长度为m的n个不同的一维向量。在这种情况下,每个这样的向量将被独立地变换。
  • 最佳尺寸 cv2.dct() 的性能很大程度上取决于传递给它的矩阵的确切尺寸,这种关系(性能与尺寸的关系)并不是单调的。只有一些尺寸是比其他尺寸表现出的性能更好。建议在将矩阵传递给 cv2.dct() 时,首先在比当前矩阵大的尺寸中确定最佳尺寸,然后将矩阵扩展为该尺寸。OpenCV 为你提供了一个合适的例程来计算这个值,称为 cv2.getOptimalDFTSize()
  • 示例代码
代码语言:javascript复制
image = mt.cv_rgb_imread('img1.jpg')
image = mt.image_resize(image, [300, 300]).astype('float32')
image = mt.to_gray_image(image)
dct_res = cv2.dct(image)
inverse_img = cv2.dct(dct_res, flags=cv2.DCT_INVERSE)
PIS(image, (dct_res*150).astype('uint8'), inverse_img.astype('uint8'))

17. cv2.determinant()

计算方阵的行列式

代码语言:javascript复制
vector =(np.random.random([3, 3]) * 5).astype('int32').astype('float32')
res = cv2.determinant(vector)

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

18. cv2.dft()

计算矩阵的离散傅里叶变换

  • 函数使用 cv2.dft()函数实现离散傅里叶变换以及其逆变换(取决于flags参数)。源矩阵src必须是一维或二维的。结果矩阵dst将具有与src相同的类型和尺寸。 参数flags是一个位域值,可以设置为cv2.DFT_INVERSE,cv2.DFT_ROWS,cv2.DFT_SCALE,cv2.DFT_COMPLEX_OUTPUTcv2.DFT_REALOUTPUT中的一个或多个。
代码语言:javascript复制
cv2.dft(src, flags=0, nonzeroRows=0)

  • flags 说明
    • 如果设置为cv2.DFT_INVERSE,则完成逆变换。
    • 如果设置标志为cv2.DFT_ROWS,则二维n×m输入被视为长度为m的n个不同的一维向量,并且每个这样的向量将独立变换。
    • 标志cv2.DFT_SCALE通过将结果除以矩阵中的元素数来标准化结果,这通常用于DFT_INVERSE,因为它保证逆的逆将具有正确的标准化。
    • 标志cv2.DFT_COMPLEX_OUTPUT:和cv2.DFT_REAL_OUTPUT是有用的,因为当计算实数矩阵的傅里叶变换时,结果将有复共轭对称性。因此,即使结果是复数,结果矩阵的元素数量等于输入矩阵中的元素数量,而不是该数量的两倍。这样的压缩是cv2.dft()的默认行为。
    • 若要强制输出复数的形式,则需设置标志cv2.DFT_COMPLEX_OUTPUT。在逆变换的情况下,输入(通常)为复数,输出也为复数。然而,如果输入矩阵(对逆变换的情况)具有复共轭对称性(例如,如果它本身是实数矩阵的傅里叶变换的结果),那么逆变换将是一个实数矩阵。如果知道是这种情况,并且希望结果矩阵表示为一个实数矩阵(从而使用一半的内存量),则可以设置cv2.DFT_REAL_OUTPUT标志。
    • 请注意,如果设置cv2.DFT_REAL_OUTPUT标志,cv2.dft()不会检查输入矩阵是否具有必要的对称性,它只是假定具有对称性。
  • nonzeroRows cv2.dft()的最后一个参数是nonzeroRows,它默认为0,但如果设置它为任何非0值,将导致cv2.dft()认为只有输入矩阵的前nonzeroRows行是有意义的。如果cv2.DFT_INVERSE被设置,那么就认为只有输出矩阵的前nonzeroRows行是非零的。在使用cv2.dft()计算卷积的互相关时,这个标志特别方便。
  • 最佳尺寸 cv2.dft()的性能很大程度上取决于传递给它的矩阵的确切尺寸,这种关系(性能与尺寸的关系)并不是线性的。只有一些尺寸是比其他尺寸表现出的性能更好。建议在将矩阵传递给cv2.dft()时,首先在比当前矩阵大的尺寸中确定最佳尺寸,然后将矩阵扩展为该尺寸。OpenCV提供了一个合适的例程来计算这个值,称为cv2.getOptimalDFTSize()
  • 示例代码
代码语言:javascript复制
image = mt.cv_rgb_imread('img1.jpg')
image = mt.image_resize(image, [300, 300]).astype('float32')
image = mt.to_gray_image(image)

dft_res = cv2.dft(image)
inverse_img = cv2.dft(dft_res, flags=cv2.DFT_INVERSE)

PIS(image, dft_res, inverse_img)

19. cv2.divide()

实现两个矩阵逐元素相除

代码语言:javascript复制
mat_1 = np.random.random([5, 5, 5, 5])
mat_2 = np.random.random([5, 5, 5, 5])

res = cv2.divide(mat_1,mat_2) 

20. cv2.eigen()

计算方阵的特征值和特征向量

代码语言:javascript复制
cv2.eigen(mat, lowindex=-1, highindex=-1)
  • 给定一个对称矩阵mat,cv2.eigen()会计算出该矩阵的特征向量和特征值。矩阵必须为浮点类型之一。特征值矩阵以递减的顺序包含mat的特征值。如果要提供矩阵的特征向量,特征向量则以行的形式存储在矩阵中,并且与对应的特征值在特征值矩阵中的顺序相同。附加参数lowindexhighindex允许只计算一些特征值(两者必须一起使用)。例如,如果lowindex=0highindex=1,就只计算最大的两个特征向量。
  • 参考代码
代码语言:javascript复制
mat = np.random.random([5, 5])
res = cv2.eigen(mat)

-->
res
(True, array([[ 2.38338798]...9424513]]), array([[ 0.48055992,...815113 ]]))
special variables
function variables
0:True
1:array([[ 2.38338798],
       [ 0.95330573],
       [ 0.09642702],
       [-0.29716848],
       [-0.99424513]])
2:array([[ 0.48055992,  0.47769814,  0.35204413,  0.55726429,  0.32617187],
       [ 0.11930107, -0.17197101,  0.86940861, -0.32391572, -0.3088697 ],
       [-0.1228634 ,  0.55909817,  0.04237424, -0.67306158,  0.46637576],
       [-0.49973229, -0.42185973,  0.30025171,  0.21678729,  0.65966218],
       [ 0.70000117, -0.50167127, -0.16806823, -0.2907344 ,  0.3815113 ]])
len():3

示例源码

  • https://github.com/zywvvd/Python_Practise

参考资料

  • 《学习 OpenCV3》 第五章

0 人点赞