2022-5-8:OpenCV入门(四)core组件进阶

1.LUT函数:Look up table

Mat lookUpTable(1,256,CV_8U);
u从三个都说副高fdffffDdqqqdqddq		FQFQ2Q2W	GW	 问对方成为亲卫队请问我去问驱蚊器委屈委屈强强        

  
   char* p = lookUpTable.data;
for(int i = 0 ; i < 256 ; ++i)
	p[i] = table[i];

//然后调用函数(I是输入 J是输出):
for (int i = 0; i < times; ++i)
	LUT(I, lookUpTable, J);

2.计时函数:getTickCount()和getTickFrequency()

getTickCount()返回CPU自某个事件以来走过的时钟周期数
getTickFrequency()返回CPU一秒钟所走的时钟周期数

double time0 = static_cast<double>(getTickCount());//记录起始时间
//进行图像处理操作。。。。。
time0 = ((double)getTickCount() - time0)/getTickFrequency();
cout<<"此方法运行事件:"<<time0<<"秒"<<endl;//输出运行时间

3.访问图像中像素的三类方法:

方法一 指针访问:C操作符[];
方法二 迭代器iterator
方法三 动态地址计算

#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <iostream>  
using namespace std;
using namespace cv;

void colorReduce(Mat& inputImage, Mat& outputImage, int div);
int main()
{
	//【1】创建原始图并显示
	Mat srcImage = imread("1.bmp",1);
	imshow("原始图像", srcImage);
	//【2】按原始图的参数规格来创建创建效果图
	Mat dstImage;
	dstImage.create(srcImage.rows, srcImage.cols, srcImage.type());//效果图的大小、类型与原图片相同 
	//【3】记录起始时间
	double time0 = static_cast<double>(getTickCount());
	//【4】调用颜色空间缩减函数
	colorReduce(srcImage, dstImage, 32);
	//【5】计算运行时间并输出
	time0 = ((double)getTickCount() - time0) / getTickFrequency();
	cout << "\t此方法运行时间为: " << time0 << "秒" << endl;  //输出运行时间
	//【6】显示效果图
	imshow("效果图", dstImage);
	waitKey(0);
}
//---------------------------------【colorReduce( )函数】---------------------------------
//          描述:使用【指针访问:C操作符[ ]】方法版的颜色空间缩减函数
//----------------------------------------------------------------------------------------------
void colorReduce(Mat& inputImage, Mat& outputImage, int div)
{
	//参数准备
	outputImage = inputImage.clone();  //拷贝实参到临时变量
	int rowNumber = outputImage.rows;  //行数
	int colNumber = outputImage.cols * outputImage.channels();  //列数 x 通道数=每一行元素的个数

	//双重循环,遍历所有的像素值
	for (int i = 0; i < rowNumber; i++)  //行循环
	{
		uchar* data = outputImage.ptr<uchar>(i);  //获取第i行的首地址
		for (int j = 0; j < colNumber; j++)   //列循环
		{
			// ---------【开始处理每个像素】-------------     
			data[j] = data[j] / div * div + div / 2;
			//*data++ = *data / div * div + div / 2;//也可以写成这样
	// ----------【处理结束】---------------------
		}  //行处理结束
	}
}
//-------------------------------------【colorReduce( )函数】-----------------------------
//		描述:使用【迭代器】方法版的颜色空间缩减函数
//----------------------------------------------------------------------------------------------
void colorReduce(Mat& inputImage, Mat& outputImage, int div)  
{  
	//参数准备
	outputImage = inputImage.clone();  //拷贝实参到临时变量
	//获取迭代器
	Mat_<Vec3b>::iterator it = outputImage.begin<Vec3b>();  //初始位置的迭代器
	Mat_<Vec3b>::iterator itend = outputImage.end<Vec3b>();  //终止位置的迭代器

	//存取彩色图像像素
	for(;it != itend;++it)  
	{  
		// ------------------------【开始处理每个像素】--------------------
		(*it)[0] = (*it)[0]/div*div + div/2;  
		(*it)[1] = (*it)[1]/div*div + div/2;  
		(*it)[2] = (*it)[2]/div*div + div/2;  
		// ------------------------【处理结束】----------------------------
	}  
} 
//----------------------------------【colorReduce( )函数】-------------------------------
//          描述:使用【动态地址运算配合at】方法版本的颜色空间缩减函数
//----------------------------------------------------------------------------------------------
void colorReduce(Mat& inputImage, Mat& outputImage, int div)  
{  
	//参数准备
	outputImage = inputImage.clone();  //拷贝实参到临时变量
	int rowNumber = outputImage.rows;  //行数
	int colNumber = outputImage.cols;  //列数

	//存取彩色图像像素
	for(int i = 0;i < rowNumber;i++)  
	{  
		for(int j = 0;j < colNumber;j++)  
		{  	
			// ------------------------【开始处理每个像素】--------------------
			outputImage.at<Vec3b>(i,j)[0] =  outputImage.at<Vec3b>(i,j)[0]/div*div + div/2;  //蓝色通道
			outputImage.at<Vec3b>(i,j)[1] =  outputImage.at<Vec3b>(i,j)[1]/div*div + div/2;  //绿色通道
			outputImage.at<Vec3b>(i,j)[2] =  outputImage.at<Vec3b>(i,j)[2]/div*div + div/2;  //红是通道
			// -------------------------【处理结束】----------------------------
		}  // 行处理结束     
	}  
}  
``
## 4.ROI(region of interest):感兴趣区域

```cpp
	Mat imageROI;
	//方法一
	imageROI = srcImage(Rect(200, 250, logoImage.cols, logoImage.rows));
	//方法二
	//imageROI= srcImage4(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));

5.分离颜色通道、多通道图像混合

通道分离:split函数
通道合并:merge函数

vector<Mat> channels;
split(srcImage, channels);//分离色彩通道
Mat imageBlueChannel = channels.at(0);
Mat imageGreenChannel = channels.at(1);
Mat imageRedChannel = channels.at(2);
merge(channels, srcImage);//将三个单通道重新合并成一个三通道

6.图像对比度、亮度值调整

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace std;
using namespace cv;

static void ContrastAndBright(int, void*);

int g_nContrastValue; //对比度值
int g_nBrightValue;  //亮度值
Mat g_srcImage, g_dstImage;

int main()
{
	//改变控制台前景色和背景色
	system("color 2F");

	// 读入用户提供的图像
	g_srcImage = imread("1.bmp");
	if (!g_srcImage.data) { printf("读取g_srcImage图片错误~! \n"); return false; }
	g_dstImage = Mat::zeros(g_srcImage.size(), g_srcImage.type());

	//设定对比度和亮度的初值
	g_nContrastValue = 80;
	g_nBrightValue = 80;

	//创建窗口
	namedWindow("【效果图窗口】", 1);

	//创建轨迹条
	createTrackbar("对比度:", "【效果图窗口】", &g_nContrastValue, 300, ContrastAndBright);
	createTrackbar("亮   度:", "【效果图窗口】", &g_nBrightValue, 200, ContrastAndBright);

	//调用回调函数
	ContrastAndBright(g_nContrastValue, 0);
	ContrastAndBright(g_nBrightValue, 0);

	//输出一些帮助信息
	cout << endl << "\t运行成功,请调整滚动条观察图像效果\n\n"
		<< "\t按下“q”键时,程序退出\n";

	//按下“q”键时,程序退出
	while (char(waitKey(1)) != 'q') {}
	return 0;
}


//-----------------------------【ContrastAndBright( )函数】------------------------------------
//	描述:改变图像对比度和亮度值的回调函数
//-----------------------------------------------------------------------------------------------
static void ContrastAndBright(int, void*)
{

	// 创建窗口
	namedWindow("【原始图窗口】", 1);

	// 三个for循环,执行运算 g_dstImage(i,j) = a*g_srcImage(i,j) + b
	for (int y = 0; y < g_srcImage.rows; y++)
	{
		for (int x = 0; x < g_srcImage.cols; x++)
		{
			for (int c = 0; c < 3; c++)
			{
				g_dstImage.at<Vec3b>(y, x)[c] = saturate_cast<uchar>((g_nContrastValue * 0.01) * (g_srcImage.at<Vec3b>(y, x)[c]) + g_nBrightValue);
			}
		}
	}
	// 显示图像
	imshow("【原始图窗口】", g_srcImage);
	imshow("【效果图窗口】", g_dstImage);
}

在这里插入图片描述在这里插入图片描述

7.离散傅里叶变换

void dft(InputArray src, OutputArray dst, int flags=0, int nonzeroRows=0)//第一个参数为输入矩阵;第二个参数为运算结果;第三个参数为转换的标识符(下表);第四个参数为想要处理的那一行值,函数会假设只有输入矩阵的第一个非零行包含非零元素。

在这里插入图片描述

int getOptimalDFTSize(int vecsize)//返回给定向量尺寸的DFT最优尺寸大小
void copyMakeBorder(InputArray src, OutputArray dst, int top, int bottom, int left, int right, int borderType, const Scalar&value=Scalar() )
//扩充图像边界
//第一个参数为输入图像;第二个参数为输出图像;第三到第六个参数:需要在四个方向边界扩充的像素数;第七个参数为边界类型,常用为BORDER_CONSTANT;第八个参数为const Scalar&类型的value,有默认值Scalar()。
void magnitude(InputArray x,InputArray y,OutputArray magnitude)
//计算二维矢量的幅值
//第一个参数为浮点型X坐标值,实部;第二个参数为浮点型Y坐标值,虚部;第三个参数为输出的幅值
//X和Y的平方和再开根号
void log(InputArray src, OutputArray dst)
//计算自然对数
void normalize(InputArray src, OutputArray dst, double alpha=1,double beta=0, int norm_type=NORM_L2, int dtype=-1, InputArray mask =noArray())
//矩阵归一化
//第一个参数为输入图像;第二个参数为输出图像;第三个参数为归一化后的最大值,第四个参数为归一化后的最小值;第五个参数为归一化类型;第六个参数取负值时,输出矩阵和src有同样的类型,否则有同样的通道数;第七个参数为可选的操作掩膜。
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace cv;

int main()
{

	//【1】以灰度模式读取原始图像并显示
	Mat srcImage = imread("1.bmp", 0);
	if (!srcImage.data) { printf("读取图片错误,请确定目录下是否有imread函数指定图片存在~! \n"); return false; }
	imshow("原始图像", srcImage);


	//【2】将输入图像延扩到最佳的尺寸,边界用0补充
	int m = getOptimalDFTSize(srcImage.rows);
	int n = getOptimalDFTSize(srcImage.cols);
	//将添加的像素初始化为0.
	Mat padded;
	copyMakeBorder(srcImage, padded, 0, m - srcImage.rows, 0, n - srcImage.cols, BORDER_CONSTANT, Scalar::all(0));

	//【3】为傅立叶变换的结果(实部和虚部)分配存储空间。
	//将planes数组组合合并成一个多通道的数组complexI
	Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) };
	Mat complexI;
	merge(planes, 2, complexI);

	//【4】进行就地离散傅里叶变换
	dft(complexI, complexI);

	//【5】将复数转换为幅值,即=> log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))
	split(complexI, planes); // 将多通道数组complexI分离成几个单通道数组,planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
	magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude  
	Mat magnitudeImage = planes[0];

	//【6】进行对数尺度(logarithmic scale)缩放
	magnitudeImage += Scalar::all(1);
	log(magnitudeImage, magnitudeImage);//求自然对数

	//【7】剪切和重分布幅度图象限
	//若有奇数行或奇数列,进行频谱裁剪      
	magnitudeImage = magnitudeImage(Rect(0, 0, magnitudeImage.cols & -2, magnitudeImage.rows & -2));
	//重新排列傅立叶图像中的象限,使得原点位于图像中心  
	int cx = magnitudeImage.cols / 2;
	int cy = magnitudeImage.rows / 2;
	Mat q0(magnitudeImage, Rect(0, 0, cx, cy));   // ROI区域的左上
	Mat q1(magnitudeImage, Rect(cx, 0, cx, cy));  // ROI区域的右上
	Mat q2(magnitudeImage, Rect(0, cy, cx, cy));  // ROI区域的左下
	Mat q3(magnitudeImage, Rect(cx, cy, cx, cy)); // ROI区域的右下
	//交换象限(左上与右下进行交换)
	Mat tmp;
	q0.copyTo(tmp);
	q3.copyTo(q0);
	tmp.copyTo(q3);
	//交换象限(右上与左下进行交换)
	q1.copyTo(tmp);
	q2.copyTo(q1);
	tmp.copyTo(q2);

	//【8】归一化,用0到1之间的浮点值将矩阵变换为可视的图像格式
	//此句代码的OpenCV3版为:
	normalize(magnitudeImage, magnitudeImage, 0, 1, NORM_MINMAX);

	//【9】显示效果图
	imshow("频谱幅值", magnitudeImage);
	waitKey();

	return 0;
}

在这里插入图片描述在这里插入图片描述

8.输入输出XML和YAML文件

一. XML、YAML文件的打开

  1. 文件写操作
//第一种
FileStorage fs
fs.open("abs.xml",FileStorage::WRITE);
//第二种
FileStorage fs("abs.xml",FileStorage::WRITE);
  1. 文件读操作
//第一种
FileStorage fs
fs.open("abs.xml",FileStorage::READ);
//第二种
FileStorage fs("abs.xml",FileStorage::READ);

二. 进行文件读写操作

  1. 文本和数字的输入和输出
//写入文件
fs << "iterationNr" << 100;
//读取文件
int itNr;
fs["iterationNr"] >> itNr;
itNr = (int) fs["iterationNr"];
  1. OpenCV数据结构的输入和输出
//数据结构的初始化
Mat R = Mat_<uchar>::eye(3,3),
Mat T = Mat_<double>::zeros(3,1);
//向 Mat中写入数据
fs << "R" << R;
fs << "T" << T;
//从 Mat中读取数据
fs ["R"] << R;
fs ["T"] >> T;

三. vector(arrays)和maps的输入和输出

对于vector结构输入和输出,要在第一个元素之前加上"[“,最后一个元素之前加上”]"。

fs << "strings" << "[";//开始读入string文本序列
fs << "imagel.jpg" << "Awesomeness" <<"baboon.jpg";
fs << "]";//关闭序列

对于map结构,替换成“{ }”

fs << "Mapping" ;//开始读入Mapping文本序列
fs << "{" << "One" << 1;
fs <<"Twp" << 2 << "}";//关闭序列

在这里插入图片描述
四、文件关闭

fs.release();

文件写入示例

#include "opencv2/opencv.hpp"  
#include <time.h>  
using namespace cv;

int main()
{
	//初始化
	FileStorage fs("test.yaml", FileStorage::WRITE);

	//开始文件写入
	fs << "frameCount" << 5;
	time_t rawtime; time(&rawtime);//获取time_t类型的当前时间
	/*用localtime将time_t表示的时间转换为没有经过时区转换的UTC时间
	 然后再用asctime转换为我们常见的格式 Fri Jan 11 17:25:24 2008
	*/
	fs << "calibrationDate" << asctime(localtime(&rawtime));
	Mat cameraMatrix = (Mat_<double>(3, 3) << 1000, 0, 320, 0, 1000, 240, 0, 0, 1);
	Mat distCoeffs = (Mat_<double>(5, 1) << 0.1, 0.01, -0.001, 0, 0);
	fs << "cameraMatrix" << cameraMatrix << "distCoeffs" << distCoeffs;
	fs << "features" << "[";
	for (int i = 0; i < 3; i++)
	{
		int x = rand() % 640;
		//一般性:rand() % (b-a+1)+ a;就表示ab之间的一个随机整数。
		int y = rand() % 480;
		uchar lbp = rand() % 256;

		fs << "{:" << "x" << x << "y" << y << "lbp" << "[:";
		for (int j = 0; j < 8; j++)
			fs << ((lbp >> j) & 1);
		fs << "]" << "}";
	}
	fs << "]";
	fs.release();

	printf("\n文件读写完毕,请在工程目录下查看生成的文件~");
	getchar();

	return 0;

文件读取示例

#include "opencv2/opencv.hpp"  
#include <time.h>  
using namespace cv;
using namespace std;

int main()
{
	//改变console字体颜色
	system("color 6F");

	//初始化
	FileStorage fs2("test.yaml", FileStorage::READ);

	// 第一种方法,对FileNode操作
	int frameCount = (int)fs2["frameCount"];

	std::string date;
	// 第二种方法,使用FileNode运算符> > 
	fs2["calibrationDate"] >> date;

	Mat cameraMatrix2, distCoeffs2;
	fs2["cameraMatrix"] >> cameraMatrix2;
	fs2["distCoeffs"] >> distCoeffs2;

	cout << "frameCount: " << frameCount << endl
		<< "calibration date: " << date << endl
		<< "camera matrix: " << cameraMatrix2 << endl
		<< "distortion coeffs: " << distCoeffs2 << endl;

	FileNode features = fs2["features"];
	FileNodeIterator it = features.begin(), it_end = features.end();
	int idx = 0;
	std::vector<uchar> lbpval;

	//使用FileNodeIterator遍历序列
	for (; it != it_end; ++it, idx++)
	{
		cout << "feature #" << idx << ": ";
		cout << "x=" << (int)(*it)["x"] << ", y=" << (int)(*it)["y"] << ", lbp: (";
		// 我们也可以使用使用filenode > > std::vector操作符很容易的读数值阵列
		(*it)["lbp"] >> lbpval;
		for (int i = 0; i < (int)lbpval.size(); i++)
			cout << " " << (int)lbpval[i];
		cout << ")" << endl;
	}
	fs2.release();

	//程序结束,输出一些帮助文字
	printf("\n文件读取完毕,请输入任意键结束程序~");
	getchar();

	return 0;
}

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值