opencv中矩阵计算的一些函数

您所在的位置:网站首页 mat怎么计算 opencv中矩阵计算的一些函数

opencv中矩阵计算的一些函数

2023-09-15 21:17| 来源: 网络整理| 查看: 265

转自:http://blog.sina.com.cn/s/blog_7908e1290101i97z.html

综述:

OpenCV有针对矩阵操作的C语言函数. 许多其他方法提供了更加方便的C++接口,其效率与OpenCV一样. OpenCV将向量作为1维矩阵处理. 矩阵按行存储,每行有4字节的校整. //由于opencv的矩阵式一位数组或者一位指针,所以我们只能利用opencv的函数对矩阵元素进行操作(当然这样也是最安全的做法,- -!太不习惯了) 分配矩阵空间: CvMat* cvCreateMat(int rows, int cols, int type);

type: 矩阵元素类型. 格式为CV_(S|U|F)C. 例如: CV_8UC1 表示8位无符号单通道矩阵, CV_32SC2表示32位有符号双通道矩阵. 例程: CvMat* M = cvCreateMat(4,4,CV_32FC1)//这个函数用来初始化Mat,不初始化虽然是会报warrying,但是运行时会报错,由于Mat和IplImage的类型不太一样,所以做两者之间转换的时候想改变数据类型很难(大概可以先转换矩阵类型,再转换数据类型,这就麻烦了,还没找到好方法),还需要注意这个分配空间并不管理数据的初始化,最好利用cvSet对数据进行初始化。

OpenCV - Operations on Arrays 对数组(矩阵)的一些操作 Function (函数名) Use (函数用处) Author : Ggicci  转载请注明出处! add 矩阵加法,A+B的更高级形式,支持mask scaleAdd 矩阵加法,一个带有缩放因子dst(I) = scale * src1(I) + src2(I) addWeighted 矩阵加法,两个带有缩放因子dst(I) = saturate(src1(I) * alpha + src2(I) * beta + gamma) subtract 矩阵减法,A-B的更高级形式,支持mask multiply 矩阵逐元素乘法,同Mat::mul()函数,与A*B区别,支持mask gemm 一个广义的矩阵乘法操作 divide 矩阵逐元素除法,与A/B区别,支持mask abs 对每个元素求绝对值 absdiff 两个矩阵的差的绝对值 exp 求每个矩阵元素 src(I) 的自然数 e 的 src(I) 次幂 dst[I] = esrc(I) pow 求每个矩阵元素 src(I) 的 p 次幂 dst[I] = src(I)p log 求每个矩阵元素的自然数底 dst[I] = log|src(I)| (if src != 0) sqrt 求每个矩阵元素的平方根 min, max 求每个元素的最小值或最大值返回这个矩阵 dst(I) = min(src1(I), src2(I)), max同 minMaxLoc 定位矩阵中最小值、最大值的位置 compare 返回逐个元素比较结果的矩阵 bitwise_and, bitwise_not, bitwise_or, bitwise_xor 每个元素进行位运算,分别是和、非、或、异或 cvarrToMat 旧版数据CvMat,IplImage,CvMatND转换到新版数据Mat extractImageCOI 从旧版数据中提取指定的通道矩阵给新版数据Mat randu 以Uniform分布产生随机数填充矩阵,同 RNG::fill(mat, RNG::UNIFORM) randn 以Normal分布产生随机数填充矩阵,同 RNG::fill(mat, RNG::NORMAL) randShuffle 随机打乱一个一维向量的元素顺序 theRNG() 返回一个默认构造的RNG类的对象 theRNG()::fill(...) reduce 矩阵缩成向量 repeat 矩阵拷贝的时候指定按x/y方向重复 split 多通道矩阵分解成多个单通道矩阵 merge 多个单通道矩阵合成一个多通道矩阵 mixChannels 矩阵间通道拷贝,如Rgba[]到Rgb[]和Alpha[] sort, sortIdx 为矩阵的每行或每列元素排序 setIdentity 设置单元矩阵 completeSymm 矩阵上下三角拷贝 inRange 检查元素的取值范围是否在另两个矩阵的元素取值之间,返回验证矩阵 checkRange 检查矩阵的每个元素的取值是否在最小值与最大值之间,返回验证结果bool sum 求矩阵的元素和 mean 求均值 meanStdDev 均值和标准差 countNonZero 统计非零值个数 cartToPolar, polarToCart 笛卡尔坐标与极坐标之间的转换 flip 矩阵翻转 transpose 矩阵转置,比较 Mat::t() AT trace 矩阵的迹 determinant 行列式 |A|, det(A) eigen 矩阵的特征值和特征向量 invert 矩阵的逆或者伪逆,比较 Mat::inv() magnitude 向量长度计算 dst(I) = sqrt(x(I)2 + y(I)2) Mahalanobis Mahalanobis距离计算 phase 相位计算,即两个向量之间的夹角 norm 求范数,1-范数、2-范数、无穷范数 normalize 标准化 mulTransposed 矩阵和它自己的转置相乘 AT * A, dst = scale(src - delta)T(src - delta) convertScaleAbs 先缩放元素再取绝对值,最后转换格式为8bit型 calcCovarMatrix 计算协方差阵 solve 求解1个或多个线性系统或者求解最小平方问题(least-squares problem) solveCubic 求解三次方程的根 solvePoly 求解多项式的实根和重根 dct, idct 正、逆离散余弦变换,idct同dct(src, dst, flags | DCT_INVERSE) dft, idft 正、逆离散傅立叶变换, idft同dft(src, dst, flags | DTF_INVERSE) LUT 查表变换 getOptimalDFTSize 返回一个优化过的DFT大小 mulSpecturms 两个傅立叶频谱间逐元素的乘法 体验新版博客 释放矩阵空间: CvMat* M = cvCreateMat(4,4,CV_32FC1); cvReleaseMat(&M);//这个别忘了用就是了 复制矩阵: CvMat* M1 = cvCreateMat(4,4,CV_32FC1); CvMat* M2; M2=cvCloneMat(M1); 初始化矩阵: double a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };

CvMat Ma=cvMat(3, 4, CV_64FC1, a); 另一种方法:

CvMat Ma; cvInitMatHeader(&Ma, 3, 4, CV_64FC1, a); 初始化矩阵为单位阵: CvMat* M = cvCreateMat(4,4,CV_32FC1); cvSetIdentity(M); // 这里似乎有问题。 //这个函数可以初始化对角线上的元素,这个是单位阵,不是所有元素都赋1,这个函数需要第二个函数,虽然有默认值,但是这个变量和我之前的理解有点不对,也没有实验,贴个原型吧: void cvSetIdentity( CvArr* mat, CvScalar value=cvRealScalar(1) );这里的cvRealScalar(1)是个强制类型转换。 存取矩阵元素 假设需要存取一个2维浮点矩阵的第(i,j)个元素. 间接存取矩阵元素: cvmSet(M,i,j,2.0); // Set M(i,j) t = cvmGet(M,i,j); // Get M(i,j) 直接存取,假设使用4-字节校正: CvMat* M = cvCreateMat(4,4,CV_32FC1); int n = M->cols; float *data = M->data.fl; data[i*n+j] = 3.0; 直接存取,校正字节任意: CvMat* M = cvCreateMat(4,4,CV_32FC1); int step = M->step/sizeof(float); float *data = M->data.fl;//这个也是Mat和IplImage的区别,Mat的data是union类型,里面是五个不同类型的指针,根据你存储的类型选择相同类型的指针;而IplImage的imagedata就直接存储数据了。

(data+i*step)[j] = 3.0;

直接存取一个初始化的矩阵元素: double a[16]; CvMat Ma = cvMat(3, 4, CV_64FC1, a); a[i*4+j] = 2.0; // Ma(i,j)=2.0; 矩阵/向量操作 矩阵-矩阵操作: CvMat *Ma, *Mb, *Mc; cvAdd(Ma, Mb, Mc); // Ma+Mb -> Mc cvSub(Ma, Mb, Mc); // Ma-Mb -> Mc cvMatMul(Ma, Mb, Mc); // Ma*Mb -> Mc//从前几天看到的一些技巧,我感觉这个几个函数不是很好,没有返回值,不能嵌套调用,想完成三个矩阵的相乘,还需要临时变量,比如恢复SVD的时候。 按元素的矩阵操作: CvMat *Ma, *Mb, *Mc; cvMul(Ma, Mb, Mc); // Ma.*Mb -> Mc cvDiv(Ma, Mb, Mc); // Ma./Mb -> Mc cvAddS(Ma, cvScalar(-10.0), Mc); // Ma.-10 -> Mc 向量乘积: double va[] = {1, 2, 3}; double vb[] = {0, 0, 1}; double vc[3]; CvMat Va=cvMat(3, 1, CV_64FC1, va); CvMat Vb=cvMat(3, 1, CV_64FC1, vb); CvMat Vc=cvMat(3, 1, CV_64FC1, vc); double res=cvDotProduct(&Va,&Vb); // 点乘: Va . Vb -> res cvCrossProduct(&Va, &Vb, &Vc); // 向量积: Va x Vb -> Vc end{verbatim}

注意 Va, Vb, Vc 在向量积中向量元素个数须相同.

单矩阵操作: CvMat *Ma, *Mb; cvTranspose(Ma, Mb); // transpose(Ma) -> Mb (不能对自身进行转置) CvScalar t = cvTrace(Ma); // trace(Ma) -> t.val[0] double d = cvDet(Ma); // det(Ma) -> d cvInvert(Ma, Mb); // inv(Ma) -> Mb 非齐次线性系统求解: CvMat* A = cvCreateMat(3,3,CV_32FC1); CvMat* x = cvCreateMat(3,1,CV_32FC1); CvMat* b = cvCreateMat(3,1,CV_32FC1); cvSolve(&A, &b, &x); // solve (Ax=b) for x 特征值分析(针对对称矩阵): CvMat* A = cvCreateMat(3,3,CV_32FC1); CvMat* E = cvCreateMat(3,3,CV_32FC1); CvMat* l = cvCreateMat(3,1,CV_32FC1); cvEigenVV(&A, &E, &l); // l = A的特征值 (降序排列) // E = 对应的特征向量 (每行) 奇异值分解SVD: CvMat* A = cvCreateMat(3,3,CV_32FC1); CvMat* U = cvCreateMat(3,3,CV_32FC1); CvMat* D = cvCreateMat(3,3,CV_32FC1); CvMat* V = cvCreateMat(3,3,CV_32FC1); cvSVD(A, D, U, V, CV_SVD_U_T|CV_SVD_V_T); // A = U D V^T

标号使得 U 和 V 返回时被转置(若没有转置标号,则有问题不成功!!!).//这个函数解释比较少,首先这个函数不能接受IplImage类型的输入变量,其次必须是浮点型,原文中这个问题,我没有遇到,我使用时最后一个参数用的是默认值0。

//////////////////////////////////////////////////////////////////////////////////////////////////

     自己遇到的问题:

    1,首先是初始化的问题,opencv提供了初始化Mat和初始化MatHead两种方法,文档中介绍都不分配内存存储数据,但实际上cvCreateMat这个函数是分配空间的,类推IplImage也是这样。不初始化会在运行时报错。

    2,为了调用SVD函数,我要用到很多Mat类型的数据,而且要从IplImage转化为Mat,这里可以选择两个函数,一个是cvGetImage,一个是cvConvert。cvGetImage会将输入数据的文件头一并复制,不符合我的要求,我的输入是IPL_DEPTH_8U ,要转化的矩阵是CV_32FC1,第二个函数不会复制文件头。另外要注意,Mat类型中的type包含很多信息,不光有矩阵的数据类型,不要尝试在矩阵复制后,更改type达到上面的目的。更改type会导致release不成功。

    3,opencv不支持不同大小的矩阵相加,我又初始化一个载体大小的图像,将水印的奇异值矩阵复制过去,这是我程序为数不多的几次自己编写的程序块,注意更改单个矩阵值的函数是cvmSet和cvmGet。不要自己找啊。

    4,cvCreateMat函数并不会对数据进行初始化,最好继续用cvSet对数据进行初始化。

 

目标

     我们有多种方法可以获得从现实世界的数字图像:数码相机、扫描仪、计算机体层摄影或磁共振成像就是其中的几种。在每种情况下我们(人类)看到了什么是图像。但是,转换图像到我们的数字设备时我们的记录是图像的每个点的数值。

 

      例如在上图中你可以看到车的镜子只是一个包含所有强度值的像素点矩阵。现在,我们如何获取和存储像素值可能根据最适合我们的需要而变化,最终可能减少计算机世界内的所有图像数值矩阵和一些其他的信息的描述基质本身。OpenCV 是一个计算机视觉库,其主要的工作是处理和操作,进一步了解这些信息。因此,你需要学习和开始熟悉它的第一件事是理解OpenCV 是如何存储和处理图像。

Mat

      OpenCV 自 2001 年出现以来。在那些日子里库是围绕C接口构建的。在那些日子里,他们使用名为IplImage C 的结构在内存中存储图像。这是您将在大多数较旧的教程和教材中看到的那个。使用这个结构的问题是将 C 语言的所有负面效果都摆到了桌面上。最大的问题是手动管理。它是建立在用户来负责处理内存分配和解除分配的假设之上的。当程序规模较小时,这是没有问题的,一旦代码基开始变得越来越大它将会越来越挣扎着处理所有这一切而不是着眼于实际解决自己的开发目标。

      幸运的是 c + + 出现了,并引入了类的概念,使得为用户开辟另一条路成为可能:

      自动内存管理 (或多或少)。好消息是,c + +,如果完全兼容 C 所以进行更改时没有兼容性问题产生。因此, OpenCV其2.0 版本引入一个新的c + + 接口,通过利用这些优点将为你的工作提供新的方法。某种程度上,在其中您不需要拨弄内存管理让你的代码简洁 (写得更少,实现的更多)。C + + 接口的唯一主要缺点在于,目前许多嵌入式的开发系统支持仅 C.因此,除非您的目标是这一平台,否则就没有理由再使用旧的方法(除非你是个受虐狂程序员和喜欢自讨苦吃)。

      你需要知道的关于Mat的第一件事是你不再需要手动分配其大小并且当你不需要它的时候你不再需要手动释放它。虽然这样做仍然是可能的,大多数 OpenCV 函数将手动分配其输出数据。还有一个额外的好处是如果传递一个已存在Mat对象,它已经为矩阵分配所需的空间,这段空间将被重用。也就是说我们在任何时候只使用与我们执行任务时所必须多的内存一样多的内存。

       Mat本质上是由两个数据部分组成的类: (包含信息有矩阵的大小,用于存储的方法,矩阵存储的地址等) 的矩阵头和一个指针,指向包含了像素值的矩阵(可根据选择用于存储的方法采用任何维度存储数据)。矩阵头部的大小是恒定的。然而,矩阵本身的大小因图像的不同而不同,通常是较大的数量级。因此,当你在您的程序中传递图像并在有些时候创建图像副本您需要花费很大的代价生成图像矩阵本身,而不是图像的头部。OpenCV 是图像处理库,它包含大量的图像处理函数。若要解决的计算挑战,最终大部分时间你会使用库中的多个函数。由于这一原因图像传给库中的函数是一种常见的做法。我们不应忘记我们正在谈论往往是计算量相当大的图像处理算法。我们想要做的最后一件事是通过制作不必要的可能很大的图像的拷贝进一步降低您的程序的速度。

      为了解决这一问题 OpenCV 使用引用计数系统。其思想是Mat的每个对象具有其自己的头,但可能他们通过让他们矩阵指针指向同一地址的两个实例之间共享该矩阵。此外,拷贝运算符将只能复制矩阵头部,也还将复制指针到大型矩阵,但不是矩阵本身。

 

Mat A, C; //仅创建了头部 A = imread(argv[1], CV_LOAD_IMAGE_COLOR); //在此我们知道使用的方法(分配矩阵) Mat B(A); //使用拷贝构造函数 C = A; //赋值运算符 复制代码

      上文中的所有对象,以相同的单个数据矩阵的结束点。他们头不同,但是使用的其中任何一个对矩阵进行任何修改,也将影响所有其他的。在实践中的不同对象只是提供相同的底层数据不同的访问方法,然而,它们的头部是不同的。真正有趣的部分是您可以创建仅指向完整数据的一小部分的头。例如,要在图像中创建兴趣区域 ( ROI) 您只需创建一个新头设置新边界:

 

Mat D (A, Rect(10, 10, 100, 100) ); // 用矩形界定

Mat E = A(Range:all(), Range(1,3)); // 用行和列来界定

复制代码

现在,你可能会问是否矩阵的本身可以属于多个Mat对象在不再需要时负责清理数据。简短的回答是:最后一个使用它的对象。这对于使用引用计数的机制,每当有人复制Mat对象的头,矩阵的计数器被增加。每当一个头被清除,此计数器被下调。当该计数器变为零,矩阵也就被释放了。因为有时会仍然也要复制矩阵的本身,存在着 clone() 或 copyTo() 函数。

 

Mat F = A.clone();

Mat G;

A.copyTo(G);

复制代码

现在 modifyingForGwill 不会影响由 theMatheader 指出的矩阵。你要记得从所有的是:

           • 输出图像分配 OpenCV 功能是自动 (除非另行指定,否则)。

           • 用c + + OpenCV的接口就无需考虑内存释放。

           • 赋值运算符和复制构造函数 (构造函数)只复制头。

           • 使用clone () 或copyTo () 函数将复制的图像的基础矩阵。

存储方法

      这是关于你是如何存储的像素值。您可以选择的颜色空间和使用的数据类型。色彩空间是指我们如何结合为了代码指定的颜色的颜色分量。最简单的是灰色的规模。在这里我们所掌握的颜色是黑色和白色。组合的这些让我们能创造很多的灰度级。

     对于彩色的方法,我们有很多方法可供选择。不过,每一就是将他们拆解成三个或四个基本组成部分,这些部分就会组合给所有其他的方法。最受欢迎的这一个 RGB,主要是因为这也是我们的眼睛如何建立中我们的眼睛的颜色。其基准的颜色是红、 绿、 蓝。编写代码的一种颜色的透明度有时第四个元素: 添加 alpha (A)。但是,它们很多颜色系统每个具有自身的优势:

           • RGB 是最常见的是我们的眼睛使用类似的事情,我们显示系统还撰写使用这些颜色。

           · 单纯疱疹和合肥分解颜色到他们的色相、 饱和度和亮度值/组件,这是我们来描述颜色更自然的方式。您使用,例如可驳回的最后一个组件,使你不那么明智的输入图像的光照条件的算法。

           • YCrCb 使用流行的 JPEG 图像格式。

           • CIE L *b*a 是均匀颜色空间,它是非常方便的如果您需要测量给定的颜色,以另一种颜色的距离。

      现在,每个建筑构件都自己有效的域。这会导致使用的数据类型。我们如何存储组件的定义只是如何精细的控制,我们已于其域。最小的数据类型可能是 char 类型,这意味着一个字节或 8 位。这可能是有符号(值-127 到 + 127)或无符号(以便可以存储从 0 到 255 之间的值)。虽然这三个组件的情况下已经给 16 万可能的颜色来表示 (如 RGB 的情况下) 我们可能通过使用浮点数 (4 字节 = 32 位) 或double(8 字节 = 64 位) 数据类型的每个组件获得甚至更精细的控制。然而,请记住增加组件的大小也会增加在内存中的整张图片的大小。

显式创建Mat对象

      在Load, Modify and Save an Image 教程中,你已经可以看到如何使用readWriteImageVideo: 'imwrite() ' 函数将一个矩阵写到一个图像文件中。然而,出于调试目的显示的实际值就方便得多。您可以实现此通过Mat的



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3