标签:
代码都是源于毛星云的《opencv3.0编程入门》
1、计时函数
getTickCount()和getTickFrequency()函数;
getTickCount()函数返回CPU自某个事件以来走过的时钟周期;
getTickFrequency()函数 返回CPU一秒所走的周期数;
事例:
double time0=static_cast< double>(getTickCount()); //记录起始时间
// 事件的处理操作
time0=((double)getTickCount()-time0)/getTickFrequency();
cout<<"此方法的运行时间为:"<< time0<<"秒"<< endl;
2、访问图像像素中的三类方法:
1)【方法一】指针访问:C操作符[ ];
2)【方法二】迭代器iterator;
3)【方法三】动态地址计算;
主程序代码:
#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.jpg");
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);
}
【方法一】指针访问: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;
// ----------【处理结束】---------------------
} //行处理结束
}
}
Mat类中:公有成员变量cols和rows给出了图像的宽和高;成员函数channels()用于返回图像的通道数;
每行的像素个数:`int colNumber=outputImage.cols*outputImage.channels();
Mat 类提供了ptr函数可以得到图像任意行的首地址。ptr是一个模板函数,返回第i行的首地址;
unchar* data =outputImage.ptr< uchar>(i);//获取第i行的首地址;
【方法二】迭代器iterator;
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;
// ------------------------【处理结束】----------------------------
}
}
在迭代器中我们需要的仅仅是获取图像矩阵的begin和end,将*操作符添加在迭代器指针前,即可访问当前指向的内容;
3)【方法三】动态地址计算;
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; //红是通道
// -------------------------【处理结束】----------------------------
} // 行处理结束
}
}
动态地址运算配合at方法的colorReduce函数;
3、分离颜色通道、多通道图像的混合
1)通道分离:split( )函数;
split( )函数的C++版本有两个原型;分别是:
void split(const Mat& src,Mat* mvbegin);
void split(InputArray m,OutputArrayOfArrays mv);
第一个参数,InputArray类型的m或者const Mat&类型的src,是需要进行分离的多通道数组;
第二个参数,OutputArrayOfArrays类型的mv,填函数的输出数组或者输出的vector容器。
我们一起看一个示例。
vector<Mat> channels;
Mat imageBlueChannel;
Mat imageGreenChannel;
Mat imageRedChannel;
srcImage4= imread("dota.jpg");
// 把一个 3 通道图像转换成 3 个单通道图像
split(srcImage4,channels);//分离色彩通道
imageBlueChannel = channels.at(0);
imageGreenChannel = channels.at(1);
imageRedChannel = channels.at(2);
上面的代码先做了相关的类型声明,然后把载入的 3 通道图像转换成 3 个单通道图像,放到vector类型的 channels 中,接着进行引用赋值。
根据 OpenCV 的 BGR 色彩空间(Blue、Green、Red,蓝绿红),其中 channels.at(0)就表示引用取出 channels 中的蓝色分量,channels.at(1)就表示引用取出 channels 中的绿色色分量,channels.at(2)就表示引用取出 channels 中的红色分量。
将一个多通道数组分离成几个单通道数组的 split()函数的内容大概就是以上这些了,下面我们来看一下和它关系密切的 merge()函数。
2)通道合并:merge( )函数;
依然是一个示例,综合了 split()函数和 merge()函数的使用,先将图像的通道进行拆分,再将通道合并。具体代码如下所示。
//定义一些 Mat 对象
Mat srcImage=imread("1.jpg");
Mat imageBlueChannel, imageGreenChannel, imageRedChannel,mergeImage;
//定义 Mat 向量容器保存拆分后的数据
vector<Mat> channels;
//通道的拆分
split(srcImage,channels);
//提取三色的通道的数据
imageBlueChannel = channels.at(0);
imageGreenChannel = channels.at(1);
imageRedChannel = channels.at(2);
//对拆分的通道数据合并
merge(channels,mergeImage);
//显示最终的合并效果
imshow("mergeImage",mergeImage);
一对做相反操作的 split()函数和 merge()函数和用法就是这些。另外提一点,如果我们需要从多通道数组中提取出特定的单通道数组,或者说实现一些复杂的通道组合,可以使用 mixChannels()函数。
以其中的蓝色通道为例:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
Mat srcImage;
Mat logoImage;
vector<Mat> channels;
Mat imageBlueChannel;
Mat imageGreenChannel;
Mat imageRedChannel;
//=================【蓝色通道部分】=================
// 【1】读入图片
logoImage = imread("dota_logo.jpg", 0);
srcImage = imread("dota_jugg.jpg");
if (!logoImage.data) { printf("Oh,no,读取logoImage错误~! \n"); return false; }
if (!srcImage.data) { printf("Oh,no,读取srcImage错误~! \n"); return false; }
//【2】把一个3通道图像转换成3个单通道图像
split(srcImage, channels);//分离色彩通道
//【3】将原图的蓝色通道引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
imageBlueChannel = channels.at(0);
//【4】将原图的蓝色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageBlueChannel中。简单讲就是原图的蓝色通道加上了logo替换了原始的蓝色通道。
addWeighted(imageBlueChannel(Rect(500, 250, logoImage.cols, logoImage.rows)), 1.0,
logoImage, 0.5, 0, imageBlueChannel(Rect(500, 250, logoImage.cols, logoImage.rows)));
//【5】将三个单通道重新合并成一个三通道
merge(channels,srcImage);
//【6】显示效果图
namedWindow(" <1>游戏原画+logo蓝色通道");
imshow(" <1>游戏原画+logo蓝色通道", srcImage);
waitKey(0);
return 0;
}
标签:
原文地址:http://blog.csdn.net/qq_29828623/article/details/51983226