最近一直在更新,想说一下自己写这篇博客的目的在于应用,让你通过简单的看OpenCV的一些函数原型,就能立马去使用这个函数。
1、图像的拷贝和深层次复制—copyTo()和clone()
(1)、copyTo() 方法也是深拷贝,但是会不会去申请新的内存空间,取决于dst矩阵头中的大小信息是否与src一至,若一致则只深拷贝并不申请新的空间,否则先申请空间后再进行拷贝.注意:评判的准则是,大小一不一致
(2)、clone 是最简单的深复制方法,在使用这个方法的时候,会在内存中申请新的空间
用法:
Mat A = Mat::ones(4,5,CV_32F);
Mat B = A.clone() //clone 是完全的深拷贝,在内存中申请新的空间,与A独立
Mat C;
A.copyTo(C) //此处的C矩阵大小与A大小不一致,则申请新的内存空间,并完成拷贝,等同于clone()
Mat D = A.col(1);
A.col(0).copyTo(D); //此处D矩阵大小与A.col(0)大小一致,因此不会申请空间,而是直接进行拷贝,
相当于把A的第1列赋值给第二列。
2、saturate_cast( )方法
saturate_cast< uchar > : 此处为溢出保护,此处相当于在对数值进行剪切,使得只保留自己规定范围内的数值。
比如在这里, 溢出保护的范围我们定的是 <uchar>
因此,saturate_cast<uchar>( )方法就会对括号里面的数值进行剪切
(1)、当 (***) > 255时,赋值为255;
(2)、当 (***) < 0时,赋值为0;
3、setTo( ) 函数的使用
首选,setTo( )函数的原型是:Mat& setTo(InputArray value, InputArray mask=noArray());
解析:
1、功能:把矩阵mask中元素不为0的点全部变为value值;
2、当默认不添加mask的时候,表明mask是一个与原图尺寸大小一致的且元素值全为非0的矩阵,因此不加mask的时候,会将原矩阵的像素值全部赋值为value;
4、Scalar( )函数的使用
Scalar是一个由长度为4的数组作为元素构成的结构体,Scalar最多可以存储四个值,没有提供的值默认是0。
e.g. Scalar(1,2) 当用到的时候,就会在相应的像素里面赋值两个通道,里面数值为:(1,2)。
5、图像的简单运算之图像相加函数 addWeighted( )
首先来看一下,官方给的函数原型
void addWeighted(InputArray src1, double alpha, InputArray src2,
double beta, double gamma, OutputArray dst, int dtype = -1);
解析: src1 和src2 就是两个输入图片,dst 是最后相加得到的目标图片, 其中 alpha、beta和gamma这几个参数是表示相应的权值,具体如下:
(1)、alpha – Weight for the first array elements.
(2)、beta – Weight for the second array elements.
(3)、gamma – Scalar added to each sum.
(4)、dtype – Optional depth of the destination array. When both input arrays have the same
(5)、The function addWeighted calculates the weighted sum of two arrays as follows:
(6)、dst(I) = saturate(src1(I) alpha + src2(I) beta + gamma) ===> dst = src1*alpha + src2*beta + gamma
6、分割图像通道 split( )函数和 merge( )函数
首先来看一下,官方给的函数原型
void split(InputArray m, OutputArrayOfArrays mv);
解析: m:表示的是输入的图像,mv:表示的是,创建的一个三通道向量。
注意:
(1)、使用这个函数的时候,首先应该建立一个 三通道向量
e.g. vector<Mat> planes;
(2)、然后才能执行此函数操作:
split(image,planes )
(3)、此时后就可以在得到的三通道向量planes里面进行相关的操作,比如,将一幅图片只加到 蓝色通道
e.g planes[0] += image2 ;
(4)、最后要想查看效果的话,就需要进行合成操作,在这里使用到函数: merge( )
e.g merge(planes,result) ;
result 里面就是,你所得到的图像
7、关于图像重映射的 remap( )函数
首先来看一下,官方给的函数原型:
void remap( InputArray src, OutputArray dst,
InputArray map1, InputArray map2,
int interpolation, int borderMode = BORDER_CONSTANT,
const Scalar& borderValue = Scalar());
解析:
- src: 源图像
- dst: 目标图像,与 src 相同大小
- map1: x坐标
- map2: y坐标
- interpolation: 表示插值方法
- borderMode:表示边界插值类型
- borderValue:表示插值数值
8、OpenCV 中范数求解函数 norm
首先来看一下,官方给的函数原型:
double norm(InputArray src1, InputArray src2,
int normType = NORM_L2, InputArray mask = noArray());
解析:
- src1 是指输入的第一个向量
- src2 是指输入的第二个向量
- normType 是指的所求范数类型,默认为 NORM_L2 【欧几里得范数,俗称 2范数】
9、帧差法 absdiff( )函数
首先来看一下,官方给的函数原型:
void absdiff(InputArray src1, InputArray src2, OutputArray dst);
解析: 首先这个函数可计算 当前帧与背景之差的绝对值,也就是说,我们可以认为场景大多数情况下是不变的,而只有前景(被跟踪目标)会运动,这样就可以建立背景模型,通过比较当前帧和背景模型,就能轻松的跟踪目标运动情况了
- src1 是第一个原数组
- src2 是第二个原数组
- dst 是 求差 之后得到的数组
10、Threshold( ) 函数 // 输出二直图像(第四个参数和第五个参数有关)
首先来看一下,官方给的函数原型:
double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)
====> 这个函数主要的作用是:通过遍历灰度图中的点,将图像像素进行二值化,处理过后的图片只有二种色值
参数信息:
- 第一个参数,InputArray类型的src,输入数组,填单通道 , 8或32位浮点类型的Mat即可。
- 第二个参数,OutputArray类型的dst,函数调用后的运算结果存在这里,即这个参数用于存放输出结果,且和第 一个参数中的Mat变量有一样的尺寸和类型。
- 第三个参数,double类型的thresh,阈值的具体值。
- 第四个参数,double类型的maxval,当第五个参数阈值类型type取 THRESH_BINARY
或THRESH_BINARY_INV阈值类型时的最大值. - 第五个参数,int类型的type,阈值类型,。
- 其它参数很好理解,我们来看看第五个参数,第五参数有以下几种类型
- 0: THRESH_BINARY 当前点值大于阈值时,取Maxval,也就是第四个参数,下面再不说明,否则设置为0
- 1: THRESH_BINARY_INV 当前点值大于阈值时,设置为0,否则设置为Maxval
- 2: THRESH_TRUNC 当前点值大于阈值时,设置为阈值,否则不改变
- 3: THRESH_TOZERO 当前点值大于阈值时,不改变,否则设置为0
- 4: THRESH_TOZERO_INV 当前点值大于阈值时,设置为0,否则不改变
10、floodFill( ) 函数 [ 满水填充算法 ]—寻找颜色接近的连续区域
首先来看一下,官方给的函数原型:
int cv::floodFill( InputOutputArray _image,
InputOutputArray _mask,
Point seedPoint, /// 漫水填充起始点
Scalar newVal, /// 重绘区域的新值
Rect* rect = 0,
Scalar loDiff = Scalar(),
Scalar upDiff = Scalar(),
int flags = 4 )
- 第一个参数,InputOutputArray类型的image, 输入/输出1通道或3通道,8位或浮点图像,具体参数由之后的参数具体指明。
- 第二个参数,InputOutputArray类型的mask,这是第二个版本的floodFill独享的参数,表示操作掩模,。它应该为单通道、8位、长和宽上都比输入图像image大两个像素点的图像。第二个版本的floodFill需要使用以及更新掩膜,所以这个mask参数我们一定要将其准备好并填在此处。需要注意的是,漫水填充不会填充掩膜mask的非零像素区域。例如,一个边缘检测算子的输出可以用来作为掩膜,以防止填充到边缘。同样的,也可以在多次的函数调用中使用同一个掩膜,以保证填充的区域不会重叠。另外需要注意的是,掩膜mask会比需填充的图像大,所以 mask 中与输入图像(x,y)像素点相对应的点的坐标为(x+1,y+1)。
- 第三个参数,Point类型的seedPoint,漫水填充算法的起始点。
- 第四个参数,Scalar类型的newVal,像素点被染色的值,即在重绘区域像素的新值。
- 第五个参数,Rect*类型的rect,有默认值0,一个可选的参数,用于设置floodFill函数将要重绘区域的最小边界矩形区域。
- 第六个参数,Scalar类型的loDiff,有默认值Scalar( ),表示当前观察像素值与其部件邻域像素值或者待加入该部件的种子像素之间的亮度或颜色之负差(lower brightness/colordifference)的最大值。
- 第七个参数,Scalar类型的upDiff,有默认值Scalar( ),表示当前观察像素值与其部件邻域像素值或者待加入该部件的种子像素之间的亮度或颜色之正差(lower brightness/colordifference)的最大值。
- 第八个参数,int类型的flags,操作标志符,此参数包含三个部分,比较复杂,我们一起详细看看。
- 低八位(第0~7位)用于控制算法的连通性,可取4 (4为缺省值) 或者
8。如果设为4,表示填充算法只考虑当前像素水平方向和垂直方向的相邻点;如果设为 8,除上述相邻点外,还会包含对角线方向的相邻点。
高八位部分(16~23位)可以为0 或者如下两种选项标识符的组合:<1>FLOODFILL_FIXED_RANGE -
如果设置为这个标识符的话,就会考虑当前像素与种子像素之间的差,否则就考虑当前像素与其相邻像素的差。也就是说,这个范围是浮动的。<2>FLOODFILL_MASK_ONLY - 如果设置为这个标识符的话,函数不会去填充改变原始图像 (也就是忽略第三个参数newVal), 而是去填充掩模图像(mask)。这个标识符只对第二个版本的floodFill有用,因第一个版本里面压根就没有mask参数。 中间八位部分,上面关于高八位FLOODFILL_MASK_ONLY标识符中已经说的很明显,需要输入符合要求的掩码。Floodfill的flags参数的中间八位的值就是用于指定填充掩码图像的值的。但如果flags中间八位的值为0,则掩码会用1来填充。
11、getTickCount( ) 函数
首先来看一下,官方给的函数原型:
int64 getTickCount();
此函数原型非常简单,用来计算代码运行的时间,但是这个运行时间跟你所用的机器有很大的关系,所以使用这个函数来观测运行时间,最有参考价值的是相对时间。
应用实例:
const int64 start = getTickCount();
colorReduce (image1,64);
double duration = (getTickCount() - start)/getTickFrequency();
12、compare( ) 函数
首先来看一下,官方给的函数原型:
void compare(InputArray src1, InputArray src2, OutputArray dst, int cmpop);
解析:
- src1:原始图像1(必须是单通道)或者一个数值,比如是一个Mat或者一个单纯的数字n;
- src2:原始图像2(必须是单通道)或者一个数值,比如是一个Mat或者一个单纯的数字n;
- dst:结果图像,类型是CV_8UC1,即单通道8位图,大小和src1和src2中最大的那个一样,比较结果为真的地方值为255,否则为0;
- cmpop:操作类型,有以下几种类型:
CMP_EQ=0, //相等
CMP_GT=1, //大于
CMP_GE=2, //大于等于
CMP_LT=3, //小于
CMP_LE=4, //小于等于
CMP_NE=5 }; //不相等
13、compare( )算法分割图像
首先来看一下,官方给的函数原型:
cv::grabCut(image, //输入图像
result, //分段结果
rectangle, // 包含前景的矩形
bgModel,fgModel, // 前景、背景
1, // 迭代次数
cv::GC_INIT_WITH_RECT); // 用矩形
简单应用实例:
// 打开另一幅图像
cv::Mat image= cv::imread("/home/lm/AApracticeOpenCV/orange.jpg");
if (!image.data)
{
cout<<"不能打开图像!"<<endl;
return 0;
}
// 矩形外的像素是背景
cv::Rect rectangle(50,70,image.cols-150,image.rows-180);
cv::Mat result;
//两个临时矩阵变量,作为算法的中间变量使用,不用care
cv::Mat bgModel,fgModel;
double tt = cv::getTickCount();
// GrabCut 分段
cv::grabCut(image, //输入图像
result, //分段结果
rectangle,// 包含前景的矩形
bgModel,fgModel, // 前景、背景
100, // 迭代次数
cv::GC_INIT_WITH_RECT); // 用矩形
tt = cv::getTickCount() - tt;
printf("算法执行执行时间:%g ms\n", tt/cv::getTickFrequency()*1000);
// 得到可能是前景的像素
//比较函数保留值为GC_PR_FGD的像素
cv::compare(result,cv::GC_PR_FGD,result,cv::CMP_EQ);
// 产生输出图像
cv::Mat foreground(image.size(),CV_8UC3,cv::Scalar(255,255,255));
//背景值为 GC_BGD=0,作为掩码
image.copyTo(foreground,result);
cv::namedWindow("Result");
cv::imshow("Result", result);
13、cvtcolor( ) 函数/色度空间转换函数
首先来看一下,官方给的函数原型:
void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 );
解析:
14、inRange( ) / 可同事多通道进行二值化操作
首先来看一下,官方给的函数原型:
void inRange(InputArray src, InputArray lowerb,
InputArray upperb, OutputArray dst);
解析:
- 参数1:输入要处理的图像,可以为单通道或多通道。
- 参数2:包含下边界的数组或标量。
- 参数3:包含上边界数组或标量。
- 参数4:输出图像,与输入图像src 尺寸相同且为CV_8U 类型。
该函数的要点就是:如果一幅灰度图像的某个像素的灰度值在指定的高、低阈值范围之内,则在dst图像中令该像素值为255,否则令其为0,这样就生成了一幅二值化的输出图像
15、calcHist( ) / 用直方图统计像素
首先来看一下,官方给的函数原型:
CV_EXPORTS void calcHist( const Mat* images, /// 源图像
int nimages, ///源图像的个数
const int* channels, /// 列出通道
InputArray mask, /// 输入掩码
OutputArray hist, ///输出直方图
int dims, /// 直方图维度(通道数量)
const int* histSize, ///每个维度位数
const float** ranges, ///每个维度范围
bool uniform = true, ///true表示箱子间距相等
bool accumulate = false ); /// 是否在多次调用时进行累加
直方图是一个简单的表格,每个像素放在一个箱子里面
对一副 灰度图 进行直方图处理的一般步骤(调用OpenCV库函数)
- 首先,创建灰度图像直方图 Histogram1D h;
- 接下来计算直方图, Mat histo = h.getHistogram( image ) /// 获取直方图的函数
- 如果在这里想要读取每个箱子里面的像素值,就可以直接使用全局遍历,就可以读出来像素值
for (int i =0 ; i < 256; i++ ){
cout << "Value" << i << " = " << histo.at<float>(i) << endl;
}
- 计算直方图,并返回它的图像
h.getImageOfHistogram( image ) /// 该方法就可以得到直方图图像
16、LUT( ) / 查找表函数的使用(Look up table)
首先来看一下,官方给的函数原型:
LUT(InputArray src, InputArray lut, OutputArray dst);
- src表示的是输入图像(可以是单通道也可是3通道)
- lut表示查找表(查找表也可以是单通道,也可以是3通道,如果输入图像为单通道,那查找表必须为单通道,
若输入图像为3通道,查找表可以为单通道,也可以为3通道,若为单通道则表示对图像3个通道都应用这个表,若为3通道则分别应用
) - dst表示输出图像
大体解释一下查找表的作用: LUT(Look-Up Table)实际上就是一张像素灰度值的映射表,它将实际采样到的像素灰度值经过一定的变换如阈值、反转、二值化、对比度调整、线性变换等,变成了另外一个与之对应的灰度值,这样可以起到突出图像的有用信息,增强图像的光对比度的作用。
17、equalizeHist( ) / 对图像的直方图进行均衡化
首先来看一下,官方给的函数原型:
void equalizeHist( InputArray src, OutputArray dst );
OpenCV提供的简单易用函数,用于直方图均衡化处理
在这里需要注意: src和dst 这两个参数就是Mat类型的图像变量。
18、normalize( ) / 得到特定值属于某个区域的概率
首先来看一下,官方给的函数原型:
void cv::normalize(InputArry src,InputOutputArray dst,double alpha=1,double beta=0,int norm_type=NORM_L2,
int dtype=-1,InputArray mark=noArry())
- src 输入数组;
- dst 输出数组,数组的大小和原数组一致;
- alpha 1,用来规范值,2.规范范围,并且是下限;
- beta 只用来规范范围并且是上限;
- norm_type 归一化选择的数学公式类型;
- dtype 当为负,输出在大小深度通道数都等于输入,当为正,输出只在深度与输如不同,不同的地方游 dtype决定;
- mark 掩码。选择感兴趣区域,选定后只能对该区域进行操作。