赞
踩
OpenCV对矩阵操作提供了丰富的操作函数。本节将详细描述常用基本的矩阵和图像算子。
cv::abs:计算矩阵每个元素的绝对值。
float data[] = {-1,-2,-3,4,5,6,7,8,9};
cv::Mat m1(cv::Size(3,3),CV_32FC1,data);
cv::Mat m2 = cv::abs(m1);
std::cout << "m2 = " << m2 << std::endl;
cv::absdiff:计算两个数组之间或数组与标量之间的每个元素的绝对差。其原型为:
void cv::absdiff(InputArray src1,InputArray src2,OutputArray dst )
当两个数组的大小和类型相同时,它们之间的绝对差为: dst ( I ) = saturate ( ∣ src1 ( I ) − src2 ( I ) ∣ ) \texttt{dst}(I) = \texttt{saturate} (| \texttt{src1}(I) - \texttt{src2}(I)|) dst(I)=saturate(∣src1(I)−src2(I)∣)
当第二个数组是由Scalar构造或具有与其中的通道数一样多的元素时,数组与标量之间的绝对差: dst ( I ) = saturate ( ∣ src1 ( I ) − src2 ∣ ) \texttt{dst}(I) = \texttt{saturate} (| \texttt{src1}(I) - \texttt{src2} |) dst(I)=saturate(∣src1(I)−src2∣)
当第一个数组由Scalar构造或具有与src2中的通道数一样多的元素时,标量和数组之间的绝对差: dst ( I ) = saturate ( ∣ src1 − src2 ( I ) ∣ ) \texttt{dst}(I) = \texttt{saturate} (| \texttt{src1} - \texttt{src2}(I) |) dst(I)=saturate(∣src1−src2(I)∣)
cv::Mat m3(cv::Size(3,3),CV_32FC1,data2);
cv::Mat m4;
cv::absdiff(m1,m3,m4);
std::cout << "cv::absdiff(m1,m3,m4) = " << m4 << std::endl;
cv::Mat m5;
cv::absdiff(m1,0.3,m5);
std::cout << "cv::absdiff(m1,0.3,m5) = " << m5 << std::endl;
1)cv::add:计算两个数组或一个数组和一个标量的每个元素的总和。
void cv::add(InputArraysrc1,InputArray src2,OutputArray dst,InputArray mask = noArray(),int dtype = -1)
以下几种情况
其中,参数I是数组元素的多维索引。 在多通道阵列的情况下,每个通道都是独立处理的。输入阵列和输出阵列都可以具有相同或不同的深度。例如,可以将一个16位无符号数组添加到一个8位有符号数组中,并将和存储为32位浮点数组。 输出数组的深度由dtype参数确定。 在上面的第二种和第三种情况以及第一种情况下,当src1.depth()== src2.depth()时,dtype可以设置为默认值-1。 在这种情况下,输出数组将具有与输入数组相同的深度,无论是src1,src2还是两者。
// 创建矩阵 float data1[] = {1,2,3,4,5,6,7,8,9}; float data2[] = {1,3,5,7,9,11,13,15,17}; float maskdata[] = {1,1,1,0,0,0,1,1,1}; cv::Mat src1(3,3,CV_32FC1,data1); cv::Mat src2(3,3,CV_32FC1,data2); cv::Mat mask(3,3,CV_8UC1,maskdata); // 矩阵相加,与output = src1 + src2 结果相同 cv::Mat output; cv::add(src1,src2,output); cout << "src1 + src2 = " << output << endl; // 与常量相加 cv::add(src1,0.5,output); cout << "src1 + 0.5 = " << output << endl; // 带有marsk矩阵相加 cv::add(src1,src2,output,mask); cout << "src1 + src2 marsked = " << output << endl;
2)cv::addWeighted:计算两个数组的加权和。
**void cv::addWeighted(InputArray src1,double alpha,InputArray src2,double beta,double gamma,OutputArray dst,int dtype = -1) **
函数addWeighted计算两个数组的加权和,如下所示:
dst ( I ) = saturate ( src1 ( I ) ∗ alpha + src2 ( I ) ∗ beta + gamma ) \texttt{dst} (I)= \texttt{saturate} ( \texttt{src1} (I)* \texttt{alpha} + \texttt{src2} (I)* \texttt{beta} + \texttt{gamma} ) dst(I)=saturate(src1(I)∗alpha+src2(I)∗beta+gamma)
// 带权重相加
cv::addWeighted(src1,0.5,src2,0.5,0.75,output);
std::cout << "src1 * 0.5 + src2*0.5+ 0.75 = " << output << endl;
3)cv::scaleAdd:计算缩放数组和另一个数组的总和。
void cv::scaleAdd(InputArray src1,double alpha,InputArray src2,OutputArray dst)
函数scaleAdd是经典的原始线性代数运算之一,在BLAS中称为DAXPY或SAXPY。 它计算缩放数组和另一个数组的和: dst ( I ) = scale ⋅ src1 ( I ) + src2 ( I ) \texttt{dst} (I)= \texttt{scale} \cdot \texttt{src1} (I) + \texttt{src2} (I) dst(I)=scale⋅src1(I)+src2(I)
void cv::batchDistance(InputArray src1,InputArray src2,OutputArray dist,int dtype,OutputArray nidx,int normType = NORM_L2,int K = 0,InputArray mask = noArray(),int update = 0,bool crosscheck = false)
float data1[] = {0,0,1,
1,1,1,
0,0,1};
float data2[] = {1,1,0,
0,0,0,
1,1,0};
cv::Mat src1(3,3,CV_32FC1,data1);
cv::Mat src2(3,3,CV_32FC1,data2);
cv::Mat dst;
cv::Mat ndix;
cv::batchDistance(src1,src2,dst,CV_32FC1,ndix,cv::NORM_L2,2);
cout << "dst = " << dst << endl;
cout << "ndix = " << ndix << endl;
1)bitwise_and:计算两个数组或一个数组和一个标量的每个元素的按位与操作。
void cv::bitwise_and (InputArray src1,InputArray src2,OutputArray dst,InputArray mask = noArray())
对于浮点数组,其机器特定的位表示形式(通常符合IEEE754)用于操作。 在多通道阵列的情况下,每个通道都是独立处理的。 在上述第二种和第三种情况下,首先将标量转换为数组类型。
// 逻辑与操作
// 相同大小矩阵
cv::bitwise_and(src1,src2,dst);
cout << "src1 & src2 = " << dst << endl;
// 与常量运算
cv::bitwise_and(src1,0x0E,dst);
cout << "src1 & 0x0E = " << dst << endl;
2)bitwise_not:反转数组的每一位。
void cv::bitwise_not (InputArray src,OutputArray dst,InputArray mask = noArray())
dst ( I ) = ¬ src ( I ) \texttt{dst} (I) = \neg \texttt{src} (I) dst(I)=¬src(I)
对于浮点输入数组,其特定于机器的位表示形式(通常符合IEEE754)用于操作。 在多通道阵列的情况下,每个通道都是独立处理的。
// 逻辑非操作
cv::bitwise_not(src1,dst);
cout << "~src1 = " << dst << endl;
3)bitwise_or:计算两个数组或一个数组和一个标量的每个元素的按位或操作。
void cv::bitwise_or(InputArray src1,InputArray src2,OutputArray dst,InputArray mask = noArray())
对于浮点输入数组,其特定于机器的位表示形式(通常符合IEEE754)用于操作。 在多通道阵列的情况下,每个通道都是独立处理的。
// 逻辑或操作
cv::bitwise_or(src1,src2,dst);
cout << "src1 | src2 = " << dst << endl;
// 与常量运算
cv::bitwise_or(src1,0x02,dst);
cout << "src1 | 0x02 = " << dst << endl;
4)bitwise_xor:计算两个数组或一个数组和一个标量的每个元素的按位“异或”运算。
void cv::bitwise_xor(InputArray src1,InputArray src2,OutputArray dst,InputArray mask = noArray())
对于浮点输入数组,其特定于机器的位表示形式(通常符合IEEE754)用于操作。 在多通道阵列的情况下,每个通道都是独立处理的。
// 逻辑异或运算
cv::bitwise_xor(src1,src2,dst);
cout << "src1 ^ src2 = " << dst << endl;
// 与常量运算
cv::bitwise_xor(src1,0x0E,dst);
cout << "src1 ^ 0x0E = " << dst << endl;
计算一组向量的协方差矩阵。
void cv::calcCovarMatrix(const Mat * samples,int nsamples,Mat & covar,Mat & mean,int flags,int ctype = CV_64F)
flag的类型有:
// 创建矩阵 float data1[] = {1,1,127, 64,32,16, 1,1,2}; float data2[] = {127,64,0, 0,0,0, 16,8,0}; cv::Mat src1(3,3,CV_32FC1,data1); cv::Mat src2(3,3,CV_32FC1,data2); cv::Mat dst; cv::Mat mean; cv::Mat srcs[] = {src1,src2}; // 计算矩阵协方差 cv::calcCovarMatrix(srcs,2,dst,mean,cv::COVAR_SCALE|cv::COVAR_COLS); cout << "dst = " << dst << endl; cout << "mean = " << mean << endl;
**1)cv::cartToPolar:**计算2D向量的大小和角度(笛卡尔坐标转极坐标)。
void cv::cartToPolar (InputArray x,InputArray y,OutputArray magnitude,OutputArray angle,bool angleInDegrees = false)
magnitude ( I ) = x ( I ) 2 + y ( I ) 2 , angle ( I ) = atan2 ( y ( I ) , x ( I ) ) [ ⋅ 180 / π ] magnitude(I)=√x(I)2+y(I)2,angle(I)=atan2(y(I),x(I))[⋅180/π] magnitude(I)=x(I)2+y(I)2 ,angle(I)=atan2(y(I),x(I))[⋅180/π]
角度的计算精度约为0.3度。对于点(0,0),角度设置为0。
//建立容器存坐标 vector<cv::Point2f> sides; sides.push_back(cv::Point2f(3, 4)); sides.push_back(cv::Point2f(6, 8)); sides.push_back(cv::Point2f(1, 1)); cv::Mat xpts(sides.size(), 1, CV_32F, &sides[0].x, 2 * sizeof(float)); cv::Mat ypts(sides.size(), 1, CV_32F, &sides[0].y, 2 * sizeof(float)); cout << "x: " << xpts.t() << endl; cout << "y: " << ypts.t() << endl; cv::Mat magnitude, angle; cv::cartToPolar(xpts, ypts, magnitude, angle);//调用库函数 cout << "\nmagnitude: " << magnitude.t(); cout << "\nangle: " << angle.t() *180. / CV_PI <<endl;
2)cv::polarToCart:根据大小和角度计算2D向量的x和y坐标。
void cv::polarToCart(InputArray magnitude,InputArray angle,OutputArray y,bool angleInDegrees = false)
函数cv :: polarToCart计算每个2D矢量的笛卡尔坐标,这些矢量由大小和角度的相应元素表示:
x ( I ) = magnitude ( I ) cos ( angle ( I ) ) y ( I ) = magnitude ( I ) sin ( angle ( I ) ) x(I)=magnitude(I)cos(angle(I))y(I)=magnitude(I)sin(angle(I)) x(I)=magnitude(I)cos(angle(I))y(I)=magnitude(I)sin(angle(I))
估计坐标的相对精度约为1e-6。
检查输入数组的每个元素是否在有效的范围内。
bool cv::checkRange(InputArray a,bool quiet = true,Point * pos = 0,double minVal = -DBL_MAX,double maxVal = DBL_MAX)
函数cv :: checkRange检查每个数组元素既不是NaN也不是无限。 当minVal> -DBL_MAX且maxVal <DBL_MAX时,该函数还将检查每个值是否在minVal和maxVal之间。 在多通道阵列的情况下,每个通道都是独立处理的。 如果某些值超出范围,则第一个离群值的位置存储在pos中(当pos!= NULL时)。 然后,该函数将返回false(当quiet = true时)或引发异常。
float data1[] = {1,1,127,
64,32,16,
1,1,2};
cv::Mat src1(3,3,CV_32FC1,data1);
// 检查元素的范围是否在1~128之间
bool res = cv::checkRange(src1,true,0,1,128);
cout << "res = " << res << endl;
对两个数组或数组和标量值执行每个元素的比较。
void cv::compare (InputArray src1,InputArray src2,OutputArray dst,int cmpop)
如果比较结果为true,则将输出数组的相应元素设置为255。可以用等效的矩阵表达式替换比较操作:
Mat dst1 = src1 >= src2;
Mat dst2 = src1 < 8;
cmpop的类型如下:CMP_EQ 、CMP_GT 、CMP_GE 、CMP_LT 、CMP_LE 、CMP_NE
// 创建矩阵
float data1[] = {1,1,127,
64,32,16,
1,1,2};
float data2[] = {127,64,0,
0,0,0,
16,8,0};
cv::Mat src1(3,3,CV_32FC1,data1);
cv::Mat src2(3,3,CV_32FC1,data2);
cv::Mat dst;
// 矩阵比较
cv::compare(src1,src2,dst,cv::CMP_EQ);
cout << "dst = " << dst << endl;
将方矩阵的下半部或上半部复制到另一半。
void cv::completeSymm(InputOutputArray m,bool lowerToUpper = false)
函数cv :: completeSymm将方矩阵的下半部或上半部复制到另一半。 矩阵对角线保持不变:
// 创建矩阵
float data1[] = {1,1,127,
64,32,16,
1,1,2};
cv::Mat src1(3,3,CV_32FC1,data1);
cout << "src1 = \n" << format(src1, cv::Formatter::FMT_PYTHON) << endl;
// 复制到另一半
cv::completeSymm(src1);
cout << "dst = \n" << format(src1, cv::Formatter::FMT_PYTHON) << endl;
缩放,计算绝对值,然后将结果转换为8位类型。
void cv::convertScaleAbs(InputArray src,OutputArray dst,double alpha = 1,double beta = 0)
在输入数组的每个元素上,函数convertScaleAbs依次执行三个操作:缩放,获取绝对值,转换为无符号的8位类型:
dst ( I ) = saturate_cast<uchar> ( ∣ src ( I ) ∗ alpha + beta ∣ ) \texttt{dst} (I)= \texttt{saturate\_cast<uchar>} (| \texttt{src} (I)* \texttt{alpha} + \texttt{beta} |) dst(I)=saturate_cast<uchar>(∣src(I)∗alpha+beta∣)
如果是多通道阵列,该函数将独立处理每个通道。 当输出不是8位时,可以通过调用Mat :: convertTo方法(或使用矩阵表达式)然后通过计算结果的绝对值来模拟该操作。 例如:
Mat_<float> A(30,30);
randu(A, Scalar(-100), Scalar(100));
Mat_<float> B = A*5 + 3;
B = abs(B);
边缘填充。
void cv::copyMakeBorder(InputArray src,OutputArray dst,int top,int bottom,int left,int right,int borderType,const Scalar & value = Scalar())
该功能将源图像复制到目标图像的中间。 复制的源图像左侧,右侧,上方和下方的区域将被外推像素填充。 这不是基于此功能的过滤功能(它们会即时推断像素),而是其他更复杂的功能(包括您自己的功能)可以用来简化图像边界处理。
borderType有以下类型:
BORDER_CONSTANT、BORDER_REPLICATE、**BORDER_REFLECT **、BORDER_WRAP、**BORDER_REFLECT_101 **、**BORDER_TRANSPARENT **、**BORDER_REFLECT101 **、**BORDER_DEFAULT **、**BORDER_ISOLATED **
// 创建矩阵
cv::Mat src = cv::Mat::ones(15,15,CV_8UC1);
cout << "src = \n" << src << endl;
cv::Mat dst;
int top = (int) (0.1 * src.rows);
int bottom = top;
int left = (int) (0.1*src.cols);
int right = left;
// 边缘填充
copyMakeBorder(src,dst,top, bottom, left, right,cv::BORDER_CONSTANT);
cout << "dst = \n" << dst << endl;
计算非零数组元素。
int cv::countNonZero(InputArray src)
该函数返回src中非零元素的数量:
∑ I : src ( I ) ≠ 0 1 \sum _{I: \; \texttt{src} (I) \ne0 } 1 ∑I:src(I)=01
// 创建矩阵
float data[] = {127,64,0,
0,0,0,
16,8,0};
cv::Mat src(3,3,CV_32FC1,data);
// 计算非零元素
int counts = cv::countNonZero(src);
cout << "non-zeros counts = " << counts << endl;
1)cv::dct:对1D或2D数组执行正向或反向离散余弦变换。
void cv::dct(InputArray src,OutputArray dst,int flags = 0)
函数cv :: dct执行1D或2D浮点数组的正向或反向离散余弦变换(DCT):
N个元素的一维向量的正余弦变换:
Y = C ( N ) ⋅ X Y = C^{(N)} \cdot X Y=C(N)⋅X,其中, C j k ( N ) = α j / N cos ( π ( 2 k + 1 ) j 2 N ) C^{(N)}_{jk}= \sqrt{\alpha_j/N} \cos \left ( \frac{\pi(2k+1)j}{2N} \right ) Cjk(N)=αj/N cos(2Nπ(2k+1)j), α 0 = 1 \alpha_0=1 α0=1, α j = 2 \alpha_j=2 αj=2 for j > 0 j > 0 j>0
N个元素的一维向量的余弦逆变换:
X = ( C ( N ) ) − 1 ⋅ Y = ( C ( N ) ) T ⋅ Y X = \left (C^{(N)} \right )^{-1} \cdot Y = \left (C^{(N)} \right )^T \cdot Y X=(C(N))−1⋅Y=(C(N))T⋅Y
由于 C ( N ) C^{(N)} C(N)是正交矩阵, C ( N ) ⋅ ( C ( N ) ) T = I C^{(N)} \cdot \left(C^{(N)}\right)^T = I C(N)⋅(C(N))T=I
M x N矩阵的正向2D余弦变换: Y = C ( N ) ⋅ X ⋅ ( C ( N ) ) T Y = C^{(N)} \cdot X \cdot \left (C^{(N)} \right )^T Y=C(N)⋅X⋅(C(N))T
M x N矩阵的2D余弦逆变换: X = ( C ( N ) ) T ⋅ X ⋅ C ( N ) X = \left (C^{(N)} \right )^T \cdot X \cdot C^{(N)} X=(C(N))T⋅X⋅C(N)
该函数通过查看输入数组的flags和大小来选择操作模式:
当前dct支持偶数大小的数组(2、4、6 …)。 对于数据分析和近似,可以在必要时填充阵列。 而且,函数性能在很大程度上取决于数组大小,而不是单调(请参见getOptimalDFTSize)。 在当前实现中,经由大小为N / 2的向量的DFT来计算大小为N的向量的DCT。 因此,最佳DCT大小N1> = N可以计算为:
size_t getOptimalDCTSize(size_t N) { return 2*getOptimalDFTSize((N+1)/2); }
N1 = getOptimalDCTSize(N);
// 创建矩阵
cv::Mat src(256,256,CV_32FC1);
// 产生随机矩阵
cv::randu(src,0,255);
src.convertTo(src,CV_32FC1,1.0 / 255.0);
cv::Mat dst;
// 离散余弦变换
cv::dct(src,dst);
cv::imshow("src",src);
cv::imshow("dst",dst);
cv::waitKey();
2)cv::idct:对1D或2D数组执行离散余弦变逆换。
void cv::idct(InputArray src,OutputArray dst,int flags = 0)
计算浮点类型方阵的行列式
double cv::determinant(InputArray mtx)
函数cv :: determinant计算并返回指定矩阵的行列式。 对于小型矩阵(mtx.cols = mtx.rows <= 3),使用直接方法。 对于较大的矩阵,该函数将LU分解与部分旋转配合使用。
对于对称的正确定矩阵,也可以使用特征分解来计算行列式。
// 创建矩阵
float data[] = {1,2,3,4,5,6,7,8,9};
cv::Mat src(3,3,CV_32FC1,data);
// 计算行列式
double res = cv::determinant(src);
cout << "res = " << res << endl;
1)cv::dft:对1D或2D浮点数组执行正向或反向离散傅立叶变换。
void cv::dft(InputArray src,OutputArray dst,int flags = 0,int nonzeroRows = 0)
函数cv :: dft执行以下操作之一:
对N个元素的一维向量进行傅立叶变换:
Y = F ( N ) ⋅ X Y = F^{(N)} \cdot X Y=F(N)⋅X,其中, F j k ( N ) = exp ( − 2 π i j k / N ) F^{(N)}_{jk}=\exp(-2\pi i j k/N) Fjk(N)=exp(−2πijk/N), i = − 1 i=\sqrt{-1} i=−1
对N个元素的一维向量进行傅立叶逆变换:
X ′ = ( F ( N ) ) − 1 ⋅ Y = ( F ( N ) ) ∗ ⋅ y X = ( 1 / N ) ⋅ X , X′=(F(N))−1⋅Y=(F(N))∗⋅yX=(1/N)⋅X, X′=(F(N))−1⋅Y=(F(N))∗⋅yX=(1/N)⋅X,
其中, F ∗ = ( Re ( F ( N ) ) − Im ( F ( N ) ) ) T F^*=\left(\textrm{Re}(F^{(N)})-\textrm{Im}(F^{(N)})\right)^T F∗=(Re(F(N))−Im(F(N)))T
M x N矩阵的2D傅里叶变换: Y = F ( M ) ⋅ X ⋅ F ( N ) Y = F^{(M)} \cdot X \cdot F^{(N)} Y=F(M)⋅X⋅F(N)
反转M x N矩阵的2D傅立叶变换:
X ′ = ( F ( M ) ) ∗ ⋅ Y ⋅ ( F ( N ) ) ∗ X = 1 M ⋅ N ⋅ X ′ X′=(F(M))∗⋅Y⋅(F(N))∗X=1M⋅N⋅X′ X′=(F(M))∗⋅Y⋅(F(N))∗X=M⋅N1⋅X′
因此,该函数根据输入数组的flags和大小选择操作模式:
如果设置了DFT_SCALE,则缩放在转换后完成。
与dct不同,该函数支持任意大小的数组。 但是,只有那些数组才能得到有效处理,其大小可以乘以较小质数(在当前实现中为2、3和5)的乘积来分解。 可以使用getOptimalDFTSize方法计算这种有效的DFT大小。
// 获取最优大小 cv::Mat padded; int m = cv::getOptimalDFTSize(I.rows); int n = cv::getOptimalDFTSize(I.cols); // 边缘填充 cv::copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, cv::BORDER_CONSTANT,cv:: Scalar::all(0)); // 合并 cv::Mat planes[] = { cv::Mat_<float>(padded), cv::Mat::zeros(padded.size(), CV_32F) }; cv::Mat complexI; cv::merge(planes, 2, complexI); // 离散傅立叶变换 cv::dft(complexI, complexI); // 计算幅度并切换到对数尺度 // => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2)) cv::split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I)) cv::magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude cv::Mat magI = planes[0]; // 切换到对数尺度 magI += cv::Scalar::all(1); cv::log(magI, magI); // 重新排列傅立叶图像的象限,使原点位于图像中心 //int cx = magI.cols/2; //int cy = magI.rows/2; //cv::Mat q0(magI, cv::Rect(0, 0, cx, cy)); //cv::Mat q1(magI, cv::Rect(cx, 0, cx, cy)); //cv::Mat q2(magI, cv::Rect(0, cy, cx, cy)); //cv::Mat q3(magI, cv::Rect(cx, cy, cx, cy)); //cv::Mat tmp; //q0.copyTo(tmp); //q3.copyTo(q0); //tmp.copyTo(q3); //q1.copyTo(tmp); //q2.copyTo(q1); //tmp.copyTo(q2); // 规范化 cv::normalize(magI, magI, 0, 1, cv::NORM_MINMAX);
dft逆变换:
cv::dft(complexI, inverseTransform, cv::DFT_INVERSE|cv::DFT_REAL_OUTPUT);
2)cv::idft:计算一维或二维数组的离散傅立叶逆变换。
void cv::idft(InputArray src,OutputArray dst,int flags = 0,int nonzeroRows = 0)
1)cv::divide:对两个数组或按数组的标量执行按元素的除法。
void cv::divide(InputArray src1,InputArray src2,OutputArray dst,double scale = 1,int dtype = -1)
多通道阵列的不同通道是独立处理的。对于src2(I)为零的整数类型,dst(I)也将为零。
注意:对于浮点数据,对于零src2(I)值没有特殊定义的行为。 使用常规浮点除法。 期望浮点数据具有正确的IEEE-754行为(具有NaN,Inf结果值)。
当输出数组的深度为CV_32S时,不应用饱和度。 在溢出的情况下,您甚至可能会得到错误符号的结果。
// 创建矩阵
float data1[] = {1,2,3,4,5,6,7,8,9};
float data2[] = {1,3,5,7,9,11,13,15,17};
cv::Mat src1(3,3,CV_32FC1,data1);
cv::Mat src2(3,3,CV_32FC1,data2);
// 除法运算
// 矩阵之间除法运算
cv::Mat dst;
cv::divide(src1,src2,dst);
cout << "dst = " << dst << endl;
// 与标量除法运算
cv::divide(1,src2,dst);
cout << "dst = " << dst << endl;
2)cv::multiply:计算两个数组的按元素缩放的乘积。
void cv::multiply(InputArray src1,InputArray src2,OutputArray dst,double scale = 1,int dtype = -1)
函数乘法计算两个数组的每个元素的乘积: dst ( I ) = saturate ( scale ⋅ src1 ( I ) ⋅ src2 ( I ) ) \texttt{dst} (I)= \texttt{saturate} ( \texttt{scale} \cdot \texttt{src1} (I) \cdot \texttt{src2} (I)) dst(I)=saturate(scale⋅src1(I)⋅src2(I))
3)cv::mulTransposed:
计算矩阵的乘积及其转置。
void cv::mulTransposed(InputArray src,OutputArray dst,bool aTa,InputArray delta = noArray(),double scale = 1,int dtype = -1)
函数cv :: mulTransposed计算src及其转置的乘积:
除此以外。 该函数用于计算协方差矩阵。 增量为零时,当B = A’时,它可用作通用矩阵乘积A * B的更快替代品
1)cv::eigen:计算对称矩阵的特征值和特征向量。
bool cv::eigen(InputArray src,OutputArray eigenvalues,OutputArray eigenvectors = noArray())
函数cv :: eigen仅计算对称矩阵src的特征值或特征值和特征向量:
src*eigenvectors.row(i).t() = eigenvalues.at<srcType>(i)*eigenvectors.row(i).t()
// 创建矩阵
float data[] = {
1,2,3,
2,1,2,
3,2,1
};
cv::Mat src(3,3,CV_32FC1,data);
// 计算对称矩阵特征值
cv::Mat eigenValues,eigenVector;
cv::eigen(src,eigenValues,eigenVector);
cout << "eigen values = " << eigenValues << endl;
cout << "eigen vectors = " << eigenValues << endl;
2)cv::eigenNonSymmetric:计算非对称矩阵的特征值和特征向量(仅真实特征值)。
void cv::eigenNonSymmetric (InputArray src,OutputArray eigenvalues,OutputArray eigenvectors)
该函数计算方阵src的特征值和特征向量(可选):
src*eigenvectors.row(i).t() = eigenvalues.at<srcType>(i)*eigenvectors.row(i).t()
// 创建矩阵
float data2[] = {1,3,5,7,9,11,13,15,17};
cv::Mat src2(3,3,CV_32FC1,data2);
cv::eigenNonSymmetric(src,eigenValues,eigenVector);
cout << "eigen values = " << eigenValues << endl;
cout << "eigen vectors = " << eigenValues << endl;
1)cv::exp:计算每个数组元素的指数。
void cv::exp(InputArray src,OutputArray dst)
函数cv :: exp计算输入数组中每个元素的指数: dst [ I ] = e s r c ( I ) \texttt{dst} [I] = e^{ src(I) } dst[I]=esrc(I)
单精度输入的最大相对误差约为7e-6,双精度输入的最大相对误差小于1e-10。 当前,该函数将输出的非规格化值转换为零。 不处理特殊值(NaN,Inf)。
2)cv::pow:将每个数组元素提升为幂。
void cv::pow(InputArray src,double power,OutputArray dst)
函数cv :: pow将输入数组的每个元素提升为power:
dst ( I ) = { src ( I ) p o w e r i f ( power ) i s i n t e g e r ∣ src ( I ) ∣ p o w e r o t h e r w i s e \texttt{dst} (I) = {src(I)powerif(power)isinteger|src(I)|powerotherwise dst(I)={src(I)powerif(power)isinteger∣src(I)∣powerotherwise
3)cv::sqrt:计算数组元素的平方根。
void cv::sqrt(InputArray src,OutputArray dst)
函数cv :: sqrt计算每个输入数组元素的平方根。 在多通道阵列的情况下,每个通道都是独立处理的。 精度与内置std :: sqrt大致相同。
4)cv::subtract:计算两个数组或数组与标量之间的每个元素的差。
void cv::subtract(InputArray src1,InputArray src2,OutputArray dst,InputArray mask = noArray(),int dtype = -1)
函数减法计算:
其中,我是数组元素的多维索引。 在多通道阵列的情况下,每个通道都是独立处理的。
上面列表中的第一个函数可以替换为矩阵表达式:
dst = src1 - src2;
dst -= src1; // equivalent to subtract(dst, src1, dst);
输入阵列和输出阵列都可以具有相同或不同的深度。 例如,您可以减去8位无符号数组,并将差值存储在16位有符号数组中。 输出数组的深度由dtype参数确定。 在上面的第二种和第三种情况以及第一种情况下,当src1.depth()== src2.depth()时,dtype可以设置为默认值-1。 在这种情况下,输出数组将具有与输入数组相同的深度,无论是src1,src2还是两者。
5)cv::sum:计算数组元素的总和。
Scalar cv::sum(InputArray src)
函数cv :: sum针对每个通道独立计算并返回数组元素的总和。
1)cv::extractChannel:从src提取单个通道(coi是从0开始的索引)
void cv::extractChannel(InputArray src,OutputArray dst,int coi)
cv::Mat src = cv::imread("resources/images/f1.jpg");
cv::Mat blue;
cv::extractChannel(src,blue,0);
cv::imshow("src",src);
cv::imshow("blue",blue);
cv::waitKey();
2)cv::insertChannel:将单个通道插入目标矩阵或数组(coi是从0开始的索引)
void cv::insertChannel(InputArray src,OutputArray dst,int coi)
计算非零像素位置的列表。
void cv::findNonZero(InputArray src,OutputArray idx)
// 创建矩阵
float data[] = {127,64,0,
0,0,0,
16,8,0};
cv::Mat binaryImage(3,3,CV_32FC1,data);
// 非零元素位置
cv::Mat locations;
cv::findNonZero(binaryImage, locations);
// 访问位置
// cv::Point pnt = locations.at<cv::Point>(i);
cout << "locations = " << locations << endl;
1)cv::flip:围绕垂直轴,水平轴或两个轴翻转2D数组。
void cv::flip(InputArray src,OutputArray dst,int flipCode)
函数cv :: flip以三种不同的方式之一翻转数组(行和列索引均基于0):
dst i j = { src src.rows − i − 1 , j i f flipCode = 0 src i , src.cols − j − 1 i f flipCode > 0 src src.rows − i − 1 , src.cols − j − 1 i f flipCode < 0 \texttt{dst} _{ij} = \left\{ srcsrc.rows−i−1,jifflipCode=0srci,src.cols−j−1ifflipCode>0srcsrc.rows−i−1,src.cols−j−1ifflipCode<0 \right. dstij=⎩⎨⎧srcsrc.rows−i−1,jsrci,src.cols−j−1srcsrc.rows−i−1,src.cols−j−1ifflipCode=0ifflipCode>0ifflipCode<0
// 创建矩阵
float data[] = {127,64,0,
0,0,0,
16,8,0};
cv::Mat src(3,3,CV_32FC1,data);
// 翻转矩阵
cv::Mat dst;
cv::flip(src, dst,0);
// 访问位置
// cv::Point pnt = locations.at<cv::Point>(i);
cout << "locations = " << dst << endl;
2)cv::rotate:以90度的倍数旋转2D阵列
void cv::rotate(InputArray src,int rotateCode)
函数cv :: rotate以三种不同的方式之一旋转数组:顺时针旋转90度(rotateCode = ROTATE_90_CLOCKWISE)。 顺时针旋转180度(rotateCode = ROTATE_180)。 顺时针旋转270度(rotateCode = ROTATE_90_COUNTERCLOCKWISE)。
广义矩阵乘法。
void cv::gemm(InputArray src1,InputArray src2,double alpha,InputArray src3,double beta,OutputArray dst,int flags = 0)
函数cv :: gemm执行类似于BLAS 3级中的gemm函数的广义矩阵乘法。例如,gemm(src1,src2,alpha,src3,beta,dst,GEMM_1_T + GEMM_3_T对应于
dst = alpha ⋅ src1 T ⋅ src2 + beta ⋅ src3 T \texttt{dst} = \texttt{alpha} \cdot \texttt{src1} ^T \cdot \texttt{src2} + \texttt{beta} \cdot \texttt{src3} ^T dst=alpha⋅src1T⋅src2+beta⋅src3T
对于复杂(两通道)数据,请执行复杂矩阵乘法。
该函数可以替换为矩阵表达式。 例如,上述调用可以替换为:
dst = alpha*src1.t()*src2 + beta*src3.t();
cv::Mat T;
cv::Mat A=cv::Mat::eye(1,3,CV_32FC1);
cv::Mat C=cv::Mat::eye(3,3,CV_32FC1);
std::cout<<"A="<<A<<std::endl<<"C="<<C<<std::endl;
cv::gemm(A,C,1,10,0,T,0);//the src3 can't be 0,so if you
//want to ignore the src3,
//you should set the b eater as 0
std::cout<<"T="<<T;
返回给定向量大小的最佳DFT大小。
DFT性能不是矢量大小的单调函数。 因此,当您计算两个数组的卷积或对一个数组执行光谱分析时,通常有意义的是用零填充输入数据以获得更大的数组,该数组可以比原始数组快得多的速度转换。 大小为2的幂(2、4、8、16、32,…)的阵列处理速度最快。 但是,大小为2、3和5的乘积(例如300 = 5 * 5 * 3 * 2 * 2)的数组也可以得到非常有效的处理。
函数cv :: getOptimalDFTSize返回大于或等于vecsize的最小值N,以便可以有效处理大小为N的向量的DFT。 在当前实现中,对于一些整数p,q,r,N = 2 ^ p ^ * 3 ^ q ^ * 5 ^ r ^。
如果vecsize太大(非常接近INT_MAX),则该函数返回负数。
尽管该函数不能直接用于估计DCT变换的最佳矢量大小(由于当前的DCT实现仅支持偶数大小的矢量),但可以轻松地将其处理为getOptimalDFTSize((vecsize + 1)/ 2)* 2。
1)cv::hconcat:水平方向串联应用于给定矩阵。
void cv::hconcat(const Mat * src,size_t nsrc,OutputArray dst)
cv::Mat matArray[] = { cv::Mat(4, 1, CV_8UC1, cv::Scalar(1)),
cv::Mat(4, 1, CV_8UC1, cv::Scalar(2)),
cv::Mat(4, 1, CV_8UC1, cv::Scalar(3)),};
cv::Mat out;
cv::hconcat( matArray, 3, out );
2)cv::vconcat:垂直方向串联应用于给定矩阵。
void cv::vconcat(const Mat * src,size_t nsrc,OutputArray dst)
cv::Mat matArray[] = { cv::Mat(4, 1, CV_8UC1, cv::Scalar(1)),
cv::Mat(4, 1, CV_8UC1, cv::Scalar(2)),
cv::Mat(4, 1, CV_8UC1, cv::Scalar(3)),};
cv::Mat out;
cv::vconcat( matArray, 3, out );
检查数组元素是否位于其他两个数组的元素之间。
void cv::inRange(InputArray src,InputArray lowerb,InputArray upperb,OutputArray dst)
该函数检查范围如下:
也就是说,如果src(I)在指定的1D,2D,3D,…框内,则dst(I)设置为255(全1位),否则设置为0。
当下边界参数和/或上边界参数为标量时,应忽略上述公式中lowerb和upperb的索引(I)。
cv::Mat src = cv::imread("resources/images/f1.jpg",0);
cv::Mat dst;
cv::inRange(src,cv::Scalar(120, 120, 120), cv::Scalar(200, 200, 200),dst);
cv::imshow("src",src);
cv::imshow("dst",dst);
cv::waitKey();
查找矩阵的逆或伪逆。
double cv::invert(InputArray src,OutputArray dst,int flags = DECOMP_LU)
函数cv :: invert反转矩阵src并将结果存储在dst中。 当矩阵src是奇异或非正方形时,该函数计算伪逆矩阵(dst矩阵),以便norm(src * dst-I)最小,其中I是一个单位矩阵。
在使用DECOMP_LU方法的情况下,如果成功计算了反函数,则函数返回非零值;如果src为奇数,则函数返回0。
在DECOMP_SVD方法的情况下,该函数返回src的逆条件数(最小奇异值与最大奇异值之比),如果src为奇异,则返回0。 如果src是奇异的,则SVD方法将计算伪逆矩阵。
与DECOMP_LU相似,方法DECOMP_CHOLESKY仅适用于也应对称且定义明确的非奇异方阵。 在这种情况下,函数将倒置矩阵存储在dst中,并返回非零值。 否则,它返回0。
// 创建矩阵
float data[] = {1,2,3,4,5,6,7,8,9};
cv::Mat src(3,3,CV_32FC1,data);
// 求矩阵的逆或伪逆
cv::Mat dst;
cv::invert(src,dst);
cout << "dst = " << dst << endl;
计算每个数组元素的自然对数。
void cv::log(InputArray src,OutputArray dst)
函数cv :: log计算输入数组中每个元素的自然对数: dst ( I ) = log ( src ( I ) ) \texttt{dst} (I) = \log (\texttt{src}(I)) dst(I)=log(src(I))
未定义零,负和特殊(NaN,Inf)值的输出。
对数组执行查找表转换。
void cv::LUT(InputArray src,InputArray lut,OutputArray dst)
函数LUT用查询表中的值填充输出数组。 条目的索引取自输入数组。 也就是说,该函数按以下方式处理src的每个元素:
dst ( I ) ← lut(src(I) + d) \texttt{dst} (I) \leftarrow \texttt{lut(src(I) + d)} dst(I)←lut(src(I) + d)
,其中:
KaTeX parse error: Expected '}', got '_' at position 55: … depth \text{CV_̲8U} \\ 128 & if…
uchar table[256];
for (int i = 0; i < 256; ++i)
table[i] = (uchar)(4 * (i/4));
cv::Mat src = cv::imread("resources/images/f1.jpg");
cv::Mat dst;
cv::Mat lut(1,256,CV_8UC3,table);
cv::LUT(src,lut,dst);
cv::imshow("src",src);
cv::imshow("dst",dst);
cv::waitKey();
计算2D向量的量纲。
void cv::magnitude(InputArray x,InputArray y,OutputArray magnitude)
函数cv :: magnitude计算由x和y数组的相应元素形成的2D向量的量纲:
dst ( I ) = x ( I ) 2 + y ( I ) 2 \texttt{dst} (I) = \sqrt{\texttt{x}(I)^2 + \texttt{y}(I)^2} dst(I)=x(I)2+y(I)2
// 创建矩阵
float datax[] = {1,2,3,4,5,6,7,8,9};
float data2[] = {1,3,5,7,9,11,13,15,17};
cv::Mat srcx(3,3,CV_32FC1,datax);
cv::Mat srcy(3,3,CV_32FC1,data2);
// 计算2D向量的量纲
cv::Mat dst;
cv::magnitude(srcx,srcy,dst);
cout << "magnitude = " << dst << endl;
计算两个矩阵的马氏距离(Mahalanobis Distance)。
double cv::Mahalanobis(InputArray v1,InputArray v2,InputArray icovar)
函数cv :: Mahalanobis计算并返回两个向量之间的加权距离:
d ( vec1 , vec2 ) = ∑ i , j icovar(i,j) ⋅ ( vec1 ( I ) − vec2 ( I ) ) ⋅ ( vec1(j) − vec2(j) ) d( \texttt{vec1} , \texttt{vec2} )= \sqrt{\sum_{i,j}{\texttt{icovar(i,j)}\cdot(\texttt{vec1}(I)-\texttt{vec2}(I))\cdot(\texttt{vec1(j)}-\texttt{vec2(j)})} } d(vec1,vec2)=∑i,jicovar(i,j)⋅(vec1(I)−vec2(I))⋅(vec1(j)−vec2(j))
可以使用calcCovarMatrix函数计算协方差矩阵,然后使用求反函数(最好是使用DECOMP_SVD方法,最精确的求逆函数)求逆。
//2行5列 Mat Pt(2, 5, CV_64FC1); Pt.at<double>(0, 0) = 2; Pt.at<double>(1, 0) = 4; Pt.at<double>(0, 1) = 2; Pt.at<double>(1, 1) = 2; Pt.at<double>(0, 2) = 3; Pt.at<double>(1, 2) = 3; Pt.at<double>(0, 3) = 4; Pt.at<double>(1, 3) = 4; Pt.at<double>(0, 4) = 4; Pt.at<double>(1, 4) = 2; cout << Pt << endl; //计算协方差矩阵 Mat coVar, meanVar; calcCovarMatrix(Pt, coVar, meanVar, COVAR_NORMAL|COVAR_COLS); cout << "Covar is:\n" << coVar << endl; cout << "Mean is:\n" << meanVar << endl; //计算协方差的逆 Mat iCovar; invert(coVar, iCovar, DECOMP_SVD); Mat pt1(2, 1, CV_64FC1); Mat pt2(2, 1, CV_64FC1); pt1.at<double>(0, 0) = 1; pt1.at<double>(1, 0) = 1; pt2.at<double>(0, 0) = 5; pt2.at<double>(1, 0) = 5; double Maha1 = Mahalanobis(pt1, meanVar, iCovar); double Maha2 = Mahalanobis(pt2, meanVar, iCovar); cout << "Maha distance 1:\t" << Maha1 << endl; cout << "Maha distance 2:\t" << Maha2 << endl;
1)cv::max:函数cv :: max计算两个数组的每个元素的最大值。
void cv::max(InputArray src1,InputArray src2,OutputArray dst)
1)cv::min:函数cv :: max计算两个数组的每个元素的最小值。
void cv::min(InputArray src1,InputArray src2,OutputArray dst)
// 创建矩阵 float data1[] = {1,2,3,4,5,6,7,8,9}; float data2[] = {1,3,5,7,9,11,13,15,17}; cv::Mat src1(3,3,CV_32FC1,data1); cv::Mat src2(3,3,CV_32FC1,data2); // 计算两个数组的最大值 cv::Mat dst; // 数组间计算 cv::max(src1,src2,dst); cout << "max = " << dst << endl; // 标量间计算 cv::max(src1,5,dst); cout << "max = " << dst << endl; // 计算两个数组最小值 cv::min(src1,src2,dst); cout << "min = " << dst << endl; cv::min(src1,5,dst); cout << "min = " << dst << endl;
1)cv::mean:计算数组元素的平均值(均值)。
Scalar cv::mean (InputArray src,InputArray mask = noArray())
函数cv :: mean独立于每个通道计算数组元素的平均值M,然后将其返回:
N = ∑ I : mask ( I ) ≠ 0 1 M c = ( ∑ I : mask ( I ) ≠ 0 mtx ( I ) c ) / N N=∑I:mask(I)≠01Mc=(∑I:mask(I)≠0mtx(I)c)/N N=∑I:mask(I)=01Mc=(∑I:mask(I)=0mtx(I)c)/N
当所有mask元素均为0时,该函数返回Scalar :: all(0)
// 创建矩阵
float data1[] = {1,2,3,4,5,6,7,8,9};
float data2[] = {1,3,5,7,9,11,13,15,17};
cv::Mat src1(3,3,CV_32FC1,data1);
cv::Mat src2(3,3,CV_32FC1,data2);
// 计算均值
cv::Scalar result = cv::mean(src1);
cout << "mean = " << result << endl;
result = cv::mean(src2);
cout << "mean = " << result << endl;
2)cv::meanStdDev:计算数组元素的均值和标准差。
void cv::meanStdDev(InputArray src,OutputArray mean,OutputArray stddev,InputArray mask = noArray())
函数cv :: meanStdDev为每个通道独立计算数组元素的平均值和标准偏差M,并通过输出参数返回:
N = ∑ I , mask ( I ) ≠ 0 1 mean c = ∑ I : mask ( I ) ≠ 0 src ( I ) c N stddev c = ∑ I : mask ( I ) ≠ 0 ( src ( I ) c − mean c ) 2 N N=∑I,mask(I)≠01meanc=∑I:mask(I)≠0src(I)cNstddevc=√∑I:mask(I)≠0(src(I)c−meanc)2N N=∑I,mask(I)=01meanc=N∑I:mask(I)=0src(I)cstddevc=N∑I:mask(I)=0(src(I)c−meanc)2
当所有mask元素均为0时,该函数返回Scalar :: all(0)
// 创建矩阵
float data1[] = {1,2,3,4,5,6,7,8,9};
float data2[] = {1,3,5,7,9,11,13,15,17};
cv::Mat src1(3,3,CV_32FC1,data1);
cv::Mat src2(3,3,CV_32FC1,data2);
cv::Mat resultMean,resultStdDev;
cv::meanStdDev(src1,resultMean,resultStdDev);
cout << "mean = " << resultMean << ",stddev = " << resultStdDev << endl;
1)cv::split:将多个单通道矩阵合并成一个多通道矩阵。
void cv::merge(const Mat * mv,size_t count,OutputArray dst)
函数cv :: merge合并多个数组以组成单个多通道数组。 也就是说,输出数组的每个元素都是输入数组的元素的串联,其中第i个输入数组的元素被视为mv [i] .channels()-元素向量。
Mat m1 = (Mat_<uchar>(2,2) << 1,4,7,10);
Mat m2 = (Mat_<uchar>(2,2) << 2,5,8,11);
Mat m3 = (Mat_<uchar>(2,2) << 3,6,9,12);
Mat channels[3] = {m1, m2, m3};
Mat m;
merge(channels, 3, m);
/*
m =
[ 1, 2, 3, 4, 5, 6;
7, 8, 9, 10, 11, 12]
m.channels() = 3
*/
2)cv::split:将一个多通道矩阵拆分成多个单通道矩阵。
void cv::split(const Mat & src,Mat * mvbegin)
函数cv :: split将多通道数组拆分为单独的单通道数组: mv [ c ] ( I ) = src ( I ) c \texttt{mv} [c](I) = \texttt{src} (I)_c mv[c](I)=src(I)c
如果您需要提取单个通道或进行其他一些复杂的通道置换,请使用mixChannels。
// 创建矩阵 float data1[] = {1,2,3,4,5,6,7,8,9}; float data2[] = {1,3,5,7,9,11,13,15,17}; cv::Mat src1(3,3,CV_32FC1,data1); cv::Mat src2(3,3,CV_32FC1,data2); cv::Mat srcs[] = {src1,src2}; // 矩阵合并 cv::Mat merged; cv::merge(srcs,2,merged); cout << "merged = \n" << format(merged, cv::Formatter::FMT_PYTHON) << endl; // 矩阵拆分 std::vector<cv::Mat> channels; cv::split(merged,channels); cout << "channels[0] = \n" << format(channels[0], cv::Formatter::FMT_PYTHON) << endl; cout << "channels[1] = \n" << format(channels[1], cv::Formatter::FMT_PYTHON) << endl;
3)、cv::mixChannels:函数cv :: mixChannels提供了用于改组图像通道的高级机制。
void cv::mixChannels(const Mat * src,size_t nsrcs,Mat * dst,size_t ndsts,size_t npairs)
Mat bgra( 100, 100, CV_8UC4, Scalar(255,0,0,255) );
Mat bgr( bgra.rows, bgra.cols, CV_8UC3 );
Mat alpha( bgra.rows, bgra.cols, CV_8UC1 );
// forming an array of matrices is a quite efficient operation,
// because the matrix data is not copied, only the headers
Mat out[] = { bgr, alpha };
// bgra[0] -> bgr[2], bgra[1] -> bgr[1],
// bgra[2] -> bgr[0], bgra[3] -> alpha[0]
int from_to[] = { 0,2, 1,1, 2,0, 3,3 };
mixChannels( &bgra, 1, out, 2, from_to, 4 );
执行两个傅立叶频谱的逐元素乘法。
void cv::mulSpectrums(InputArray a,InputArray b,int flags,bool conjB = false)
函数cv :: mulSpectrums执行两个CCS-pakaged或复杂矩阵的逐元素乘法,这两个矩阵是实际或复杂傅立叶变换的结果。
该函数与dft和idft一起可用于快速计算两个数组的卷积(pass conjB = false)或相关性(pass conjB = true)。 当数组很复杂时,只需将它们与第二个数组元素的可选共轭简单地相乘(每个元素)。 当数组为实数时,假定它们是CCS-pakaged的(有关详细信息,请参阅dft)。
#include <iostream> #include <opencv2/opencv.hpp> using namespace cv; using namespace std; //http://docs.opencv.org/modules/core/doc/operations_on_arrays.html#dft[2] void convolveDFT(Mat A, Mat B, Mat& C) { // 重新配置空间给输出数组 C.create(abs(A.rows - B.rows)+1, abs(A.cols - B.cols)+1, A.type()); Size dftSize; // 计算最优DFT大小 dftSize.width = getOptimalDFTSize(A.cols + B.cols - 1); dftSize.height = getOptimalDFTSize(A.rows + B.rows - 1); // allocate temporary buffers and initialize them with 0's Mat tempA(dftSize, A.type(), Scalar::all(0)); Mat tempB(dftSize, B.type(), Scalar::all(0)); // copy A and B to the top-left corners of tempA and tempB, respectively 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); // now transform the padded A & B in-place; // use "nonzeroRows" hint for faster processing dft(tempA, tempA, 0, A.rows); dft(tempB, tempB, 0, B.rows); // multiply the spectrums; // the function handles packed spectrum representations well mulSpectrums(tempA, tempB, tempA, DFT_COMPLEX_OUTPUT); //mulSpectrums(tempA, tempB, tempA, DFT_REAL_OUTPUT); // transform the product back from the frequency domain. // Even though all the result rows will be non-zero, // you need only the first C.rows of them, and thus you // pass nonzeroRows == C.rows dft(tempA, tempA, DFT_INVERSE + DFT_SCALE, C.rows); // now copy the result back to C. tempA(Rect(0, 0, C.cols, C.rows)).copyTo(C); // all the temporary buffers will be deallocated automatically } int main(int argc, char* argv[]) { const char* filename = "resources/images/f1.jpg"; Mat I = imread(filename, 0); if( I.empty()) return -1; Mat kernel = (Mat_<float>(3,3) << 1, 1, 1, 1, 1, 1, 1, 1, 1); cout << kernel; Mat floatI = Mat_<float>(I);// change image type into float Mat filteredI; convolveDFT(floatI, kernel, filteredI); normalize(filteredI, filteredI, 0, 1, cv::NORM_MINMAX); // Transform the matrix with float values into a // viewable image form (float between values 0 and 1). imshow("image", I); imshow("filtered", filteredI); waitKey(0); }
计算数组的绝对范数。
double cv::norm (InputArray src1,int normType = NORM_L2,InputArray mask = noArray())
此版本的规范计算src1的绝对规范。 使用NormTypes指定要计算的范式类型:
NORM_INF :
KaTeX parse error: Expected '}', got '_' at position 123: … = \texttt{NORM_̲INF} ) } \\ {\|…
NORM_L1 :
KaTeX parse error: Expected '}', got '_' at position 119: … = \texttt{NORM_̲L1} )} \\{ \| \…
NORM_L2 :
KaTeX parse error: Expected '}', got '_' at position 125: … = \texttt{NORM_̲L2} ) } \\{ \| …
NORM_L2SQR:
KaTeX parse error: Expected '}', got '_' at position 123: … = \texttt{NORM_̲L2SQR} )}\\ { \…
NORM_HAMMING :对于一个输入数组,从零开始计算该数组的汉明距离;对于两个输入数组,在两个数组之间,计算汉明距离。
NORM_HAMMING2 :与NORM_HAMMING相似,但是在计算中,输入序列的每两位将被添加并视为一个位,以便与NORM_HAMMING进行相同的计算。
NORM_TYPE_MASK :位掩码,可用于将规范类型与规范标志分开
NORM_RELATIVE :标志
NORM_MINMAX :标志
规范数组的范数或值范围。
函数cv :: normalize标准化比例尺并移动输入数组元素:
∥ dst ∥ L p = alpha \| \texttt{dst} \| _{L_p}= \texttt{alpha} ∥dst∥Lp=alpha
(其中p = Inf,1或2)分别在normType = NORM_INF,NORM_L1或NORM_L2时:
min I dst ( I ) = alpha , max I dst ( I ) = beta \min _I \texttt{dst} (I)= \texttt{alpha} , \, \, \max _I \texttt{dst} (I)= \texttt{beta} minIdst(I)=alpha,maxIdst(I)=beta
当normType = NORM_MINMAX(仅适用于密集阵列)时。 可选的掩码指定要标准化的子数组。 这意味着在子数组上计算了范数或min-n-max,然后修改了该子数组以进行标准化。 如果只想使用掩码来计算范数或最小最大值,而要修改整个数组,则可以使用范数和Mat :: convertTo。
不允许对稀疏矩阵进行范围转换。
vector<double> positiveData = { 2.0, 8.0, 10.0 }; vector<double> normalizedData_l1, normalizedData_l2, normalizedData_inf, normalizedData_minmax; // Norm to probability (total count) // sum(numbers) = 20.0 // 2.0 0.1 (2.0/20.0) // 8.0 0.4 (8.0/20.0) // 10.0 0.5 (10.0/20.0) normalize(positiveData, normalizedData_l1, 1.0, 0.0, NORM_L1); // Norm to unit vector: ||positiveData|| = 1.0 // 2.0 0.15 // 8.0 0.62 // 10.0 0.77 normalize(positiveData, normalizedData_l2, 1.0, 0.0, NORM_L2); // Norm to max element // 2.0 0.2 (2.0/10.0) // 8.0 0.8 (8.0/10.0) // 10.0 1.0 (10.0/10.0) normalize(positiveData, normalizedData_inf, 1.0, 0.0, NORM_INF); // Norm to range [0.0;1.0] // 2.0 0.0 (shift to left border) // 8.0 0.75 (6.0/8.0) // 10.0 1.0 (shift to right border) normalize(positiveData, normalizedData_minmax, 1.0, 0.0, NORM_MINMAX);
1)cv::perspectiveTransform:执行向量的透视矩阵转换。
函数cv :: perspectiveTransform通过以下方式将src的每个元素视为2D或3D向量,从而对其进行转换:
( x , y , z ) → ( x ′ / w , y ′ / w , z ′ / w ) (x, y, z) \rightarrow (x'/w, y'/w, z'/w) (x,y,z)→(x′/w,y′/w,z′/w),其中 ( x ′ , y ′ , z ′ , w ′ ) = mat ⋅ [ x y z 1 ] (x', y', z', w') = \texttt{mat} \cdot [xyz1] (x′,y′,z′,w′)=mat⋅[xyz1], w = { w ′ , i f ( w ′ ≠ 0 ) ∞ , o t h e r w i s e w = {w′,if(w′≠0)∞,otherwise w={w′,if(w′=0)∞,otherwise
这里显示了3D矢量变换。 在2D矢量变换的情况下,z分量被省略。
2)cv::getPerspectiveTransform:根据四对对应点计算透视变换。
Mat cv::getPerspectiveTransform (InputArray src,InputArray dst,int solveMethod = DECOMP_LU)
该函数计算透视变换的3×3矩阵:
KaTeX parse error: Expected '}', got '_' at position 72: …} = \texttt{map_̲matrix} \cdot \…,其中, d s t ( i ) = ( x i ′ , y i ′ ) , s r c ( i ) = ( x i , y i ) , i = 0 , 1 , 2 , 3 dst(i)=(x'_i,y'_i), src(i)=(x_i, y_i), i=0,1,2,3 dst(i)=(xi′,yi′),src(i)=(xi,yi),i=0,1,2,3
3)cv::warpPerspective:将透视变换应用于图像。
void cv::warpPerspective(InputArray src,OutputArray dst,InputArray M,Size dsize,int flags = INTER_LINEAR,int borderMode = BORDER_CONSTANT,const Scalar & borderValue = Scalar())
函数warpPerspective使用指定的矩阵转换源图像:
dst ( x , y ) = src ( M 11 x + M 12 y + M 13 M 31 x + M 32 y + M 33 , M 21 x + M 22 y + M 23 M 31 x + M 32 y + M 33 ) \texttt{dst} (x,y) = \texttt{src} \left ( \frac{M_{11} x + M_{12} y + M_{13}}{M_{31} x + M_{32} y + M_{33}} , \frac{M_{21} x + M_{22} y + M_{23}}{M_{31} x + M_{32} y + M_{33}} \right ) dst(x,y)=src(M31x+M32y+M33M11x+M12y+M13,M31x+M32y+M33M21x+M22y+M23)
当设置标志WARP_INVERSE_MAP时。 否则,首先使用invert反转变换,然后将其放在上面的公式中,而不是M中。该函数无法就地操作。
// Input Quadilateral or Image plane coordinates Point2f inputQuad[4]; // Output Quadilateral or World plane coordinates Point2f outputQuad[4]; // Lambda Matrix Mat lambda( 2, 4, CV_32FC1 ); //Input and Output Image; Mat input, output; //Load the image input = imread( "resources/images/f1.jpg"); // Set the lambda matrix the same type and size as input lambda = Mat::zeros( input.rows, input.cols, input.type() ); // The 4 points that select quadilateral on the input , from top-left in clockwise order // These four pts are the sides of the rect box used as input inputQuad[0] = Point2f( -30,-60 ); inputQuad[1] = Point2f( input.cols+50,-50); inputQuad[2] = Point2f( input.cols+100,input.rows+50); inputQuad[3] = Point2f( -50,input.rows+50 ); // The 4 points where the mapping is to be done , from top-left in clockwise order outputQuad[0] = Point2f( 0,0 ); outputQuad[1] = Point2f( input.cols-1,0); outputQuad[2] = Point2f( input.cols-1,input.rows-1); outputQuad[3] = Point2f( 0,input.rows-1 ); // // Get the Perspective Transform Matrix i.e. lambda lambda = getPerspectiveTransform( inputQuad, outputQuad ); // // Apply the Perspective Transform just found to the src image warpPerspective(input,output,lambda,output.size() ); imshow("Input",input); imshow("Output",output); waitKey(0);
计算2D向量的旋转角度(方向场)。
void cv::phase(InputArray x,OutputArray angle,bool angleInDegrees = false)
函数cv :: phase计算由x和y的对应元素形成的每个2D矢量的旋转角度: angle ( I ) = atan2 ( y ( I ) , x ( I ) ) \texttt{angle} (I) = \texttt{atan2} ( \texttt{y} (I), \texttt{x} (I)) angle(I)=atan2(y(I),x(I))
角度估计精度约为0.3度。 当x(I)= y(I)= 0时,相应的角度(I)设置为0。
Mat img = cv::imread( "resources/images/f1.jpg",0);
Mat grad1,grad2,angle;
Sobel(img, grad1, CV_64FC1, 1, 0); //求梯度
Sobel(img, grad2, CV_64FC1, 0, 1);
blur(grad1,grad1,Size(6,6));
blur(grad2,grad2,Size(6,6));
phase(grad1, grad2, angle, true); //求角度
normalize(angle, angle, 0, 255, NORM_MINMAX); //归一化 方便显示,和实际数据没有关系
angle.convertTo(angle,CV_8UC1);
imshow("src",img);
imshow("angle",angle);
waitKey();
计算峰值信噪比(PSNR)图像质量指标。
double cv::PSNR (InputArray src1,InputArray src2,double R = 255.)
此函数计算两个输入阵列src1和src2之间的峰值信噪比(PSNR)图像质量度量,以分贝(dB)为单位。 数组必须具有相同的类型。PSNR计算如下:
PSNR = 10 ⋅ log 10 ( R 2 M S E ) \texttt{PSNR} = 10 \cdot \log_{10}{\left( \frac{R^2}{MSE} \right) } PSNR=10⋅log10(MSER2)
其中R是深度的最大整数值(例如,对于CV_8U数据为255),MSE是两个数组之间的均方误差。
double compute_PSNR(cv::Mat Mat1, cv::Mat Mat2) { cv::Mat M1 = Mat1.clone(); cv::Mat M2 = Mat2.clone(); int rows = M2.rows; int cols = M2.cols // 确保它们的大小是一致的 cv::resize(mGND,mGND,cv::Size(cols,rows) ); mGND.convertTo(M1,CV_32F); mSR.convertTo(mSR,CV_32F); // compute PSNR Mat Diff; // Diff一定要提前转换为32F,因为uint8格式的无法计算成平方 Diff.convertTo(Diff,CV_32F); cv::absdiff(M1,M2,Diff); // Diff = | M1 - M2 | Diff= Diff.mul(Diff); // | M1 - M2 |.^2 Scalar S = cv::sum(Diff); // 分别计算每个通道的元素之和 double sse; // square error if (mDiff.channels()==3) sse = S.val[0] +S.val[1] + S.val[2]; // sum of all channels else sse = S.val[0]; int nTotalElement = mGND.channels()*mGND.total(); double mse = ( sse / (double)nTotalElement ); // // 加上0.0000001作为偏置,不至于发生除了的错误 double psnr = 10.0 * log10( 255*255 / (Mse+0.0000001) ); std::cout<< "PSNR : " << Psnr << std::endl; return psnr;
1)cv::randn:用正态分布的随机数填充数组。
void cv::randn(InputOutputArray dst,InputArray stddev)
函数cv :: randn用正态分布的随机数填充矩阵dst,该随机数具有指定的均值向量和标准差矩阵。 剪切生成的随机数以适合输出数组数据类型的值范围。
2)cv::randShuffle:随机随机排列数组元素。
void cv::randShuffle(InputOutputArray dst,double iterFactor = 1.,RNG * rng = 0)
函数cv :: randShuffle通过随机选择元素对并交换它们来对指定的1D数组进行混洗。 此类交换操作的数量为dst.rows * dst.cols * iterFactor。
3)cv::randu:生成单个均匀分布的随机数或随机数数组。
void cv::randu(InputOutputArray dst,InputArray low,InputArray high)
该函数的非模板变量使用指定范围内的均匀分布的随机数填充矩阵dst。 low c ≤ dst ( I ) c < high c \texttt{low} _c \leq \texttt{dst} (I)_c < \texttt{high} _c lowc≤dst(I)c<highc
将矩阵简化为向量。
void cv::reduce(InputArray src,OutputArray dst,int dim,int dtype = -1)
函数reduce通过将矩阵行/列视为一组一维向量并对向量执行指定的操作,直到获得单个行/列,将矩阵简化为向量。 例如,该函数可用于计算光栅图像的水平和垂直投影。 如果使用REDUCE_MAX和REDUCE_MIN,则输出图像应与源图像具有相同的类型。 在REDUCE_SUM和REDUCE_AVG的情况下,输出可能具有较大的元素位深度,以保持精度。 这两种归约模式也支持多通道阵列。
Mat m = (Mat_<uchar>(3,2) << 1,2,3,4,5,6); Mat col_sum, row_sum; reduce(m, col_sum, 0, REDUCE_SUM, CV_32F); reduce(m, row_sum, 1, REDUCE_SUM, CV_32F); /* m = [ 1, 2; 3, 4; 5, 6] col_sum = [9, 12] row_sum = [3; 7; 11] */
用输入数组的重复副本填充输出数组。
void cv::repeat(InputArray src,int ny,OutputArray dst)
函数cv :: repeat沿着两个轴中的每个轴将输入数组复制一次或多次: dst i j = src i m o d s r c . r o w s , j m o d s r c . c o l s \texttt{dst} _{ij}= \texttt{src} _{i\mod src.rows, \; j\mod src.cols } dstij=srcimodsrc.rows,jmodsrc.cols
1)cv::solve:求解一个或多个线性系统或最小二乘问题。
bool cv::solve(InputArray src1,InputArray src2,OutputArray dst,int flags = DECOMP_LU)
函数cv :: solve解决了线性系统或最小二乘问题(后者可以通过SVD或QR方法或通过指定标志DECOMP_NORMAL来实现):
dst = arg min X ∥ src1 ⋅ X − src2 ∥ \texttt{dst} = \arg \min _X \| \texttt{src1} \cdot \texttt{X} - \texttt{src2} \| dst=argminX∥src1⋅X−src2∥
如果使用DECOMP_LU或DECOMP_CHOLESKY方法,则该函数返回1
如果src1或者 src1 T src1 \texttt{src1}^T\texttt{src1} src1Tsrc1是non-singular,返回0,否则返回1。
在后一种情况下,dst无效。 其他方法在左侧部分为奇数的情况下找到伪解。
2)cv::solveCubic:查找三次方程的实根。
int cv::solveCubic(InputArray coeffs,OutputArray roots)
函数solveCubic查找三次方程的实根:
根存储在roots数组中。
3)cv::solvePoly:查找多项式方程的实根或复数根。
double cv::solvePoly(InputArray coeffs,OutputArray roots,int maxIters = 300)
函数cv :: solvePoly查找多项式方程的实根和复根:
coeffs [ n ] x n + coeffs [ n − 1 ] x n − 1 + . . . + coeffs [ 1 ] x + coeffs [ 0 ] = 0 \texttt{coeffs} [n] x^{n} + \texttt{coeffs} [n-1] x^{n-1} + ... + \texttt{coeffs} [1] x + \texttt{coeffs} [0] = 0 coeffs[n]xn+coeffs[n−1]xn−1+...+coeffs[1]x+coeffs[0]=0
1)cv::sort:对矩阵的每一行或每一列进行排序。
void cv::sort(InputArray src,OutputArray dst,int flags)
函数cv :: sort以升序或降序对每个矩阵行或每个矩阵列进行排序。 因此,您应该传递两个操作标志以获得所需的行为。 如果要按字典顺序对矩阵行或列进行排序,则可以将STL std :: sort泛型函数与正确的比较谓词一起使用。
2)cv::sortIdx:对矩阵的每一行或每一列进行排序。
void cv::sortIdx(InputArray src,OutputArray dst,int flags)
函数cv :: sortIdx以升序或降序对每个矩阵行或每个矩阵列进行排序。 因此,您应该传递两个操作标志以获得所需的行为。 它没有对元素本身进行重新排序,而是将已排序元素的索引存储在输出数组中。 例如:
Mat A = Mat::eye(3,3,CV_32F), B;
sortIdx(A, B, SORT_EVERY_ROW + SORT_ASCENDING);
// B will probably contain
// (because of equal elements in A some permutations are possible):
// [[1, 2, 0], [0, 2, 1], [0, 1, 2]]
返回矩阵的轨迹。
Scalar cv::trace(InputArray mtx)
函数cv :: trace返回矩阵mtx的对角元素之和: t r ( mtx ) = ∑ i mtx ( i , i ) \mathrm{tr} ( \texttt{mtx} ) = \sum _i \texttt{mtx} (i,i) tr(mtx)=∑imtx(i,i)
1)cv::transform:对每个数组元素执行矩阵转换。
void cv::transform(InputArray src,OutputArray dst,InputArray m)
函数cv :: transform对数组src的每个元素执行矩阵转换,并将结果存储在dst中:
N通道数组src的每个元素都被解释为N元素矢量,它使用M x N或M x(N + 1)矩阵m转换为M元素矢量-输出数组dst的对应元素。
该功能可用于N维点的几何变换,任意线性色彩空间变换(例如各种RGB到YUV变换),混洗图像通道等等。
2)cv::transpose:转置矩阵。
void cv::transpose(InputArray src,OutputArray dst)
函数cv :: transpose转置矩阵src: dst ( i , j ) = src ( j , i ) \texttt{dst} (i,j) = \texttt{src} (j,i) dst(i,j)=src(j,i)
1)cv::hconcat:将水平串联应用于给定矩阵。
void cv::hconcat(const Mat * src,size_t nsrc,OutputArray dst)
该函数水平连接两个或多个cv :: Mat矩阵(具有相同的行数)。
cv::Mat matArray[] = { cv::Mat(4, 1, CV_8UC1, cv::Scalar(1)),
cv::Mat(4, 1, CV_8UC1, cv::Scalar(2)),
cv::Mat(4, 1, CV_8UC1, cv::Scalar(3)),};
cv::Mat out;
cv::hconcat( matArray, 3, out );
//out:
//[1, 2, 3;
// 1, 2, 3;
// 1, 2, 3;
// 1, 2, 3]
2)cv::vconcat:将垂直串联应用于给定矩阵。
void cv::vconcat(const Mat * src,size_t nsrc,OutputArray dst)
cv::Mat matArray[] = { cv::Mat(1, 4, CV_8UC1, cv::Scalar(1)),
cv::Mat(1, 4, CV_8UC1, cv::Scalar(2)),
cv::Mat(1, 4, CV_8UC1, cv::Scalar(3)),};
cv::Mat out;
cv::vconcat( matArray, 3, out );
//out:
//[1, 1, 1, 1;
// 2, 2, 2, 2;
// 3, 3, 3, 3]
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。