opencv如何把一个矩阵不同列分离开_OpenCV矩阵操作(二)

本文详细介绍了OpenCV中处理矩阵的各种操作,包括计算矩阵的行列式、点积、特征值与特征向量、翻转、矩阵乘法、选择子区域等。还讲解了cvDet、cvDiv、cvEigenVV、cvGetCol等函数的使用,以及如何利用这些函数进行矩阵的高效处理。
摘要由CSDN通过智能技术生成

OpenCV矩阵操作(二)

====================================================================

cvDet

double cvDet(const

CvArr* mat);

cvDet()用于计算一个方阵的行列式。这个数组可以是任何数据类型,但它必须是单通道的,如果是小的矩阵,则直接用标准公式计算。然而对于大型矩阵,这样就不是很有效,行列式的计算使用高斯消去法。值得指出的是,如果已知一个矩阵是对称正定的,也可以通过奇异值分解的策略来解决。欲了解更多信息,请参阅“cvSVD”一节。但这个策略是将U和V设置为NULL,然后矩阵W的乘积就是所求正定矩阵。

cvDiv

void

cvDiv(

const CvArr*

src1,

const CvArr*

src2,

CvArr*

dst,

double scale =

1

);

cvDiv是一个实现除法的简单函数;它用src2除以src1中对应元素,然后把最终的结果存到dst中。如果mask非空,那么dst中的任何与mask中0元素相对应的元素都不改变。如果对数组中所有元素求倒数,则可以设置src1为NULL,函数将假定src1是一个元素全为1的数组。

cvDotProduct

double

cvDotProduct(

const CvArr*

src1,

const CvArr*

src2

);

这个函数主要计算两个N维向量的点积[Lagrange1773]。与叉积函数相同,点积函数也不太关注向量是行或者是列的形式。src1和src2都应该是单通道的数组,并且数组的数据类型应该一致。

cvEigenVV

double

cvEigenVV(

CvArr*

mat,

CvArr*

evects,

CvArr*

evals,

double eps =

0

);

对对称矩阵mat,cvEigenVV()会计算出该矩阵的特征值和相应的特征向量。函数实现的是雅可比方法[Bronshtein97],对于小的矩阵是非常高效的,雅可比方法需要一个停止参数,它是最终矩阵中偏离对角线元素最大尺寸。可选参数eps用于设置这个值。在计算的过程中,所提供的矩阵mat的数据空间被用于计算,所以,它的值会在调用函数后改变。函数返回时,你会在evects中找到以行顺序保存的特征向量。对应的特征值被存储到evals中。特征向量的次序以对应特征值的重要性按降序排列。该cvEigenVV()函数要求所有三个矩阵具有浮点类型。正如cvDet()(前述),如果被讨论的向量是已知的对称和正定矩阵,那么最好使用SVD计算mat的特征值和特征向量。

cvFlip

void

cvFlip(

const CvArr*

src,

CvArr* dst =

NULL,

int flip_mode =

0

);

本函数是将图像绕着在X轴或Y轴或者绕着X轴或Y轴上同时旋转。当参数flip_mode被设置为0的时候,图像只会绕X轴旋转。flip_mode被设置为正值时(例如,+1),图像会围绕Y轴旋转,如果被设置成负值(例如,-1),图像会围绕X轴和Y轴旋转。Win32运行视频处理系统时,你会发现自己经常使用此功能来进行图像格式变换,也就是坐标原点在左上角和左下角的变换。

cvGEMM

double

cvGEMM(

const CvArr*

src1,

const CvArr*

src2,

double

alpha,

const CvArr*

src3,

double

beta,

CvArr*

dst,

int tABC =

0

);

广义矩阵乘法(generalized

matrix

multiplicatipm,GEMM)在OpenCV中是由cvGEMM()来实现的,可实现矩阵乘法、转置后相乘、比例缩放等。最常见的情况下,cvGEMM()计算如下:其中A,B和C分别是矩阵src1,src2和src3,α和β是数值系数,op()是附在矩阵上的可选转置。参数src3可以设置为空。在这种情况下,不会参与计算。转置将由可选参数tABC来控制,它的值可以是0或者(通过布尔OR操作)CV_GEMM_A_T、CV_GEMM_B_T和CV_GEMM_C_T的任何组合(每一个标志都有一个矩阵转换相对应)。过去的OpenCV包含cvMatMul()和cvMatMulAdd()方法,但是,它们很容易和cvMul()混淆,其实它们的功能是完全不一样的(即两个数组的元素与元素相乘)。这个函数以宏的形式继续存在,它们直接调用cvGEMM()。两者对应关系如表3-7所示。

表3-7:cvGEMM()一般用法的宏别名

cvMatMul(A,B,

D)

cvGEMM(A,B,1,NULL,0,D,0)

cvMatMulAdd(A,B,C,D)

cvGEMM(A,B,1,C,1,D,0)

只有大小符合约束的矩阵才能进行乘法运算,并且所有的数据类型都应该是浮点型。cvGEMM()函数支持双通道矩阵,在这种情况下,它将双通道视为一个复数的两个部分。

cvGetCol和cvGetCols

CvMat*

cvGetCol(

const CvArr*

arr,

CvMat*

submat,

int col

);

CvMat*

cvGetCols(

const CvArr*

arr,

CvMat*

submat,

int

start_col,

int

end_col

);

cvGetCol()函数被用作提取矩阵中的某一列,并把它以向量的形式返回(即只有一列的矩阵)。在这种情况下,矩阵指针submat将被修改为指向arr中的特定列,必须指出的是,该指针在修改过程中并未涉及内存的分配或数据的复制;submat的内容仅仅是作了简单修改以使它正确地指出arr中所选择的列。它支持所有数据类型。cvGetCols()函数的工作原理与cvGetCols完全一致,区别只在于前者将选择从start_col到end_col之间的所有列。这两个函数都返回一个与被调用的特定列或者多列(即,submat)相对应的头指针。

cvGetDiag

CvMat*

cvGetDiag(

const CvArr*

arr,

CvMat*submat,

int diag=

0

);

cvGetDiag

()类似于cvGetCol();它能从一个矩阵选择某一条对角线并将其作为向量返回。submat是一个矩阵类型的头指针。函数cvGetDiag()将填充该向量头指针中的各分量,以使用指向arr中的正确信息。注意,调用cvGetDiag()会修改输入的头指针,将数据指针指向arr对角线上的数据,实际上,并没有复制arr的数据。可选参数diag表明submat指向哪一条对角线的。如果diag被设置为默认值0,主对角线将被选中。如果diag大于0,则始于(diag,0)的对角线将被选中,如果diag小于0,则始于(0,-diag)的对角线将被选中。cvGetDiag()并不要求矩阵arr是方阵,但是数组submat长度必须与输入数组的尺寸相匹配。当该函数被调用时,最终的返回结果与输入的submat相同。

cvGetDims和cvGetDimSize

int

cvGetDims(

const CvArr*

arr,

int*

sizes=NULL

);

int

cvGetDimSize(

const CvArr*

arr,

int index

);

您一定还记得OpenCV中的矩阵维数可以远远大于2。函数cvGetDims()返回指定数组的维数并可返回每一个维数的大小。如果数组sizes非空,那么大小将被写入sizes。如果使用了参数sizes,它应该是一个指向n个整数的指针,这里的n指维数。如果无法事先获知维数,为了安全起见,可以把sizes大小指定为CV_MAX_DIM。函数cvGetDimSize()返回一个由index参数指定的某一维大小。如果这个数组是矩阵或者图像,那么cvGetDims()将一直返回为2。对于矩阵和图像,由cvGetDims()返回的sizes的次序将总是先是行数然后是列数。

cvGetRow和cvGetRows

CvMat*

cvGetRow(

const CvArr*

arr,

CvMat*

submat,

int row

);

CvMat*

cvGetRows(

const CvArr*

arr,

CvMat*submat,

int

start_row,

int

end_row

);

cvGetRow()获取矩阵中的一行让它作为向量(仅有一行的矩阵)返回。跟cvGetCol()类似,矩阵头指针submat将被修改为指向arr中的某个特定行,并且对该头指针的修改不涉及内存的分配和数据的复制;submat的内容仅是作为适当的修改以使它正确地指向arr中所选择的行。该指针所有数据类型。cvGetRows()函数的工作原理与cvGetRow()完全一致,区别只在于前者将选择从start_row到end_row之间的所有行。这两个函数都返回一个的头指针,指向特定行或者多个行。

cvGetSize

CvSize cvGetSize(

const CvArr* arr );

它与cvGetDims()密切相关,cvGetDims()返回一个数组的大小。主要的不同是cvGetSize()是专为矩阵和图像设计的,这两种对象的维数总是2。其尺寸可以以CvSize结构的形式返回,例如当创建一个新的大小相同的矩阵或图像时,使用此函数就很方便。

cvGetSubRect

cvGetSubRect

CvSize

cvGetSubRect(

const CvArr*

arr,

CvArr*

submat,

CvRect

rect

);

cvGetSubRect()与cvGetColumns()或cvGetRows()非常类似,区别在于cvGetSubRect()通过参数rect在数组中选择一个任意的子矩阵。与其他选择数组子区域的函数的函数一样,submat仅仅是一个被cvGetSubRect()函数填充的头,它将指向用户期望的子矩阵数据,这里并不涉及内存分配和数据的复制。

cvInRange和cvInRangeS

void

cvInRange(const CvArr* src,

const CvArr*

lower,

const CvArr*

upper,

CvArr* dst

);

void

cvInRangeS(

const CvArr*

src,

CvScalar lower,

CvScalar upper,

CvArr* dst

);

这两个函数可用于检查图像中像素的灰度是否属于某一指定范围。cvInRange()检查,src的每一个像素点是否落在lower和upper范围中。如果src的值大于或者等于lower值,并且小于upper值,那么dst中对应的对应值将被设置为0xff;否则,dst的值将被设置为0。cvInRangeS()的原理与之完全相同,但src是与lower和upper中的一组常量值(类型CvScala)进行比较。对于这两个函数,图像src可以是任意类型;如果图像有多个通道,那么每一种通道都将被分别处理。注意,dst的尺寸和通道数必须与src一致,且必须为8位的图像。

cvInvert

double

cvInvert(

const CvArr*

src,

CvArr*

dst,

Int method =

CV_LU

);

cvInvert()求取保存在src中的矩阵的逆并把结果保存在dst中。这个函数支持使用多种方法来计算矩阵的逆(见表3-8),但默认采取的是高斯消去法。该函数的返回值与所选用的方法有关。

表3-8:cvInvert()函数中指定方法的参数值

方法的参数值

含义

CV_LU

高斯消去法 (LU

分解)

CV_SVD

奇异值分解(SVD)

CV_SVD_SYM

对称矩阵的SVD

就高斯消去法(method=CV_LU)来说,当函数执行完毕,src的行列式将被返回。如果行列式是0,那么事实上不进行求逆操作,并且数组dst将被设置为全0。

就CV_SVD或者CV_SVD_SYM,来说,返回值是矩阵的逆条件数(最小特征值跟最大特征值的比例)。如果src是奇异的,那么cvInvert()在SVD模式中将进行伪逆计算。

cvMahalonobis

CvSize

cvMahalonobis(

const CvArr*

vec1,

const CvArr*

vec2,

CvArr* mat

);

Mahalonobis距离(Mahal)被定义为一点和高斯分布中心之间的向量距离,该距离使用给定分布的协方差矩阵的逆作为归一化标准。参见图3-5。直观上,这是与基础统计学中的标准分数(Z-score)类似,某一点到分布中心的距离是以该分布的方差作为单位。马氏距离则是该思路在高维空间中的推广。

cvMahalonobis()计算的公式如下:

假设向量vec1对应x点,向量vec2是分布的均值。mat是协方差矩阵的逆。

实际上,这个协方差矩阵通常用cvCalcCovarMatrix()(前面所述)来进行计算,然后用cvInvert()来求逆。使用SV_SVD方法求逆是良好的程序设计习惯,因为其中一个特征值为0的分布这种情况在所难免!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值