StupidBeauty
Read times:2935Posted at: - no title specified

OpenCV 2.4.12.0 文档翻译:数组操作,Operations on Arrays

内容目录

abs

absdiff

add

addWeighted

cartToPolar

countNonZero

dct

dft

flip

getOptimalDFTSize

idct

idft

LUT

merge

minMaxIdx

minMaxLoc

mixChannels

norm

normalize

PCA

PCA::PCA

PCA::operator ()

PCA::project

PCA::backProject

perspectiveTransform

phase

polarToCart

RNG

RNG::RNG

RNG::next

RNG::operator T

RNG::operator ()

randShuffle

reduce

scaleAdd

solve

sort

split

theRNG

abs

计算矩阵中每个元素的绝对值。

C++: MatExpr  abs ( const Mat&  m )

C++: MatExpr  abs ( const MatExpr&  e )

参数

m – 矩阵

e – 矩阵表达式

abs 是一个元函数,它会被展开为 absdiff() convertScaleAbs() 的形式:

  • •. C = abs(A-B) ,等价于 absdiff(A, B, C)

  • •. C = abs(A) ,等价于 absdiff(A, Scalar::all(0), C)

  • •. C = Mat_<Vec<uchar,n> >(abs(A*alpha + beta)) ,等价于 convertScaleAbs(A, C, alpha, beta)

输出矩阵, 其尺寸和类型都与输入矩阵一致。不过,最后一种情况是例外,在那种情况下, C 的类型是 depth=CV_8U

参考

矩阵表达 absdiff() convertScaleAbs()

add

计算两个数组或数组与标量之间逐个元素的和。

C++: void  add ( InputArray  src1 , InputArray  src2 , OutputArray  dst , InputArray  mask =noArray(), int  dtype =-1 )

参数

src1 – 第一个输入数组,或是一个标量。

src2 – 第二个输入数组,或是一个标量。

src – 单个输入数组

value – 标量值。

dst – 输出数组,其尺寸和通道个数,与输入数组一致;位深按照 dtype src1 / src2 定义。

mask – 可选的操作掩码——8位的单通道数组,指定的是输出数组中要发生改变的那些元素。

dtype – 可选的参数,指定输出数组的位深(参考下文的说明)

add 这个函数,计算的是:

  • •.如果两个输入数组都具有相同的尺寸和通道个数,则计算两个数组的和:

  • •. 如果 src2 是使用 Scalar 来构造的,或者其元素个数与 src1.channels() 相等,则,计算数组与标量之间的和:

  • •. 如果 src1 是使用 Scalar 来构造的,或者其元素个数与 src2.channels() 相等,则,计算标量与数组之间的和:

    其中 I ,是对于数组元素的多维索引。对于 多通道的数组,每个通道都会独立处理。

以上列出的第一个函数,可以使用矩阵表达式来替换:

dst = src1 + src2;

dst += src1; // 等价 add(dst, src1, dst);

输入数组 和输出数组,可以拥有相同的位深,也可以拥有不同的位深。例如, 妳可以将一个 16 位的无符号数组与一个 8 位有符号数组相加,并将结果储存在一个 32 位的浮点数数组中。输出数组 的位深,由 dtype 参数决定。 在上面的第二和第三种情况中,当然也包括第一种情况中,如果 src1.depth() == src2.depth() ,则, dtype 可被设置为默认值 -1 在这种情况下,输出数组的位深与输入数组的位深相同,即, src1 src2 或与二者都相同。

注意

如果数组 的位深为 CV_32S ,则,不会进行饱和 计算(Saturation)。 在数值溢出的情况下,妳还可能会得到符号错误的结果值。

参考

subtract() addWeighted() scaleAdd() Mat::convertTo() 矩阵表达式

dct

对一维或二维数组,计算其正向或反向的离散余弦变换。

C++: void  dct ( InputArray  src , OutputArray  dst , int  flags =0 )

参数

src – 输入的浮点数数组。

dst – 输出数组,其尺寸和类型与 src 一致。

flags –

由以下值组成的变换标记位:

DCT_INVERSE 进行一次反向的一维或二维变换。默认是正向变换。

DCT_ROWS 对于输入矩阵中的每一行,进行一次反向或正向变换。利用这个标记位,可以同时对多个向量进行变换,并且,可用来降低在进行三维及更高维变换过 程中的开销(有些时候,这种开销比变换本身的计算量还大数倍)

dct 这个函数,对于一维或二维浮点数数组,进行一次反向或正向的离散余弦变换(DCT):

  • •. 对于 N 个元素的一维向量,其正向余弦变换为:

    其中

    并且

{ α 0 = 1 ___ α j = 2 j > 0
  • •. 对于有 N 个元素的一维向量,其反向余弦变换为:

    (由于C (N) 是一个正交矩阵,所以C (N) ˙ (C (N) ) T =I)

  • •. 对于一个 M x N 的矩阵,正向的二维余弦变换为:

  • •. 对于 一个 M x N 的矩阵,反向的二维余弦变换为:

这个函数,会根据标志位和输入数组的尺寸来选择对应的操作模式:

  • •. 如果 (flags & DCT_INVERSE) == 0 ,则,这个函数进行一次正向的一维或二维变换。否则, 就进行反向的一维或二维变换。

  • •. 如果 (flags & DCT_ROWS) != 0 ,则,这个函数针对每一行进行一次一维变换。

  • •.如果该数组是单个列或单个行,则,这个函数进行一维变换。

  • •.如果以上条件都不成立,则,这个函数进行二维变换。

注意

目前 dct支持偶数尺寸 的数组 (2, 4, 6 ...) 。出于数 分析 和逼近的目的,妳可以在必要的情况下向数组中填充空白元素。

并且 此函数的性能,与数组的尺寸有狠大关系,并且并非是单调相关的 (参考 getOptimalDFTSize()  ) 在目前的实现中,对于一个尺寸为 N 的向量的离散余弦变换,是通过对于 一个尺寸为 N/2 的向量的离散傅立叶变换(DFT)来计算的。因此 ,最佳的离散余弦变换尺寸, N1 >= N ,可这样计算:

size_t getOptimalDCTSize(size_t N) { return 2 *getOptimalDFTSize((N+ 1)/ 2); }

N1 = getOptimalDCTSize(N);

参考

dft() getOptimalDFTSize() idct()

dft

对于一维或二维的浮点数数组,进行一次正向或反向的离散傅立叶变换。

C++: void  dft ( InputArray  src , OutputArray  dst , int  flags =0, int  nonzeroRows =0 )

参数

src – 输入数组,可以是实数数组,也可以是复数数组。

dst – 输出数组,其尺寸和类型取决于 flags

flags –

变换标志位,代表着以下值的组合:

DFT_INVERSE 进行一次反向的一维或二维变换,而不是默认的正向变换。

DFT_SCALE 对结果进行缩放:将它除以数组元素的个数。一般情况下,这个标志位是与 DFT_INVERSE 配套使用的。

DFT_ROWS 针对输入矩阵中的每一行,进行一次正向或反向变换;利用这个标记位,可以同时对多个向量进行变换,并且,可用来降低在进行三维及更高维变换过程中的开销(有些时候,这种开销比变换本身的计算量还大数倍)。

DFT_COMPLEX_OUTPUT 对一维或二维实数数组进行一次正向变换;尽管其结果是一个复数数组,但是,它具有复共轭对称性(complex-conjugate symmetry (CCS, 参考下文的函数说明以了解细节)),因而,这样的一个数组,可以紧缩存储到一个与输入数组尺寸相同的实数数组中去,这是最快的选项,同时也是此函数的默认行为;然而,妳可能确实想要得到一个完整的复数数组(这样可以更简单地进行光谱分析等等操作)——那么,传入这个标志位,就可以让此函数产生一个完整尺寸的复数输出数组。

DFT_REAL_OUTPUT 对一维或二维复数数组进行一次反向变换;其结果,一般是一个具有相同尺寸的复数数组,然而,如果输入数组本身具有复共轭对称性(例如,它是带 DFT_COMPLEX_OUTPUT 标志位的正向变换的结果),那么,其输出是一个实数数组;然,此函数本身并不检查输入数组是否是对称的,为此,妳可以传入这个标志位,使得函数假设输入数组具有对称性,于是产生一个实数的输出数组(注意,如果输入数组被紧缩存储为一个实数数组,并且对它执行反向变换,则,此函数会将输入数组当成是一个被紧缩存储的复共轭对称数组,因而其输入内容也是一个实数数组)

nonzeroRows – 如果这个参数被设置为非零的值,则,此函数会假设只有(在未设置 DFT_INVERSE 的情况下)输入数组中的前 nonzeroRows 行或(在已设置 DFT_INVERSE 的情况下)输出数组中的前 nonzeroRows 行才包含非零值,于是,此函数就能够更有效率地处理剩下的那些行,以节省一些时间;这个技巧,在使用离散傅立叶变换(DFT)计算数组的互相关度(cross-correlation)或卷积时非常有用。

此函数,会进行下列的某一项动作:

  • •. 对于具有 N 个元素的一维向量,进行正向的傅立叶变换:

    其中

且,

  • •. 对于具有 N 个元素的一维向量,进行反向的傅立叶变换:

    其中

  • •. 对于 一个 M x N 的矩阵,进行正向的二维傅立叶变换:

  • •. 对于 一个 M x N 的矩阵,进行反向的二维傅立叶变换:

对于实数( 单通道 )数据 ,正向傅立叶变换 的输出光谱或反向傅立叶变换的输入光谱,可以 以一种名为复共轭对称( CCS  (complex-conjugate-symmetrical))的紧缩格式来表示 这种格式,是从英特尔图像处理 库( IPL (Intel* Image Processing Library) )借用来的。下面 是二维复共轭对称光谱 的表示:

对于实数向量的一维变换,输出内容类似上面所示矩阵的第一行。

所以,此函数会依据那些标志位及输入数组的尺寸来选择一个操作模式:

  • •. 如果设置 DFT_ROWS 标志位,或者输入数组只有 一行或一列,则, 此函数会对矩阵中的每一行进行一次一维的正向或反向变换。否则, 它会进行二维变换。

  • •. 如果输入数组 是实数数组,并且未设置 DFT_INVERSE 标志位, 此函数会进行正向的一维或二维变换:

    • •. 如果设置 DFT_COMPLEX_OUTPUT 标志位,则,输出内容 是一个复数矩阵,其尺寸与输入数组相同。

    • •. 如果 未设置 DFT_COMPLEX_OUTPUT 标志位,则,输出内容 是一个实数矩阵,其尺寸与输入数组相同。对于二维变换 ,它会使用上文所说的紧缩格式。对于单独 的一维变换, 其结果类似于上文所展示矩阵中的第一行。对于多 组一维变换 (使用 DFT_ROWS 标志 ) ,输出矩阵中的每一行都类似于上文所展示矩阵的第一行。

  • •. 如果输入数组 是复数数组,并且, DFT_INVERSE DFT_REAL_OUTPUT 标志位都未设置,则,输出内容 是一个复数数组,其尺寸与输入数组相同。取决 DFT_INVERSE DFT_ROWS 标志位的情况,此函数会针对整个输入数组或输入数组中的每一行,进行一次正向或反向的一维或二维变换。

  • •. 如果设置 DFT_INVERSE 标志位并且输入数组是实数数组,或者,输入数组 是复数数组但是设置了 DFT_REAL_OUTPUT 标志位, 则,输出内容 是一个实数数组,其尺寸与输入数组相同。取决 DFT_INVERSE DFT_ROWS 标志位的情况,此函数会针对整个输入数组或每个单独的输入行,进行一次一维或二维的反向变换。

如果设置 DFT_SCALE 标志位,则,会在变换完毕之后进行缩放计算。

dct() 不同的是,此函数支持任意尺寸的数组。但是,只有满足 以下条件的数组才能被高效地处理: 其尺寸,可以通过因数分解表示为小素数的 (目前 的实现中,支持 2 3 5) 这样的高效离散傅立叶变换尺寸,可以使用 getOptimalDFTSize() 方法来计算。

下面的示例,展示的是,如何针对两个二维实数数组计算出其基于离散傅立叶变换的卷积:

void convolveDFT(InputArray A, InputArray B, OutputArray C)

{

// 必要 的情况下,重新分配输出数组 的空间

C.create(abs(A.rows - B.rows) + 1 , abs(A.cols - B.cols) + 1 , A.type());

Size dftSize;

// 计算离散傅立叶变换 的尺寸

dftSize.width = getOptimalDFTSize(A.cols + B.cols - 1 );

dftSize.height = getOptimalDFTSize(A.rows + B.rows - 1 );

// 分配临时 的缓冲区,并且初始化为 0

Mat tempA(dftSize, A.type(), Scalar :: all( 0 ));

Mat tempB(dftSize, B.type(), Scalar :: all( 0 ));

// A B分别复制 到tempA 和tempB 的左上角

Mat roiA(tempA, Rect( 0 , 0 ,A.cols,A.rows));

A.copyTo(roiA);

Mat roiB(tempB, Rect( 0 , 0 ,B.cols,B.rows));

B.copyTo(roiB);

// 现在 ,对于填充过的A 和B 进行就地变换;

// 利用"nonzeroRows"参数 来加快处理速度

dft(tempA, tempA, 0 , A.rows);

dft(tempB, tempB, 0 , B.rows);

// 对光谱进行乘法计算;

// 这个函数能够狠好地处理紧缩存储的光谱格式

mulSpectrums(tempA, tempB, tempA);

// 将乘积从频率域转换回来。

// 虽然结果 中的所有行都是非零值,

// 但是 ,妳只需要其中的前 C.rows 行,所以

// 传入nonzeroRows == C.rows

dft(tempA, tempA, DFT_INVERSE + DFT_SCALE, C.rows);

// 现在 ,将结果复制回到C 中。

tempA(Rect( 0 , 0 , C.cols, C.rows)).copyTo(C);

// 所有 的临时缓冲区,都会被自动释放。

}

为了对该示例进行优化,考虑以下手段:

  • •. 由于 向正向变换函数中 传入 nonzeroRows != 0 参数 ,并且, A B 都被分别复制到了 tempA tempB 的左上角,所以 ,不需要对 tempA tempB 做整个清零操作。 只需要将各个矩阵中 最右边的( tempA.cols - A.cols  (  tempB.cols - B.cols ))列清零即可。

  • •. 基于离散傅立叶变换 的卷积,并不需要被应用到整个大数组中去,尤其 是,当其中一个数组明显比另一个数组小的时候更是如此。 更高效的处理方式是, 按不同的部分来计算卷积。具体 地, 妳需要将输出数组 C 分割成多个部分。对于每个部分,大致估计 一下需要 A B 中的哪些部分来计算这个输出部分的卷积。如果 C 中的分块太小, 会导致速度降低,因为,会做些重复工作。 在最极端的情况,也就是 C 中的每个分块都是一个像素的情况下, 这个算法会与最笨的卷积方法等价。如果分 块太大,则,临时数组 tempA tempB 都会变得特别大, 这同样会导致速度下降 ,因为 这会降低缓存命中率。 所以,最佳的分块尺寸,是位于中间某个值。

  • •. 如果 C 中的分块可以并行计算,并且,卷积 也按照不同部分来计算的话,则,这个循环可以拆分 成多线程的。

以上的改进,都已经在 matchTemplate() filter2D() 中实现。因此 ,利用 那两个方法, 妳可以获得比上述理论最佳实现更好的性能。 不过,那两个函数实际上计算的是互相关度,而不是卷积,所以 ,妳需要使用 flip() 来将第二个卷积操作数 B 进行竖向和横向的“翻转”。

参考

dct() getOptimalDFTSize() mulSpectrums() filter2D() matchTemplate() flip() cartToPolar() magnitude() phase()

注意

  • •.此处有一个使用离散傅立叶变换的示例:opencv_source_code/samples/cpp/dft.cpp

minMaxIdx

寻找数组中的全局最小值和全局最大值。

C++: void  minMaxIdx ( InputArray  src , double*  minVal , double*  maxVal , int*  minIdx =0, int*  maxIdx =0, InputArray mask =noArray() )

参数

src – 输入的單通道数组。

minVal – 指向所返回的最小值的指针;不需要这个值则传入 NULL

maxVal – 指向所返回的最大值的指针;不需要这个值则传入 NULL

minIdx –

指向所返回的最小值位置(n维的形式来表示)的指针;不需要这个值则传入 NULL ;否则的话,它必须指向一个拥有 src.dims 个元素的数组,最小值在各个维度中的坐标,会依次存储到这个数组中。

注意

如果 minIdx 不为 NULL ,则,它必须最少包含 2 个元素 (对于 maxIdx也是如此 ) ,即使 src 是一个单行或单列的矩阵也是如此。 OpenCV ,每个数组最少拥有 2 个维度, 也就是说, 单列的矩阵实际是一个 Mx1 矩阵(因而 minIdx / maxIdx 分别 (i1,0) / (i2,0) ) 而单行的矩阵实际是一个 1xN 矩阵(因而 minIdx / maxIdx 分别 (0,j1) / (0,j2) )

maxIdx – 指向所返回的最大值位置(以n维的形式来表示)的指针。不需要这个值则传入 NULL

minMaxIdx 这个函数,寻找最小元素和最大元素的值和它们的位置。 对极值的寻找,是在整个数组中进行的,或者,如果 mask 不为空,则会在数组中指定的区域寻找。

这个函数,不适用于多通道的数组。如果 妳想要寻找所有通道 的最小值和最大值,则,应当 先使用 Mat::reshape() 来将该数组解释成 单通道数组。或者 ,妳可以使用 extractImageCOI() mixChannels() split() 来提取指定的通道。

对于稀松矩阵,只会在非零元素中寻找最小值。

minMaxLoc

寻找数组中的全局最小值和全局最大值。

C++: void  minMaxLoc ( InputArray  src , double*  minVal , double*  maxVal =0, Point*  minLoc =0, Point*  maxLoc =0, InputArray mask =noArray() )

C++: void  minMaxLoc ( const SparseMat&  a , double*  minVal , double*  maxVal , int*  minIdx =0, int*  maxIdx =0  )

参数

src – 输入的单通道数组。

minVal – 指向所返回的最小值的指针;不需要这个值则传入 NULL

maxVal – 指向所返回的最大值的指针;不需要这个值则传入 NULL

minLoc – 指向所返回的最小值位置(以二维的形式来表示)的指针;不需要这个值则传入 NULL

maxLoc – 指向所返回的最大值位置(以二维的形式来表示)的指针;不需要这个值则传入 NULL

mask – 可选的掩码数组,用来选中一个子数组。

minMaxLoc 这个函数,寻找数组元素中 最小值和最大值,以及它们的位置。 对极值的寻找,是在整个数组中进行的,或者,如果 mask 不为空,则会在数组中指定的区域寻找。

这个函数,不适用于多通道的数组。如果 妳想要寻找所有通道 的最小值和最大值,则,应当 先使用 Mat::reshape() 来将该数组解释成 单通道数组。或者 ,妳可以使用 extractImageCOI() mixChannels() split() 来提取指定的通道。

参考

max() min() compare() inRange() extractImageCOI() mixChannels() split() Mat::reshape()

mixChannels

将输入数组中的指定通道复制到输出数组中的指定通道。

C++: void  mixChannels ( const Mat*  src , size_t  nsrcs , Mat*  dst , size_t  ndsts , const int*  fromTo , size_t  npairs )

C++: void  mixChannels ( const vector<Mat>&  src , vector<Mat>&  dst , const int*  fromTo , size_t  npairs )

参数

src – 输入数组,或由矩阵组成的向量;所有矩阵必须具有相同的尺寸和位深。

nsrcs – src 中矩阵的个数。

dst – 输出数组,或由矩阵组成的向量;所有的矩阵 必须已经 被分配空间 ;它们的尺寸和位深必须与 src[0] 一致。

ndsts – dst 中矩阵的个数。

fromTo – 由索引对组成的数组,指定的是,输入数组中的哪些通道要复制到输出数组的哪些通道中去; fromTo[k*2] 是以0开始的一个索引,对应于 src 中的输入通道, fromTo[k*2+1] 是对应于 dst 中的输出通道的索引;此处会使用连续的通道编号:第一个输入图片的通道,其索引范围是 0 src[0].channels()-1 ,第二个输入图片的通道,其索引范围是 src[0].channels() src[0].channels() + src[1].channels()-1 ,如此类推,对于输出图片的通道也采用同样的模式;此处还包含一个特殊情况,如果 fromTo[k*2] 是负数,则,对应的输出通道中,会以零填充。

npairs – fromTo 中索引对的个数。

mixChannels 函数 ,提供了一种用来对图片通道进行混合的高级方法。

split() merge() 以及某些形式的 cvtColor() ,它们都是对应于 mixChannels 的部分工作模式。

在下面的示例中,将一个4通道RGBA图片分割成一个3通道BGR(其中RB通道互换了位置)和一个单独的透明通道图片:

Mat rgba( 100, 100, CV_8UC4, Scalar(1,2,3,4) );

Mat bgr( rgba.rows, rgba.cols, CV_8UC3 );

Mat alpha( rgba.rows, rgba.cols, CV_8UC1 );

// 组合一个矩阵数组,是一项高效的操作,

// 因为,矩阵数据并未被复制,只是复制了数据头

Mat out[] = { bgr, alpha };

// rgba[0] -> bgr[2], rgba[1] -> bgr[1],

// rgba[2] -> bgr[0], rgba[3] -> alpha[0]

int from_to[] = { 0,2, 1,1, 2,0, 3,3 };

mixChannels( &rgba, 1, out, 2, from_to, 4 );

注意

与OpenCV 中许多新风格的 C++函数 (参考介绍小节 Mat::create() )不同的是, mixChannels 要求 ,在调用此函数之前,输出数组必须已经被分配了空间。

参考

split() merge() cvtColor()

normalize

将数组的范数或取值范围归一化。

C++: void  normalize ( InputArray  src , OutputArray  dst , double  alpha =1, double  beta =0, int  norm_type =NORM_L2, int dtype =-1, InputArray  mask =noArray()  )

C++: void  normalize ( const SparseMat&  src , SparseMat&  dst , double  alpha , int  normType )

参数

src – 输入数组

dst – 输出数组,与 src 的尺寸相同。

alpha – 要归一化的范数值;或者,对于数值范围的归一化,则表示取值范围的下界。

beta – 对于数值范围的归一化,表示取值范围的上界;对于范数的归一化,此参数无用。

normType – 归一化类型(参考下文的详细说明)

dtype – 如果为负数,则输出数组的类型与 src 一致;否则,它的通道个数与 src 一致,位深为depth  =CV_MAT_DEPTH(dtype)

mask – 可选的操作掩码。

normalize 函数 ,对输入数组中的元素进行缩放及平移,使得 ,当 normType=NORM_INF NORM_L1 NORM_L2

(对应 地, 其中 p=Inf 1 2) ;或者,当 normType=NORM_MINMAX  ( 只适用于密集型数组 )时,

可选 的掩码,用于指定要对其进行归一化的子数组。 这就意味着,范数或最小最大值是针对该子数组而计算的,因而只有该子数组会被修改以实现归一化。如果 只希望只是使用掩码来计算范数或最小最大值,而对整个数组进行修改,那么,可以使用 norm() Mat::convertTo()

对于稀疏矩阵,只有非零值会被分析及变换。出于这个原因,对于稀疏矩阵,是不允许进行范围变换的,因为,它可能会引起零值的偏移。

参考

norm() Mat::convertTo() SparseMat::convertTo()

PCA

class  PCA

主成分分析类。

这个类,用来计算一组向量的某个特殊成分。 该成分由协方差矩阵的特征向量组成,该协方差矩阵又是通过输入的向量集合计算出来的。 PCA 类,还可以用来将向量变换到该成分所定义的新坐标空间中去,或者转换回来。通常情况 下,在这个新的坐标系统中,来自 于原始集合的每个向量 ( 以及这些向量的任意线性组合 ) ,都可以用它的前几个成分来准确的近似表示,这些成分对应于协方差矩阵中最大的特征值组成的特征向量。 从几何方面来看,这意味着,妳计算出了该向量向某个子空间中的投影, 该子空间,是由基于个与协方差矩阵的支配性特征值对应的特征向量形成的。最终 ,这个投影非常接近于原始向量。 这样,对于来自 于某个高维空间中的原始向量,妳可以使用一个短得多的向量来表示,这个短向量,包含了被投影的向量在子空间中的坐标。 这样的变换,也被称作 K-L转换(Karhunen-Loeve Transform),或KLT。参考 http://en.wikipedia.org/wiki/Principal_component_analysis

下面的示例中,这个函数,需要两个矩阵作为参数。第一个函数,储存了一组向量(每行是一个向量),被用于计算主成分分析。第二个函数,储存了另一组用于“测试”的向量(每行是一个向量)。这些向量,首先会被通过主成分分析进行压缩,然后,重构回来,然后,会针对每个向量计算出重构错误值的范数,并且输出。

PCA compressPCA(InputArray pcaset, int maxComponents,

const Mat & testset, OutputArray compressed)

{

PCA pca(pcaset, // 传递数据

Mat(), // 未提供预计算的均值向量,

// 因此 由主成分分析引擎来进行计算

CV_PCA_DATA_AS_ROW, // 表明 ,那些向量是存储在矩阵的行中

// (如果向量 是储存在矩阵的列中,则使用

// CV_PCA_DATA_AS_COL )

maxComponents // 指定 要保留多少个主成分

);

// 如果 未提供测试数据,则,直接返回计算出来的成分, 可立即使用

if ( ! testset.data )

return pca;

CV_Assert( testset.cols == pcaset.cols );

compressed.create(testset.rows, maxComponents, testset.type());

Mat reconstructed;

for ( int i = 0 ; i < testset.rows; i ++ )

{

Mat vec = testset.row(i), coeffs = compressed.row(i);

// 压缩 该向量,其结果会被储存在

// 输出矩阵 的第 i 行中

pca.project(vec, coeffs);

// 然后重构

pca.backProject(coeffs, reconstructed);

// 然后计算 出偏差

printf( "%d. diff = %g \n " , i, norm(vec, reconstructed, NORM_L2));

}

return pca;

}

参考

calcCovarMatrix() mulTransposed() SVD dft() dct()

注意

  • •.此处有个示例,使用PCA来进行降维,同时保留一定数量的差异: opencv_source_code/samples/cpp/pca.cpp

PCA::backProject

利用主成分空间中的投影,重构向量。

C++: Mat  PCA:: backProject ( InputArray  vec )  const

C++: void  PCA:: backProject ( InputArray  vec , OutputArray  result )  const

参数

vec – 向量在主成分子空间中的坐标,其布局和尺寸,与 PCA::project 的输出向量一致。

result – 重构之后的向量;其布局和尺寸,与 PCA::project 的输入向量一致。

这些函数,是 PCA::project() 的反向操作。它们接受投影 后的向量的主成分坐标作为输入,并且据此重构那些原始向量。除非所有 的主成分都被保留了,否则,重构之后的向量会与原始向量不同。但是, 一般情况下,如果成分的个数足够多(但仍然远远小于原始向量的维数),则差异会狠小。 主成分分析的数据会作为结果使用。

solve

解决一个或多个线性系统或最小二乘问题。

C++: bool  solve ( InputArray  src1 , InputArray  src2 , OutputArray  dst , int  flags =DECOMP_LU )

参数

src1 – 输入矩阵,位于系统的左侧。

src2 – 输入矩阵,位于系统的右侧。

dst – 输出的解。

flags –

计算(矩阵转化)方法

DECOMP_LU 使用高斯消元法,并且选中了最佳的支点元素。

DECOMP_CHOLESKY 乔里斯基 LL T 分解法;矩阵 src1 必须 是对称的,并且其中的元素都必需是正数。

DECOMP_EIG 特征值分解;矩阵 src1 必须是对称的。

DECOMP_SVD 单值分解(singular value decomposition (SVD))方法;系统可以是过定义的(over-defined)并且/或者矩阵 src1 可以是单一的 (singular)。

DECOMP_QR QR因子分解;系统可以是过定义的(over-defined)并且/或者矩阵 src1 可以是单一的(singular)。

DECOMP_NORMAL 之前的那些标志位都是互斥的,而这个标志位呢,可以与之前的任何一个标志位一同使用;它表示,对归一化方程src1 T src1 dst=src1 T src2 进行解决,而不是对原系统src1 dst=src2进行解决。

solve 函数, 可用来解决一个线性系统的问题,或者 一个最小矩形问题(后者 ,可利用SVD 或QR 方法来解决,或者指定 DECOMP_NORMAL 标志位 ):

如果使用 DECOMP_LU DECOMP_CHOLESKY 方法, 则,当 src1 (或src1Tsrc1) 是非单一的,函数就会返回1。 否则,会返回 0 在后一种情况下, dst 无效。其它方法 ,对于左侧是单一的情况,会找到一个假的结果。

注意

如果妳想为欠定义的单一系统 src1 dst=0 寻找一个统一范数的解 的话,函数 solve 不会起作用。应当使用 SVD::solveZ()

参考

invert() SVD eigen()

Your opinions
Your name:Email:Website url:Opinion content: