当前位置:   article > 正文

OpenCV 4.x API 详解与C++实例-矩阵操作_cv::absdiff

cv::absdiff

第三节 矩阵操作

OpenCV对矩阵操作提供了丰富的操作函数。本节将详细描述常用基本的矩阵和图像算子。

1、cv::abs 和cv::absdiff


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;
  • 1
  • 2
  • 3
  • 4

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(src1src2(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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2、cv::add、cv::addWeighted、cv::scaleAdd


1)cv::add:计算两个数组或一个数组和一个标量的每个元素的总和。

void cv::add(InputArraysrc1,InputArray src2,OutputArray dst,InputArray mask = noArray(),int dtype = -1)

以下几种情况

  • 当两个输入数组具有相同的大小和相同的通道数时,两个数组的总和: dst ( I ) = saturate ( src1 ( I ) + src2 ( I ) ) if   mask ( I ) ≠ 0 \texttt{dst}(I) = \texttt{saturate} ( \texttt{src1}(I) + \texttt{src2}(I)) \quad \texttt{if mask}(I) \ne0 dst(I)=saturate(src1(I)+src2(I))if mask(I)=0
  • 从scalar构造src2或与src1.channels()具有相同数量的元素时,数组和标量的总和: dst ( I ) = saturate ( src1 ( I ) + src2 ) if   mask ( I ) ≠ 0 \texttt{dst}(I) = \texttt{saturate} ( \texttt{src1}(I) + \texttt{src2} ) \quad \texttt{if mask}(I) \ne0 dst(I)=saturate(src1(I)+src2)if mask(I)=0
  • 当从Scalar构造src1或与src2.channels()具有相同数量的元素时,标量和数组的和: dst ( I ) = saturate ( src1 + src2 ( I ) ) if   mask ( I ) ≠ 0 \texttt{dst}(I) = \texttt{saturate} ( \texttt{src1} + \texttt{src2}(I) ) \quad \texttt{if mask}(I) \ne0 dst(I)=saturate(src1+src2(I))if mask(I)=0

其中,参数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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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;
  • 1
  • 2
  • 3

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)=scalesrc1(I)+src2(I)

3、cv::batchDistance


最近邻域搜索

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

4、bitwise_and、bitwise_not、bitwise_or、bitwise_xor


1)bitwise_and:计算两个数组或一个数组和一个标量的每个元素的按位与操作。

void cv::bitwise_and (InputArray src1,InputArray src2,OutputArray dst,InputArray mask = noArray())

  • src1和src2具有相同大小时的两个数组: dst ( I ) = src1 ( I ) ∧ src2 ( I ) if   mask ( I ) ≠ 0 \texttt{dst} (I) = \texttt{src1} (I) \wedge \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0 dst(I)=src1(I)src2(I)if mask(I)=0
  • 从scalar构造src2或具有与src1.channels()相同数量的元素时的数组和标量: dst ( I ) = src1 ( I ) ∧ src2 if   mask ( I ) ≠ 0 \texttt{dst} (I) = \texttt{src1} (I) \wedge \texttt{src2} \quad \texttt{if mask} (I) \ne0 dst(I)=src1(I)src2if mask(I)=0
  • 当src1由Scalar构造或具有与src2.channels()相同数量的元素时,一个标量和一个数组: dst ( I ) = src1 ∧ src2 ( I ) if   mask ( I ) ≠ 0 \texttt{dst} (I) = \texttt{src1} \wedge \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0 dst(I)=src1src2(I)if mask(I)=0

对于浮点数组,其机器特定的位表示形式(通常符合IEEE754)用于操作。 在多通道阵列的情况下,每个通道都是独立处理的。 在上述第二种和第三种情况下,首先将标量转换为数组类型。

// 逻辑与操作
// 相同大小矩阵
cv::bitwise_and(src1,src2,dst);
cout << "src1 & src2 = " << dst << endl;
// 与常量运算
cv::bitwise_and(src1,0x0E,dst);
cout << "src1 & 0x0E = " << dst << endl;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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;
  • 1
  • 2
  • 3

3)bitwise_or:计算两个数组或一个数组和一个标量的每个元素的按位或操作。

void cv::bitwise_or(InputArray src1,InputArray src2,OutputArray dst,InputArray mask = noArray())

  • src1和src2具有相同大小时的两个数组: dst ( I ) = src1 ( I ) ∨ src2 ( I ) if   mask ( I ) ≠ 0 \texttt{dst} (I) = \texttt{src1} (I) \vee \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0 dst(I)=src1(I)src2(I)if mask(I)=0
  • 当从Scalar构造src2或具有与src1.channels()相同数量的元素时,一个数组和一个标量: dst ( I ) = src1 ( I ) ∨ src2 if   mask ( I ) ≠ 0 \texttt{dst} (I) = \texttt{src1} (I) \vee \texttt{src2} \quad \texttt{if mask} (I) \ne0 dst(I)=src1(I)src2if mask(I)=0
  • 当src1由Scalar构造或具有与src2.channels()相同数量的元素时,一个标量和一个数组: dst ( I ) = src1 ∨ src2 ( I ) if   mask ( I ) ≠ 0 \texttt{dst} (I) = \texttt{src1} \vee \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0 dst(I)=src1src2(I)if mask(I)=0

对于浮点输入数组,其特定于机器的位表示形式(通常符合IEEE754)用于操作。 在多通道阵列的情况下,每个通道都是独立处理的。

// 逻辑或操作
cv::bitwise_or(src1,src2,dst);
cout << "src1 | src2 = " << dst << endl;
// 与常量运算
cv::bitwise_or(src1,0x02,dst);
cout << "src1 | 0x02 = " << dst << endl;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

4)bitwise_xor:计算两个数组或一个数组和一个标量的每个元素的按位“异或”运算。

void cv::bitwise_xor(InputArray src1,InputArray src2,OutputArray dst,InputArray mask = noArray())

  • src1和src2具有相同大小时的两个数组: dst ( I ) = src1 ( I ) ⊕ src2 ( I ) if   mask ( I ) ≠ 0 \texttt{dst} (I) = \texttt{src1} (I) \oplus \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0 dst(I)=src1(I)src2(I)if mask(I)=0
  • 当从Scalar构造src2或具有与src1.channels()相同数量的元素时,一个数组和一个标量: dst ( I ) = src1 ( I ) ⊕ src2 if   mask ( I ) ≠ 0 \texttt{dst} (I) = \texttt{src1} (I) \oplus \texttt{src2} \quad \texttt{if mask} (I) \ne0 dst(I)=src1(I)src2if mask(I)=0
  • 当src1由Scalar构造或具有与src2.channels()相同数量的元素时,一个标量和一个数组: dst ( I ) = src1 ⊕ src2 ( I ) if   mask ( I ) ≠ 0 \texttt{dst} (I) = \texttt{src1} \oplus \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0 dst(I)=src1src2(I)if mask(I)=0

对于浮点输入数组,其特定于机器的位表示形式(通常符合IEEE754)用于操作。 在多通道阵列的情况下,每个通道都是独立处理的。

// 逻辑异或运算
cv::bitwise_xor(src1,src2,dst);
cout << "src1 ^ src2 = " << dst << endl;
// 与常量运算
cv::bitwise_xor(src1,0x0E,dst);
cout << "src1 ^ 0x0E = " << dst << endl;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

5、cv::calcCovarMatrix


计算一组向量的协方差矩阵。

void cv::calcCovarMatrix(const Mat * samples,int nsamples,Mat & covar,Mat & mean,int flags,int ctype = CV_64F)

flag的类型有:

  • COVAR_SCRAMBLED:输出协方差矩阵计算为: scale ⋅ [ vects [ 0 ] − mean , vects [ 1 ] − mean , . . . ] T ⋅ [ vects [ 0 ] − mean , vects [ 1 ] − mean , . . . ] , \texttt{scale} \cdot [ \texttt{vects} [0]- \texttt{mean} , \texttt{vects} [1]- \texttt{mean} ,...]^T \cdot [ \texttt{vects} [0]- \texttt{mean} , \texttt{vects} [1]- \texttt{mean} ,...], scale[vects[0]mean,vects[1]mean,...]T[vects[0]mean,vects[1]mean,...],
  • COVAR_NORMAL: 输出协方差矩阵计算为: scale ⋅ [ vects [ 0 ] − mean , vects [ 1 ] − mean , . . . ] ⋅ [ vects [ 0 ] − mean , vects [ 1 ] − mean , . . . ] T , \texttt{scale} \cdot [ \texttt{vects} [0]- \texttt{mean} , \texttt{vects} [1]- \texttt{mean} ,...] \cdot [ \texttt{vects} [0]- \texttt{mean} , \texttt{vects} [1]- \texttt{mean} ,...]^T, scale[vects[0]mean,vects[1]mean,...][vects[0]mean,vects[1]mean,...]T,
  • COVAR_USE_AVG: 该函数不会根据输入向量计算均值,而是使用传递的均值向量。 如果均值已预先计算或事先已知,或者如果协方差矩阵是按零件计算的,则这很有用。 在这种情况下,均值不是向量的输入子集的均值向量,而是整个集合的均值向量
  • COVAR_SCALE:协方差矩阵被缩放。 在“正常”模式下,小数位数为1./nsamples。 在“加扰”模式下,小数位数是每个输入向量中元素总数的倒数。 默认情况下(如果未指定标志),协方差矩阵不缩放(scale = 1)。
  • COVAR_ROWS:所有输入向量都存储为样本矩阵的行。 在这种情况下,均值应为单行向量。
  • COVAR_COLS:所有输入向量都存储为样本矩阵的列。 在这种情况下,均值应为单列向量。
// 创建矩阵
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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

6、cv::cartToPolar、cv::polarToCart


**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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

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。

7、cv::checkRange


检查输入数组的每个元素是否在有效的范围内。

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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

8、cv::compare


对两个数组或数组和标量值执行每个元素的比较。

void cv::compare (InputArray src1,InputArray src2,OutputArray dst,int cmpop)

  • 当src1和src2具有相同大小时,两个数组的元素: dst ( I ) = src1 ( I )   cmpop   src2 ( I ) \texttt{dst} (I) = \texttt{src1} (I) \,\texttt{cmpop}\, \texttt{src2} (I) dst(I)=src1(I)cmpopsrc2(I)
  • 当src2由标量构造或具有单个元素时,带有标量src2的src1元素: dst ( I ) = src1 ( I )   cmpop   src2 \texttt{dst} (I) = \texttt{src1}(I) \,\texttt{cmpop}\, \texttt{src2} dst(I)=src1(I)cmpopsrc2
  • 当src1由标量构造或具有单个元素时,带有src2元素的src1: dst ( I ) = src1   cmpop   src2 ( I ) \texttt{dst} (I) = \texttt{src1} \,\texttt{cmpop}\, \texttt{src2} (I) dst(I)=src1cmpopsrc2(I)

如果比较结果为true,则将输出数组的相应元素设置为255。可以用等效的矩阵表达式替换比较操作:

Mat dst1 = src1 >= src2;
Mat dst2 = src1 < 8;
  • 1
  • 2

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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

9、cv::completeSymm


将方矩阵的下半部或上半部复制到另一半。

void cv::completeSymm(InputOutputArray m,bool lowerToUpper = false)

函数cv :: completeSymm将方矩阵的下半部或上半部复制到另一半。 矩阵对角线保持不变:

  • m i j = m j i \texttt{m}_{ij}=\texttt{m}_{ji} mij=mji for i > j i > j i>j if lowerToUpper=false
  • m i j = m j i \texttt{m}_{ij}=\texttt{m}_{ji} mij=mji for i < j i < j i<j if lowerToUpper=true
// 创建矩阵
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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

10、cv::convertScaleAbs


缩放,计算绝对值,然后将结果转换为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);
  • 1
  • 2
  • 3
  • 4

11、cv::copyMakeBorder


边缘填充。

void cv::copyMakeBorder(InputArray src,OutputArray dst,int top,int bottom,int left,int right,int borderType,const Scalar & value = Scalar())

该功能将源图像复制到目标图像的中间。 复制的源图像左侧,右侧,上方和下方的区域将被外推像素填充。 这不是基于此功能的过滤功能(它们会即时推断像素),而是其他更复杂的功能(包括您自己的功能)可以用来简化图像边界处理。

borderType有以下类型:

BORDER_CONSTANTBORDER_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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

12、cv::countNonZero


计算非零数组元素。

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

13、cv::dct、cv::idct


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))1Y=(C(N))TY

    由于 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))TXC(N)

该函数通过查看输入数组的flags和大小来选择操作模式:

  • 如果(flags&DCT_INVERSE)== 0,则该函数执行正向1D或2D转换。 否则,它是一维或二维逆变换。
  • 如果(flags&DCT_ROWS)!= 0,则该函数对每一行执行一维转换。
  • 如果数组是单列或单行,则该函数执行一维转换。
  • 如果以上条件都不成立,则该函数将执行2D转换。

当前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);
  • 1
  • 2
// 创建矩阵
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();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2)cv::idct:对1D或2D数组执行离散余弦变逆换。

void cv::idct(InputArray src,OutputArray dst,int flags = 0)

14、cv::determinant


计算浮点类型方阵的行列式

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

15、cv::dft、cv::idft


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))1Y=(F(N))yX=(1/N)X, X=(F(N))1Y=(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)XF(N)

  • 反转M x N矩阵的2D傅立叶变换:

    X ′ = ( F ( M ) ) ∗ ⋅ Y ⋅ ( F ( N ) ) ∗ X = 1 M ⋅ N ⋅ X ′ X=(F(M))Y(F(N))X=1MNX X=(F(M))Y(F(N))X=MN1X

因此,该函数根据输入数组的flags和大小选择操作模式:

  • 如果设置了DFT_ROWS或输入数组具有单行或单列,则在设置DFT_ROWS时,该函数对矩阵的每一行执行一维正向或逆向变换。 否则,它将执行2D变换。
  • 如果输入数组为实数且未设置DFT_INVERSE,则该函数将执行正向1D或2D转换:
    • 设置DFT_COMPLEX_OUTPUT时,输出是与输入大小相同的复杂矩阵。
    • 如果未设置DFT_COMPLEX_OUTPUT,则输出为与输入大小相同的实数矩阵。 在2D转换的情况下,它使用如上所述的压缩格式。 如果是一个一维变换,则看起来像上面矩阵的第一行。 在进行多个一维转换的情况下(使用DFT_ROWS标志时),输出矩阵的每一行看起来都像上面矩阵的第一行。
  • 如果输入数组为复数,并且未设置DFT_INVERSE或DFT_REAL_OUTPUT,则输出为与输入大小相同的复数数组。 该函数根据标志DFT_INVERSE和DFT_ROWS独立地对整个输入数组或输入数组的每一行执行正向或反向1D或2D变换。
  • 当设置DFT_INVERSE且输入数组为实数,或者复杂但设置了DFT_REAL_OUTPUT时,输出为与输入大小相同的实数数组。 函数根据标志DFT_INVERSE和DFT_ROWS对整个输入数组或每个单独的行执行一维或二维逆变换。

如果设置了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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

dft逆变换

cv::dft(complexI, inverseTransform, cv::DFT_INVERSE|cv::DFT_REAL_OUTPUT);
  • 1

2)cv::idft:计算一维或二维数组的离散傅立叶逆变换。

void cv::idft(InputArray src,OutputArray dst,int flags = 0,int nonzeroRows = 0)

16、cv::divide、cv::multiply、cv::mulTransposed


1)cv::divide:对两个数组或按数组的标量执行按元素的除法。

void cv::divide(InputArray src1,InputArray src2,OutputArray dst,double scale = 1,int dtype = -1)

  • 将一个数组除以另一个: dst(I)   =   saturate(src1(I)*scale/src2(I)) \texttt{dst(I) = saturate(src1(I)*scale/src2(I))} dst(I) = saturate(src1(I)*scale/src2(I))
  • 没有src1时按数组标量: dst(I)   =   saturate(scale/src2(I)) \texttt{dst(I) = saturate(scale/src2(I))} dst(I) = saturate(scale/src2(I))

多通道阵列的不同通道是独立处理的。对于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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

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(scalesrc1(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及其转置的乘积:

  • dst = scale ( src − delta ) T ( src − delta ) \texttt{dst} = \texttt{scale} ( \texttt{src} - \texttt{delta} )^T ( \texttt{src} - \texttt{delta} ) dst=scale(srcdelta)T(srcdelta)
  • 当aTa=true, dst = scale ( src − delta ) ( src − delta ) T \texttt{dst} = \texttt{scale} ( \texttt{src} - \texttt{delta} ) ( \texttt{src} - \texttt{delta} )^T dst=scale(srcdelta)(srcdelta)T

除此以外。 该函数用于计算协方差矩阵。 增量为零时,当B = A’时,它可用作通用矩阵乘积A * B的更快替代品

17、cv::eigen、cv::eigenNonSymmetric


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()
  • 1
// 创建矩阵
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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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()
  • 1
// 创建矩阵
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
  • 2
  • 3
  • 4
  • 5
  • 6

18、cv::exp、cv::pow、cv::sqrt、cv::subtract、cv::sum


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)isintegersrc(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 ( I ) = saturate ( src1 ( I ) − src2 ( I ) ) if   mask ( I ) ≠ 0 \texttt{dst}(I) = \texttt{saturate} ( \texttt{src1}(I) - \texttt{src2}(I)) \quad \texttt{if mask}(I) \ne0 dst(I)=saturate(src1(I)src2(I))if mask(I)=0
  • 当src2由Scalar构造或与src1.channels()具有相同数量的元素时,数组与标量之间的差异: dst ( I ) = saturate ( src1 ( I ) − src2 ) if   mask ( I ) ≠ 0 \texttt{dst}(I) = \texttt{saturate} ( \texttt{src1}(I) - \texttt{src2} ) \quad \texttt{if mask}(I) \ne0 dst(I)=saturate(src1(I)src2)if mask(I)=0
  • 当src1由Scalar构造或与src2.channels()具有相同数量的元素时,标量和数组之间的差异: dst ( I ) = saturate ( src1 − src2 ( I ) ) if   mask ( I ) ≠ 0 \texttt{dst}(I) = \texttt{saturate} ( \texttt{src1} - \texttt{src2}(I) ) \quad \texttt{if mask}(I) \ne0 dst(I)=saturate(src1src2(I))if mask(I)=0
  • 在SubRS情况下,标量和数组之间的反差: dst ( I ) = saturate ( src2 − src1 ( I ) ) if   mask ( I ) ≠ 0 \texttt{dst}(I) = \texttt{saturate} ( \texttt{src2} - \texttt{src1}(I) ) \quad \texttt{if mask}(I) \ne0 dst(I)=saturate(src2src1(I))if mask(I)=0

其中,我是数组元素的多维索引。 在多通道阵列的情况下,每个通道都是独立处理的。
上面列表中的第一个函数可以替换为矩阵表达式:

dst = src1 - src2;
dst -= src1; // equivalent to subtract(dst, src1, dst);
  • 1
  • 2

输入阵列和输出阵列都可以具有相同或不同的深度。 例如,您可以减去8位无符号数组,并将差值存储在16位有符号数组中。 输出数组的深度由dtype参数确定。 在上面的第二种和第三种情况以及第一种情况下,当src1.depth()== src2.depth()时,dtype可以设置为默认值-1。 在这种情况下,输出数组将具有与输入数组相同的深度,无论是src1,src2还是两者。

5)cv::sum:计算数组元素的总和。

Scalar cv::sum(InputArray src)

函数cv :: sum针对每个通道独立计算并返回数组元素的总和。

19、cv::extractChannel、cv::insertChannel


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();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2)cv::insertChannel:将单个通道插入目标矩阵或数组(coi是从0开始的索引)

void cv::insertChannel(InputArray src,OutputArray dst,int coi)

20、cv::findNonZero


计算非零像素位置的列表。

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

21、cv::flip、cv::rotate


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.rowsi1,jifflipCode=0srci,src.colsj1ifflipCode>0srcsrc.rowsi1,src.colsj1ifflipCode<0 \right. dstij=srcsrc.rowsi1,jsrci,src.colsj1srcsrc.rowsi1,src.colsj1ifflipCode=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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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)。

22、cv::gemm


广义矩阵乘法。

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=alphasrc1Tsrc2+betasrc3T

对于复杂(两通道)数据,请执行复杂矩阵乘法。

该函数可以替换为矩阵表达式。 例如,上述调用可以替换为:

dst = alpha*src1.t()*src2 + beta*src3.t();
  • 1
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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

23、cv::getOptimalDFTSize


返回给定向量大小的最佳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。

24、cv::hconcat、cv::vconcat


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 );
  • 1
  • 2
  • 3
  • 4
  • 5

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 );
  • 1
  • 2
  • 3
  • 4
  • 5

25、cv::inRange


检查数组元素是否位于其他两个数组的元素之间。

void cv::inRange(InputArray src,InputArray lowerb,InputArray upperb,OutputArray dst)

该函数检查范围如下:

  • 对于单通道输入数组的每个元素: dst ( I ) = lowerb ( I ) 0 ≤ src ( I ) 0 ≤ upperb ( I ) 0 \texttt{dst} (I)= \texttt{lowerb} (I)_0 \leq \texttt{src} (I)_0 \leq \texttt{upperb} (I)_0 dst(I)=lowerb(I)0src(I)0upperb(I)0
  • 对于两通道矩阵: dst ( I ) = lowerb ( I ) 0 ≤ src ( I ) 0 ≤ upperb ( I ) 0 ∧ lowerb ( I ) 1 ≤ src ( I ) 1 ≤ upperb ( I ) 1 \texttt{dst} (I)= \texttt{lowerb} (I)_0 \leq \texttt{src} (I)_0 \leq \texttt{upperb} (I)_0 \land \texttt{lowerb} (I)_1 \leq \texttt{src} (I)_1 \leq \texttt{upperb} (I)_1 dst(I)=lowerb(I)0src(I)0upperb(I)0lowerb(I)1src(I)1upperb(I)1等等。

也就是说,如果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();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

26、cv::invert

查找矩阵的逆或伪逆。

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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

27、cv::log


计算每个数组元素的自然对数。

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)值的输出。

28、cv::LUT


对数组执行查找表转换。

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();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

29、cv::magnitude


计算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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

30、cv::Mahalanobis


计算两个矩阵的马氏距离(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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

31、cv::max、cv::min


1)cv::max:函数cv :: max计算两个数组的每个元素的最大值。

void cv::max(InputArray src1,InputArray src2,OutputArray dst)

  • 当src1、src2为相同尺度的数组时: dst ( I ) = max ⁡ ( src1 ( I ) , src2 ( I ) ) \texttt{dst} (I)= \max ( \texttt{src1} (I), \texttt{src2} (I)) dst(I)=max(src1(I),src2(I))
  • 当src1或src2为标量时: dst ( I ) = max ⁡ ( src1 ( I ) , value ) \texttt{dst} (I)= \max ( \texttt{src1} (I), \texttt{value} ) dst(I)=max(src1(I),value)

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

32、cv::mean、cv::meanStdDev


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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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)cmeanc)2N N=I,mask(I)=01meanc=NI:mask(I)=0src(I)cstddevc=NI:mask(I)=0(src(I)cmeanc)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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

33、cv::merge、cv::split、cv::mixChannels


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
    */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

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;

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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 );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

34、cv::mulSpectrums


执行两个傅立叶频谱的逐元素乘法。

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);

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71

35、cv::norm


计算数组的绝对范数。

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 :标志

36、cv::normalize


规范数组的范数或值范围。

函数cv :: normalize标准化比例尺并移动输入数组元素:

∥ dst ∥ L p = alpha \| \texttt{dst} \| _{L_p}= \texttt{alpha} dstLp=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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

37、cv::perspectiveTransform、cv::getPerspectiveTransform、cv::warpPerspective


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(w0),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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

38、cv::phase


计算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();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

39、cv::PSNR


计算峰值信噪比(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=10log10(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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

40、cv::randn、cv::randShuffle、cv::randu


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 lowcdst(I)c<highc

41、cv::reduce


将矩阵简化为向量。

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]
         */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

42、cv::repeat


用输入数组的重复副本填充输出数组。

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

43、cv::solve、cv::solveCubic、cv::solvePoly


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=argminXsrc1Xsrc2

如果使用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查找三次方程的实根:

  • 如果coeffs是4元素向量: coeffs [ 0 ] x 3 + coeffs [ 1 ] x 2 + coeffs [ 2 ] x + coeffs [ 3 ] = 0 \texttt{coeffs} [0] x^3 + \texttt{coeffs} [1] x^2 + \texttt{coeffs} [2] x + \texttt{coeffs} [3] = 0 coeffs[0]x3+coeffs[1]x2+coeffs[2]x+coeffs[3]=0
  • 如果coeffs是3元素向量: x 3 + coeffs [ 0 ] x 2 + coeffs [ 1 ] x + coeffs [ 2 ] = 0 x^3 + \texttt{coeffs} [0] x^2 + \texttt{coeffs} [1] x + \texttt{coeffs} [2] = 0 x3+coeffs[0]x2+coeffs[1]x+coeffs[2]=0

根存储在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[n1]xn1+...+coeffs[1]x+coeffs[0]=0

44、cv::sort


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]]
  • 1
  • 2
  • 3
  • 4
  • 5

45、cv::trace


返回矩阵的轨迹。

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)

46、cv::transform、cv::transpose


1)cv::transform:对每个数组元素执行矩阵转换。

void cv::transform(InputArray src,OutputArray dst,InputArray m)

函数cv :: transform对数组src的每个元素执行矩阵转换,并将结果存储在dst中:

  • dst ( I ) = m ⋅ src ( I ) \texttt{dst} (I) = \texttt{m} \cdot \texttt{src} (I) dst(I)=msrc(I)(当m.cols = src.channels()时)
  • dst ( I ) = m ⋅ [ src ( I ) ; 1 ] \texttt{dst} (I) = \texttt{m} \cdot [ \texttt{src} (I); 1] dst(I)=m[src(I);1](当m.cols = src.channels()+ 1时)

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)

47、cv::hconcat、cv::vconcat


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]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/942711?site
推荐阅读
相关标签
  

闽ICP备14008679号