赞
踩
opencv中子列的通道顺序是反过来的——BGR而不是RGB。很多情况下,因为内存足够大,可实现连续存储,因此,图像中的各行就能一行一行地连接起来,形成一个长行。连续存储有助于提升图像扫描速度,我们可以使用isContinuous()来判断矩阵是否是连续存储的。
若矩阵元素存储的是单通道像素,使用c或c++的无符号字符类型,那么像素可有256个不同值。
颜色空间缩减(color space reduction)的做法是:将现有颜色空间值除以某个输入值,以获得较少的颜色数。
简单的颜色空间缩减算法可由下面两步组成:
1.遍历图像矩阵的每一个像素;
2.对像素应用上述公式。
//首先建立一个mat型用于查表
Mat lookUpTable(1,256,CV_8U);
uchar*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)
计时函数:
getTickCount()函数返回CPU自某个事件以来走过的时钟周期数;
getTickFrequency()函数返回CPU一秒钟所走的时钟周期数。
double time0=static_cast<double>(getTickCount());//记录起始时间
//进行图像处理操作
time0=((double)getTickCount()-timeo)/getTickFrequency();
cout<<"此方法运行时间为:“<<time0<<"秒”<<endl;//输出运行时间
opencv中三种访问每个像素地方法:
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() { Mat srcImage=imread("1.jpg"); imshow("原图",srcImage); Mat dstImage; dstImage.create(srcImage.rows,srcImage.cols,srcImage.type());//效果图的大小、类型与原图片相同 //记录起始时间 double time0=static_cast<double>(getTickCount()); colorReduce(srcImage,dstImage,32); //计算运行时间并输出 time0=((double)getTickCount()-time0)/getTickFrequency(); cout<<"此方法运行时间为:"<<time0<<"秒"<<endl; imshow("效果图“,dstImage); waitKey(0); }
【一】用指针访问像素
void colorReduce(Mat & InputImage,Mat & outputImage,int div) { outputImage=inputImage.clone();//复制实参到临时变量 int rowNumber=outputImage.rows; int colNumber=outputImage.cols*outputImage.channels(); for(int i=0;i<rowNumber;i++) { uchar *data=outputImage.ptr<uchar>(i); for(int j=0;j<colNumber;j++) { data[j]=data[j]/div*div+div/2; } } }
Mat类有若干成员函数可以获取图像的属性。公有成员变量cols和rows给出了图像的宽和高,而成员函数channels()用于返回图像的通道数。灰度图的通道数为1,彩色图的通道数为3.
int colNumber=outputImage.cols*outputImage.channels();
Mat类提供了ptr函数可以得到图像任意行的首地址。ptr是一个模板函数,他返回第i行的首地址。
uchar *data=outputImage.ptr<uchar>(i);
【二】用迭代器操作像素
在迭代法中,所需要做的仅仅是获得图像矩阵的begin和end,然后增加迭代直至从begin到end。将*操作符添加在迭代指针前,即可访问当前指向二点内容。
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;
}
}
【三】动态地址计算
使用动态地址运算配合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; } } }
Mat类中的cols和rows给出了图像的宽和高。而成员函数at(int x,int y)可以用来存取图像元素,但是必须在编译期知道图像的数据类型。一定要确保指定的数据类型要和矩阵中的数据类型相符合,因为at方法本身不会对任何数据类型进行转换。
对于彩色图像,每个像素由三个部分构成:蓝色通道、绿色通道和红色通道(BGR)。对于一个包含彩色图像的Mat,会返回一个由三个8位数组成的向量,opencv将此类型的向量定义为Vec3b,即由三个unsigned char组成的向量。
image.at<Vec3b>(j,i)[channel]=value;
其中,索引值channel标明了颜色通道号。
感兴趣区域(ROI,region of interest)
定义ROI区域的两种方法:
1.使用矩形区域的Rect。它指定矩形的左上角坐标(构造函数的前两个参数)和矩形的长宽(构造函数的后两个参数)以定义一个矩形区域;
Mat imageROI;
imageROI=image(Rect(500,250,logo.cols,logo.rows));
2.指定感兴趣行或列的范围(Range)。Range是指从起始索引到终止索引(不包含终止索引)的一系列连续序列。cRange可以用来定义Range。
imageROI=image(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));
利用ROI将一幅画加到另一幅图的指定位置。通过一个图像淹没(mask),直接将插入处的像素设置为logo图像额像素值。
bool ROI_AddImage() { Mat srcImage1=imread("dota_pa.jpg"); Mat logoImage=imread("dota_logo.jpg"); if(!srcImage1.data) { printf("读取srcImage1错误~! \n"); return false; } if(!logoImage.data) { printf("读取logoImage错误~! \n"); return false; } Mat imageROI=srcImage1(Rect(200,250,logoImage.cols,logoImage.rows)); //加载掩膜(必须是灰度图) Mat mask=imread("dota_logo.jpg",0); //将掩膜复制到ROI logoImage.copyTo(imageROI,mask); namedWindow("<1>利用ROI实现图像叠加示例窗口"); imshow("<1>利用ROI实现图像叠加示例窗口",srcImage1); return true: }
先载入两张jpg图片,然后定义一个Mat类型的imageROI,并使用Rect设置其感兴趣区域为srcImage1中的一块区域,将imageROI和srcImage1关联起来。
线性混合操作是一种典型的二元(两个输入)的像素操作。
主要运用OpenCV中addWeighted函数。
void(InputArray src1,double alpha,InputArray src2,double beta,double gamma,OutputArray dst,int dtype=-1);
第一个参数,InputArray类型的是src1,表示需要加权的第一个数组,常常填一个Mat;
第二个参数,double类型的alpha,表示第一个数组的权重;
第三个参数,InputArray类型的src2,表示第二个数组,它需要和第一个数组拥有相同的尺寸和通道数;
第四个参数,double类型的beta,表示第二个数组的权重值;
第五个参数,double类型的gamma,一个加到权重总和上的标量值。
第六个参数,OutputArray类型的dst,输出的数组,它和输入的两个数组拥有相同的尺寸和通道数;
第七个参数,int类型的dtype,输出阵列的可选深度,有默认值-1。当两个输入数组具有相同的深度时,这个参数设置为-1(默认值),即等同于src1.depth()。
dst=src1[I]*alpha+src2[I]*beta+gamma;
其中I是多维数组元素的索引值。当输出数组的深度位CV_32S时,这个函数不适用,这时候会内存溢出或者算出的结果不对。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。