OpenCV 常用函数使用例子和说明

1,操作例子目录

操作描述
cv::abs()返回所有元素的绝对值
cv::absdiff()返回两个元素数组差的绝对值
cv::add()最元素相加
cv::addWeighted()添加两个每个元素的权值
cv::bitwise_and()两个数组逐元素求与操作
cv::bitwise_not()数组逐元素求非
cv::bitwise_or()两个数组逐元素求或运算
cv::bitwise_xor()两个数组逐元素求异或运算
cv::calcCovarMatrix()计算n维数组的协方差
cv::cartToPolar()将二维向量转换为极坐标
cv::checkRange()检查数组是否是有效值
cv::compare()比较两个数组是否相同
cv::completeSymm()对称矩阵,复制一半元素到另一半
cv::convertScaleAbs()缩放,采取绝对值,然后转换为8bit无符号数值
cv::countNonZero()计算数组中非零元素的个数
cv::arrtoMat()转换旧版本的数组
cv::dct()计算离散余弦函数
cv::dft()计算傅里叶转换矩阵

 

cv::idct()计算逆离散余弦矩阵
cv::idft()

计算逆傅里叶矩阵

2,代码例子

//包含OpenCV的头文件
#include <opencv2/opencv.hpp>
#include <opencv2/core/mat.hpp>
#include <iostream>
#include <time.h>
using namespace  std;
//使用OpenCV的命名空间
using namespace cv;
//cv::abs()
//数据结果
/*
//原始数据
[0.060565587, -0.60148162, -0.19788112;
0.62877017, -0.12573405, -0.5024206;
0.54621011, 0.52418745, -0.38441104]
//abs后的结果数据
[0.060565587, 0.60148162, 0.19788112;
0.62877017, 0.12573405, 0.5024206;
0.54621011, 0.52418745, 0.38441104]
*/
void test_abs()
{
	const int iRows = 3;
	const int iCols = 3;
	Mat m(iRows, iCols, CV_32FC1);
	randu(m, -1, 1);
	cout << m << endl;
	Mat m1 = abs(m);
	cout << m1 << endl;
	return;
}

//测试absdiff()
/*
m0 is:
[0.060565587, -0.60148162, -0.19788112;
0.62877017, -0.12573405, -0.5024206;
0.54621011, 0.52418745, -0.38441104]

m1 is:
[1, 1, 1;
1, 1, 1;
1, 1, 1]

m2 is:
[0.93943441, 1.6014817, 1.1978811;
0.37122983, 1.1257341, 1.5024207;
0.45378989, 0.47581255, 1.3844111]
*/
void test_absdiff()
{
	const int iRows = 3;
	const int iCols = 3;
	Mat m0(iRows, iCols, CV_32FC1);
	//m1的元素为1.0f
	Mat m1(iRows, iCols, CV_32FC1, Scalar(1.0f));
	//m0的元素为[-1,1)的随机数
	randu(m0, -1, 1);
	cout << "m0 is:\n" << m0 << endl << endl;
	cout << "m1 is:\n" << m1 << endl << endl;
	Mat m2;
	absdiff(m0, m1, m2);
	cout << "m2 is:\n" << m2 << endl << endl;
	return;
}

//测试add()
/*
m0 is:
[0.060565587, -0.60148162, -0.19788112;
0.62877017, -0.12573405, -0.5024206;
0.54621011, 0.52418745, -0.38441104]

m1 is:
[1, 1, 1;
1, 1, 1;
1, 1, 1]

m2 is:
[1.0605656, 0.39851838, 0.8021189;
1.6287701, 0.87426597, 0.4975794;
1.5462101, 1.5241874, 0.61558896]
*/
void test_add()
{
	const int iRows = 3;
	const int iCols = 3;
	Mat m0(iRows, iCols, CV_32FC1);
	//m1的元素为1.0f
	Mat m1(iRows, iCols, CV_32FC1, Scalar(1.0f));	
	
	//m0的元素为[-1,1)的随机数
	randu(m0, -1, 1);
	cout << "m0 is:\n" << m0 << endl << endl;
	cout << "m1 is:\n" << m1 << endl << endl;
	Mat m2;
	add(m0, m1, m2);
	cout << "m2 is:\n" << m2 << endl << endl;
	return;
}

//测试addWeight()
/*
m0 is:
[0.060565587, -0.60148162, -0.19788112;
0.62877017, -0.12573405, -0.5024206;
0.54621011, 0.52418745, -0.38441104]

m1 is:
[1, 1, 1;
1, 1, 1;
1, 1, 1]

m2 is:
[0.5302828, 0.19925919, 0.40105945;
0.81438506, 0.43713298, 0.2487897;
0.77310503, 0.76209372, 0.30779448]
*/
void test_addWeight()
{
	const int iRows = 3;
	const int iCols = 3;
	Mat m0(iRows, iCols, CV_32FC1);
	//m1的元素为1.0f
	Mat m1(iRows, iCols, CV_32FC1, Scalar(1.0f));

	//m0的元素为[-1,1)的随机数
	randu(m0, -1, 1);
	cout << "m0 is:\n" << m0 << endl << endl;
	cout << "m1 is:\n" << m1 << endl << endl;
	Mat m2;
	addWeighted(m0, 0.5, m1, 0.5, 0, m2);
	cout << "m2 is:\n" << m2 << endl << endl;
	return;
}

//测试bitwise_and()
//结果和 src1&src2 是相同的
/*
m0 is:
[246, 156, 192;
7, 165, 166;
2, 179, 231]

m1 is:
[  1,   1,   1;
1,   1,   1;
1,   1,   1]

m2 is:
[  0,   0,   0;
1,   1,   0;
0,   1,   1]
*/
void test_bitwise_and()
{
	const int iRows = 3;
	const int iCols = 3;
	Mat m0(iRows, iCols, CV_8UC1);
	Mat m1(iRows, iCols, CV_8UC1, Scalar(1));
	randu(m0, 0, 256);
	cout << "m0 is:\n" << m0 << endl << endl;
	cout << "m1 is:\n" << m1 << endl << endl;
	Mat m2;
	bitwise_and(m0, m1, m2);
	cout << "m2 is:\n" << m2 << endl << endl;
	return;
}

//测试bitwise_not
//结果求反
/*
m0 is:
[246, 156, 192;
7, 165, 166;
2, 179, 231]

m2 is:
[  9,  99,  63;
248,  90,  89;
253,  76,  24]
*/
void test_bitwise_not()
{
	const int iRows = 3;
	const int iCols = 3;
	Mat m0(iRows, iCols, CV_8UC1);
	randu(m0, 0, 256);
	cout << "m0 is:\n" << m0 << endl << endl;
	Mat m2;
	bitwise_not(m0, m2);
	cout << "m2 is:\n" << m2 << endl << endl;
	return;
}

//测试bitwise_or()
/*
m0 is:
[246, 156, 192;
7, 165, 166;
2, 179, 231]

m1 is:
[  1,   1,   1;
1,   1,   1;
1,   1,   1]

m2 is:
[247, 157, 193;
7, 165, 167;
3, 179, 231]

*/
void test_bitwise_or()
{
	const int iRows = 3;
	const int iCols = 3;
	Mat m0(iRows, iCols, CV_8UC1);
	Mat m1(iRows, iCols, CV_8UC1, Scalar(1));
	randu(m0, 0, 256);
	cout << "m0 is:\n" << m0 << endl << endl;
	cout << "m1 is:\n" << m1 << endl << endl;
	Mat m2;
	bitwise_or(m0, m1, m2);
	cout << "m2 is:\n" << m2 << endl << endl;
	return;
}

//测试 bitwise_xor()
/*
m0 is:
[246, 156, 192;
7, 165, 166;
2, 179, 231]

m1 is:
[  1,   1,   1;
1,   1,   1;
1,   1,   1]

m2 is:
[247, 157, 193;
6, 164, 167;
3, 178, 230]
*/
void test_bitwise_xor()
{
	const int iRows = 3;
	const int iCols = 3;
	Mat m0(iRows, iCols, CV_8UC1);
	Mat m1(iRows, iCols, CV_8UC1, Scalar(1));
	randu(m0, 0, 256);
	cout << "m0 is:\n" << m0 << endl << endl;
	cout << "m1 is:\n" << m1 << endl << endl;
	Mat m2;
	bitwise_xor(m0, m1, m2);
	cout << "m2 is:\n" << m2 << endl << endl;
	return;
}

//测试calcCovarMatrix 计算协方差矩阵
//协方差计算的例子:https://blog.youkuaiyun.com/mr_hhh/article/details/78490576
//一个需要注意的地方:
//如果不使用COVAR_SCALE的话,那么计算出来的协方差是没有除以(样本数-1)的
//如果使用COVAR_SCALE的话,那么计算出来的协方差是除以(样本数)
//所以在使用的使用,应该注意一下,需要使用的是除以(样本数)还是(样本数-1)
/*
m matrix is:
[1, 8, 4;
2, 9, 3;
1, 9, 4;
6, 8, 5]
mean matrix is:
[2.5, 8.5, 4]
covar matrix is:
[17, -2, 4;
-2, 1, -1;
4, -1, 2]
*/
void test_calcCovarMatrix()
{
	const int iRows = 4;
	const int iCols = 3;
	Mat m(iRows, iCols, CV_32FC1);

	m.at<float>(0, 0) = 1;
	m.at<float>(0, 1) = 8;
	m.at<float>(0, 2) = 4;

	m.at<float>(1, 0) = 2;
	m.at<float>(1, 1) = 9;
	m.at<float>(1, 2) = 3;

	m.at<float>(2, 0) = 1;
	m.at<float>(2, 1) = 9;
	m.at<float>(2, 2) = 4;

	m.at<float>(3, 0) = 6;
	m.at<float>(3, 1) = 8;
	m.at<float>(3, 2) = 5;

	Mat covar, mean;
	calcCovarMatrix(m, covar, mean, COVAR_NORMAL | COVAR_ROWS);
	cout << "m matrix is:\n" << m << endl;
	cout << "mean matrix is:\n" << mean << endl;
	cout << "covar matrix is:\n" << covar << endl;
	return;
}

//测试test_cartToPolar()
//将笛卡尔坐标转换为极坐标
/*
x coordinate is:
[1, 1, 0, -1, -1, -1, 0, 1]
y coordinate is:
[0, 1, 1, 1, 0, -1, -1, -1]
magnitude is:
[1, 1.4142135, 1, 1.4142135, 1, 1.4142135, 1, 1.4142135]
angle is:
[0, 44.990456, 90, 135.00955, 180, 224.99045, 270, 315.00955]
*/
void test_cartToPolar()
{
	const int iCols = 8;
	Mat x(1, iCols, CV_32FC1);
	Mat y(1, iCols, CV_32FC1);
	
	x.at<float>(0, 0) = 1;
	y.at<float>(0, 0) = 0;

	x.at<float>(0, 1) = 1;
	y.at<float>(0, 1) = 1;

	x.at<float>(0, 2) = 0;
	y.at<float>(0, 2) = 1;

	x.at<float>(0, 3) = -1;
	y.at<float>(0, 3) = 1;

	x.at<float>(0, 4) = -1;
	y.at<float>(0, 4) = 0;

	x.at<float>(0, 5) = -1;
	y.at<float>(0, 5) = -1;

	x.at<float>(0, 6) = 0;
	y.at<float>(0, 6) = -1;

	x.at<float>(0, 7) = 1;
	y.at<float>(0, 7) = -1;

	Mat mag, angle;
	//使用角度值进行表示
	//如果希望使用弧度制表示的话,那么将最后的flag设置为false即可
	cartToPolar(x, y, mag, angle, true);
	cout << "x coordinate is:\n" << x << endl;
	cout << "y coordinate is:\n" << y << endl;
	cout << "magnitude is:\n" << mag << endl;
	cout << "angle is:\n" << angle << endl;
	return;
}

//测试checkRange()
//bool checkRange(InputArray _src, bool quiet, Point* pt, double minVal, double maxVal)
//_src 输入的影像矩阵
//quiet 如果设置为false,那么超过范围的话,直接抛出异常;如果设置为true,那么函数结果返回false
//pt 如果不为NULL,那么返回第一个超过范围值的位置
//minVal 需要测试的最小值
//maxVal 需要测试的最大值
/*
m matrix is:
[1, 10, 100, 200, 150]
the matrix is [0,170)?: false
the first out of range location is:[3, 0]
*/
void test_checkRange()
{
	int iCols = 5;
	Mat m(1, iCols, CV_32FC1);
	m.at<float>(0) = 1;
	m.at<float>(1) = 10;
	m.at<float>(2) = 100;
	m.at<float>(3) = 200; 
	m.at<float>(4) = 150;
	cv::Point pos;
	//检测是够在[0,170)之间
	bool bRet = checkRange(m, true, &pos, 0, 170);
	cout << "m matrix is:\n" << m << endl;
	cout << "the matrix is [0,170)?:\t";
	if (bRet)
	{
		cout << "true" << endl;
	}
	else
	{
		cout << "false" << endl;
	}
	cout << "the first out of range location is:" << pos << endl;
	return;
}

//测试compare()
//void compare(InputArray src1, InputArray src2, OutputArray dst, int cmpop);
//src1 输入需要比较第一个源影像
//src2 输入需要比较第二个源影像
//dst 输出的比较影像 如果true的话,输出是255;不然的话,输出是0
//cmpop 比较标志 
//CMP_EQ ==
//CMP_GT >
//CMP_GE >=
//CMP_LT <
//CMP_LE <=
//CMP_NE !=
/*
src1 matrix is:
[0, 1, 2;
1, 2, 3;
2, 3, 4]
src2 matrix is:
[0, 1, 2;
1, 2, 3;
2, 2, 1]
compare equal is:
[255, 255, 255;
255, 255, 255;
255,   0,   0]
*/
void test_compare()
{
	const int iRows = 3;
	const int iCols = 3;
	Mat src1(iRows, iCols, CV_32FC1);
	Mat src2(iRows, iCols, CV_32FC1);
	Mat dst;
	for (int i=0;i<iRows;++i)
	{
		for (int j=0;j<iCols;++j)
		{
			src1.at<float>(i, j) = i + j;
			src2.at<float>(i, j) = i + j;
		}
	}
	//稍微变更一下src2中的值
	src2.at<float>(2, 2) = 1;
	src2.at<float>(2, 1) = 2;
	compare(src1, src2, dst, CMP_EQ);
	cout << "src1 matrix is:\n" << src1 << endl;
	cout << "src2 matrix is:\n" << src2 << endl;
	cout << "compare equal is:\n" << dst << endl;
	return;
}

//测试completeSymm()
//完成对称矩阵
//CV_EXPORTS_W void completeSymm(InputOutputArray mtx, bool lowerToUpper = false);
//mtx 输入输出矩阵
//lowerToUpper 如果为false的话,那么将上三角矩阵赋值到下三角矩阵
//如果为true的话, 那么需要将下三角矩阵赋值到上三角矩阵
/*
src matrix is:
[  0,   1,   2,   3;
0,   2,   3,   4;
0,   0,   4,   5;
0,   0,   0,   6]
dst matrix is:
[  0,   1,   2,   3;
1,   2,   3,   4;
2,   3,   4,   5;
3,   4,   5,   6]
*/
void test_completeSymm()
{
	const int iRows = 4;
	const int iCols = 4;
	Mat m(iRows, iCols, CV_8UC1,Scalar(0));
	for (int  i=0;i<iRows;++i)
	{
		for (int j=i;j<iCols;++j)
		{
			m.at<unsigned char>(i, j) = i + j;
		}
	}
	cout << "src matrix is:\n" << m << endl;
	completeSymm(m,false);
	cout << "dst matrix is:\n" << m << endl;
	return;
}

//测试convertScaleAbs()
//void convertScaleAbs(InputArray src, OutputArray dst,double alpha = 1, double beta = 0);
//公式为|alpha*src+beta|
//src 源影像
//dst 目标影像
/*
src matrix is:
[0, -1, -2, -3;
-1, -2, -3, -4;
-2, -3, -4, -5;
-3, -4, -5, -6]
dst matrix is:
[ 10,  12,  14,  16;
12,  14,  16,  18;
14,  16,  18,  20;
16,  18,  20,  22]
*/
void test_convertScaleAbs()
{
	const int iRows = 4;
	const int iCols = 4;
	Mat m(iRows, iCols, CV_32FC1);
	for (int i = 0; i < iRows; ++i)
	{
		for (int j = 0; j < iCols; ++j)
		{
			m.at<float>(i, j) = -(i + j);
		}
	}
	cout << "src matrix is:\n" << m << endl;
	Mat dst;
	//公式为
	//|m*2-10|
	convertScaleAbs(m, dst, 2, -10);
	cout << "dst matrix is:\n" << dst << endl;
	return;
}

//测试countNonZero()
//统计非0元素的个数
/*
src matrix is:
[0, 1, 2, 3;
0, 2, 3, 4;
0, 0, 4, 5;
0, 0, 0, 6]
matrix non zero is:
9
*/
void test_countNonZero()
{
	const int iRows = 4;
	const int iCols = 4;
	//建立一个上三角矩阵
	Mat m(iRows, iCols, CV_32FC1,Scalar(0));
	for (int i = 0; i < iRows; ++i)
	{
		for (int j = i; j < iCols; ++j)
		{
			m.at<float>(i, j) = i+j;
		}
	}
	cout << "src matrix is:\n" << m << endl;
	int nCount = countNonZero(m);
	cout << "matrix non zero is:\n" << nCount << endl;
	return;
}

//测试 dct
//CV_EXPORTS_W void dct(InputArray src, OutputArray dst, int flags = 0);
//src 输入的影像
//dst 输出影像
//由于影像必须是偶数,所以需要先优化影像的尺寸
size_t getOptimalDCTSize(size_t N) { return 2 * getOptimalDFTSize((N + 1) / 2); }
void test_dct()
{
	Mat src = imread("C:/Users/GuSheng/Desktop/标准测试图片/三国杀/58d379286a8da.jpg");
	//如果影像为NULL的话,直接返回
	if (src.empty())
	{
		return;
	}
	//将彩色影像转换为灰度影像
	cvtColor(src, src, CV_BGR2GRAY);
	//优化后的影像宽度
	int nOptWidth = getOptimalDCTSize(src.cols);
	int nOptHeight = getOptimalDCTSize(src.rows);
	int nExtWidth = (nOptWidth - src.cols) / 2;
	int nExtHeight = (nOptHeight - src.rows) / 2;
	//优化边界
	copyMakeBorder(src, src, nExtHeight, nExtHeight, nExtWidth, nExtWidth, BORDER_CONSTANT, Scalar(0));
	//显示源影像
	namedWindow("src", WINDOW_AUTOSIZE);
	imshow("src", src);
	
	//将类型转换为float类型,将其归一化到[0,1]之间的数据
	src.convertTo(src, CV_32F,1/255.0);
	Mat dst;
	//进行dft变换
	dct(src, dst);
	namedWindow("dct", WINDOW_AUTOSIZE);
	imshow("dct", dst);
	waitKey(0);
	return;
}

//测试 idct
//离散余弦反变换
void test_idct()
{
	Mat src = imread("C:/Users/GuSheng/Desktop/标准测试图片/三国杀/58d379286a8da.jpg");
	//如果影像为NULL的话,直接返回
	if (src.empty())
	{
		return;
	}
	//将彩色影像转换为灰度影像
	cvtColor(src, src, CV_BGR2GRAY);
	//优化后的影像宽度
	int nOptWidth = getOptimalDCTSize(src.cols);
	int nOptHeight = getOptimalDCTSize(src.rows);
	int nExtWidth = (nOptWidth - src.cols) / 2;
	int nExtHeight = (nOptHeight - src.rows) / 2;
	//优化边界
	copyMakeBorder(src, src, nExtHeight, nExtHeight, nExtWidth, nExtWidth, BORDER_CONSTANT, Scalar(0));
	//显示源影像
	namedWindow("src", WINDOW_AUTOSIZE);
	imshow("src", src);

	//将类型转换为float类型,将其归一化到[0,1]之间的数据
	src.convertTo(src, CV_32F, 1 / 255.0);
	Mat dst;
	//进行dft变换
	dct(src, dst);
	namedWindow("dct", WINDOW_AUTOSIZE);
	imshow("dct", dst);

	//低通滤波处理,将100行和100列之后的值设置为0,以达到平滑影像的目的
	for (int i=100;i<dst.rows;++i)
	{
		for (int j=100;j<dst.cols;++j)
		{
			dst.at<float>(i, j) = 0.0;
		}
	}
	//然后进行离散余弦函数的反变换
	Mat dst1;
	idct(dst, dst1);
	//将影像转换为8bits格式,缩放为255,设置范围为(0,255)之间,和之前对应的1/255.0相对应
	dst1.convertTo(dst1, CV_8U,255);
	namedWindow("dst1", WINDOW_AUTOSIZE);
	imshow("dst1", dst1);
	waitKey(0);
	return;
}

//测试dft 傅里叶变换
void test_dft()
{
	Mat src = imread("C:/Users/GuSheng/Desktop/标准测试图片/test1.jpg");
	if (src.empty())
	{
		//如果影像读取失败的话,直接返回
		return;
	}
	//转换为灰度影像
	cvtColor(src, src, CV_BGR2GRAY);
	//获取优化的傅里叶变换
	int iWidth = getOptimalDFTSize(src.cols);
	int iHeight = getOptimalDFTSize(src.rows);
	//重新组织影像
	copyMakeBorder(src, src, 0, 0, iHeight - src.rows, iWidth - src.cols, BORDER_CONSTANT, Scalar(0));
	//显示源影像
	namedWindow("src", WINDOW_AUTOSIZE);
	imshow("src", src);
	//组织傅里叶变换
	Mat plane[2] = { Mat_<float>(src),Mat::zeros(src.size(),CV_32FC1) };
	//合并影像--合并为复数影像
	Mat ComplexImg;
	merge(plane, 2, ComplexImg);
	//进行傅里叶变换
	dft(ComplexImg, ComplexImg);
	//分离通道
	split(ComplexImg, plane);
	magnitude(plane[0], plane[1], plane[0]);
	Mat mag=plane[0];//幅度值
	mag += Scalar::all(1);
	log(mag, mag);
	mag = mag(Rect(0, 0, mag.cols&-2, mag.rows&-2));
	//中心化处理
	int cx = mag.cols / 2;
	int cy = mag.rows / 2;
	Mat temp;
	Mat q0(mag, Rect(0, 0, cx, cy));
	Mat q1(mag, Rect(cx, 0, cx, cy));
	Mat q2(mag, Rect(0, cy, cx, cy));
	Mat q3(mag, Rect(cx, cy, cx, cy));

	q0.copyTo(temp);
	q3.copyTo(q0);
	temp.copyTo(q3);

	q1.copyTo(temp);
	q2.copyTo(q1);
	temp.copyTo(q2);
	//归一化为0-1
	normalize(mag, mag, 0, 1, NORM_MINMAX);
	//转换为8bits影像,乘以255 是为了归一化到[0,255]之间
	mag.convertTo(mag, CV_8U, 255);
	threshold(mag,mag,175,255,THRESH_BINARY);
	namedWindow("dft", WINDOW_AUTOSIZE);
	imshow("dft", mag);
	waitKey(0);
	return;
}

//测试idft
void test_idft()
{
	//读取源影像
	Mat src = imread("C:/Users/GuSheng/Desktop/标准测试图片/lena.jpg");
	if (src.empty())
	{
		//如果影像读取失败的话,直接返回
		return;
	}
	//转换为灰度影像
	cvtColor(src, src, CV_BGR2GRAY);
	//计算优化后的影像宽度和高度
	int iWidth = getOptimalDFTSize(src.cols);
	int iHeight = getOptimalDFTSize(src.rows);
	//重新整合影像
	copyMakeBorder(src, src, 0, 0, iWidth - src.cols, iHeight - src.rows, BORDER_CONSTANT, Scalar(0));
	//显示源影像
	namedWindow("src", WINDOW_AUTOSIZE);
	imshow("src", src);
	//组合影像
	Mat planes[] = { Mat_<float>(src),Mat::zeros(src.size(),CV_32FC1) };
	Mat magImage;
	merge(planes,2, magImage);
	//进行傅里叶比变换
	dft(magImage, magImage);
	//分割为实部和虚部部分
	split(magImage, planes);
	//对planes进行中心化处理
	planes[0] = planes[0](Rect(0, 0, planes[0].cols&-2, planes[0].rows&-2));
	planes[1] = planes[1](Rect(0, 0, planes[1].cols&-2, planes[1].rows&-2));
	//因为planes[0]影像储存和planes[1]的尺寸一定相同的,所以这里选择planes[0]
	int cx = planes[0].cols / 2;
	int cy = planes[0].rows / 2;
	//中心化 实数和虚数部分
	for (int i=0;i<2;++i)
	{
		Mat tmp;
		Mat q0 = planes[i](Rect(0, 0, cx, cy));
		Mat q1 = planes[i](Rect(cx, 0, cx, cy));
		Mat q2 = planes[i](Rect(0, cy, cx, cy));
		Mat q3 = planes[i](Rect(cx, cy, cx, cy));
		//中心化处理
		q0.copyTo(tmp);
		q3.copyTo(q0);
		tmp.copyTo(q3);

		q1.copyTo(tmp);
		q2.copyTo(q1);
		tmp.copyTo(q2);
	}
	//对数变换,为了显示
	Mat ShowImage;//为了显示而创建的影像,暂时先不动planes,因为后面我们要进行傅里叶的逆变换处理
	magnitude(planes[0], planes[1], ShowImage);
	ShowImage += Scalar::all(1);
	log(ShowImage, ShowImage);
	//归一化处理
	normalize(ShowImage, ShowImage, 0, 1, NORM_MINMAX);
	namedWindow("dft", WINDOW_AUTOSIZE);
	imshow("dft", ShowImage);

	//对频率域进行滤波处理
	//这里将频率域影像中心100*100的处理设置为0,也就是说低频部分过滤掉,高频部分进行保留,结果就是保留边缘部分
	//如果进行相反操作的话,那么效果就是平滑影像
// 	for (int i=0;i<2;++i)
// 	{
// 		//提取中心部分,设置为0
// 		Mat RImg = planes[i](Rect(cx - 50, cy - 50, 100, 100));
// 		RImg.setTo(Scalar(0));
// 	}
	//如果希望平滑的话
	for (int k=0;k<2;++k)
	{
		for (int i = 0; i < iHeight; ++i)
		{
			for (int j = 0; j < iWidth; ++j)
			{
				if (!((i > cx - 50) && (i < cx + 50) && (j > cy - 50) && j < cy + 50))
				{
					planes[k].at<float>(i, j) = 0;
				}
			}
		}
	}
	
	//反中心化处理
	for (int i = 0; i < 2; ++i)
	{
		Mat tmp;
		Mat q0 = planes[i](Rect(0, 0, cx, cy));
		Mat q1 = planes[i](Rect(cx, 0, cx, cy));
		Mat q2 = planes[i](Rect(0, cy, cx, cy));
		Mat q3 = planes[i](Rect(cx, cy, cx, cy));
		//中心化处理
		q0.copyTo(tmp);
		q3.copyTo(q0);
		tmp.copyTo(q3);

		q1.copyTo(tmp);
		q2.copyTo(q1);
		tmp.copyTo(q2);
	}
	//合并操作
	Mat ResultImg;
	merge(planes, 2, ResultImg);
	idft(ResultImg, ResultImg);
	//分割为实部通道和虚部通道
	split(ResultImg, planes);
	magnitude(planes[0], planes[1], planes[0]);
	//归一化处理
	normalize(planes[0], planes[0], 0, 1, NORM_MINMAX);
	planes[0].convertTo(planes[0], CV_8U, 255);
	namedWindow("idft", WINDOW_AUTOSIZE);
	imshow("idft", planes[0]);
	waitKey(0);
	return;
}

int main()
{
	//修改默认的随机数
	//RNG rng(time(NULL));
	//theRNG() = rng;
	test_dft();
	return 0;
}	

 说明1

DCT离散余弦变换

相当于低通滤波器,主要的信息(低频部分)主要集中在左上角,因此可以用来平滑影像;另外保存左上角的主要信息,可以用来影像压缩处理。 (保留影像的大小和左上角的信息)

源影像
DCT变换之后的结果

 

 

 

 

 

 

 

 

 

 

 

 

 

 

使用test_idct()例子,低通滤波之后的结果

 说明2

DFT变换(傅里叶变换)

源影像1
源影像2

 

 

 

 

 

 

 

 

 

 

 

DFT变换的结果1
DFT变换的结果2

 

 

 

 

 

 

 

 

 

 

 

DFT变换之后,二值化的影像1
DFT变换之后,二值化的影像2

 

 

 

 

 

 

 

 

 

 

 

进行傅里叶变换,中心化之后,低频部分在中心部分(主要的纹理信息),高频部分分布在四周(边缘,噪声等)。

从上述影像的傅里叶变换的结果可以看出影像有明显的旋转,可以通过houghline提取线,进行影像的校正

 3.IDFT变换(傅里叶逆变换)

源影像
DFT变换之后的结果

 

IDFT变换之后的结果

 从上图可以看出

由于高频部分的丢失,会造成振铃效应

### C++ OpenCV 常用函数及其示例 #### 图像读取与显示 `cv::imread()` `cv::imshow()` 是两个常用函数,分别用于加载图像显示图像。 ```cpp #include <opencv2/opencv.hpp> using namespace cv; int main() { // 使用 imread 函数加载图像 Mat srcImage = imread("image_path.jpg", IMREAD_COLOR); if (srcImage.empty()) { std::cout << "Error loading image!" << std::endl; return -1; } // 使用 imshow 函数显示图像 namedWindow("Original Image", WINDOW_AUTOSIZE); imshow("Original Image", srcImage); waitKey(0); // 等待按键输入 destroyAllWindows(); return 0; } ``` 此代码展示了如何通过 `cv::imread()` 加载一张彩色图片并使用 `cv::imshow()` 进行展示[^1]。 --- #### 直方图均衡化 `cv::equalizeHist()` 可以用来增强图像对比度。它适用于单通道灰度图像。 ```cpp Mat equalizedImage; equalizeHist(srcImage, equalizedImage); // 对灰度图像执行直方图均衡化 imshow("Equalized Image", equalizedImage); ``` 这段代码实现了对灰度图像的直方图均衡化操作,并将其结果显示出来[^1]。 --- #### 图像保存 `cv::imwrite()` 用于将处理过的图像保存到磁盘中。 ```cpp bool success = imwrite("output_image.png", equalizedImage); if (!success) { std::cerr << "Failed to write the image." << std::endl; } ``` 这里演示了如何利用 `cv::imwrite()` 将经过直方图均衡化的图像保存为 PNG 文件[^2]。 --- #### 边缘检测 Sobel 或 Canny 方法可以完成边缘提取任务。 ##### Sobel 检测器 ```cpp Mat sobelX, sobelY, magnitude; Sobel(grayImage, sobelX, CV_8U, 1, 0, 3); // X 方向梯度 Sobel(grayImage, sobelY, CV_8U, 0, 1, 3); // Y 方向梯度 magnitude(sobelX, sobelY, magnitude); // 计算幅值 imshow("Sobel Magnitude", magnitude); ``` ##### Canny 检测器 ```cpp Mat edges; Canny(grayImage, edges, 50, 150); // 参数分别为低阈值高阈值 imshow("Edges Detected", edges); ``` 这两种方法均能有效识别图像中的边界信息。 --- #### 凸包计算 对于形状分析场景下,可借助 `convexHull` 找出目标物体外部包裹线。 ```cpp std::vector<std::vector<Point>> contours; std::vector<Vec4i> hierarchy; findContours(binaryImage, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); // 寻找凸包 std::vector<std::vector<Point>> hull(contours.size()); for (size_t i = 0; i < contours.size(); ++i) { convexHull(Mat(contours[i]), hull[i], false); } // 绘制结果 Mat drawing = Mat::zeros(binaryImage.size(), CV_8UC3); for (size_t i = 0; i < contours.size(); ++i) { drawContours(drawing, contours, static_cast<int>(i), Scalar(255, 0, 0), 1, LINE_AA, hierarchy, INT_MAX); drawContours(drawing, hull, static_cast<int>(i), Scalar(0, 0, 255), 1, LINE_AA); } imshow("Convex Hulls", drawing); ``` 上述片段说明了怎样基于二值掩码找到轮廓以及对应的凸壳结构[^3]。 --- #### 物体检测(Haar Cascade) 为了实现特定模式匹配功能,比如人脸或者车牌定位,则需调用预训练好的分类器模型配合 `detectMultiScale` 接口工作。 ```cpp CascadeClassifier cascade; cascade.load("haarcascade_frontalface_default.xml"); std::vector<Rect> objects; cascade.detectMultiScale(imageGray, objects, 1.1, 3, 0 | CASCADE_SCALE_IMAGE, Size(30, 30)); for (const auto& obj : objects) { rectangle(imageColor, obj.tl(), obj.br(), Scalar(255, 0, 0), 2); } imshow("Detected Objects", imageColor); ``` 本部分介绍了 Haar 特征级联分类器的应用实例,可用于快速筛选感兴趣区域[^4]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值