调试方式
1)注释:组合键“Ctrl+K+C”;
2)取消注释:组合键“Ctrl+K+U”
函数
addWeighted
原型: void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1);
第一个参数,InputArray类型的src1,表示需要加权的第一个数组,常常填一个Mat。
第二个参数,alpha,表示第一个数组的权重(0-1.0)
第三个参数,src2,表示第二个数组,它需要和第一个数组拥有相同的尺寸和通道数。
第四个参数,beta,表示第二个数组的权重值(0-1.0)。
第五个参数,dst,输出的数组,它和输入的两个数组拥有相同的尺寸和通道数。
第六个参数,gamma,一个加到权重总和上的标量值。看下面的式子自然会理解(通常设置为0)。
第七个参数,dtype,输出阵列的可选深度,有默认值-1。;当两个输入数组具有相同的深度时,这个参数设置为-1(默认值),即等同于src1.depth()。
如果用数学公式来表达,addWeighted函数计算如下两个数组(src1和src2)的加权和,得到结果输出给第四个参数。即addWeighted函数的作用可以被表示为为如下的矩阵表达式为:
dst = src1[I]*alpha+ src2[I]*beta + gamma;
copyTo
原型:void copyTo( OutputArray m, InputArray mask ) const;
createTrackbar
C++: int createTrackbar(conststring& trackbarname, conststring& winname, int* value, int count, TrackbarCallback onChange=0,void* userdata=0);
创建一个具有特定名称和范围的轨迹条(Trackbar,或者说是滑块范围控制工具),指定一个和轨迹条位置同步的变量。而且要指定回调函数onChange(第五个参数),在轨迹条位置改变的时候来调用这个回调函数。并且我们知道,创建的轨迹条显示在指定的winname(第二个参数)所代表的窗口上。
第一个参数,const string&类型的trackbarname,表示轨迹条的名字,用来代表我们创建的轨迹条。
第二个参数,const string&类型的winname,填窗口的名字,表示这个轨迹条会依附到哪个窗口上,即对应namedWindow()创建窗口时填的某一个窗口名。
第三个参数,int* 类型的value,一个指向整型的指针,表示滑块的位置。并且在创建时,滑块的初始位置就是该变量当前的值。
第四个参数,int类型的count,表示滑块可以达到的最大位置的值。PS:滑块最小的位置的值始终为0。
第五个参数,TrackbarCallback类型的onChange,首先注意他有默认值0。这是一个指向回调函数的指针,每次滑块位置改变时,这个函数都会进行回调。并且这个函数的原型必须为void XXXX(int,void*);其中第一个参数是轨迹条的位置,第二个参数是用户数据(看下面的第六个参数)。如果回调是NULL指针,表示没有回调函数的调用,仅第三个参数value有变化。
第六个参数,void*类型的userdata,他也有默认值0。这个参数是用户传给回调函数的数据,用来处理轨迹条事件。如果使用的第三个参数value实参是全局变量的话,完全可以不去管这个userdata参数。
destroyAllWindows()
destroyWindow()
drawContours
void drawContours( InputOutputArray image, InputArrayOfArrays contours,int contourIdx, const Scalar& color,int thickness=1, int lineType=8,InputArray hierarchy=noArray(),int maxLevel=INT_MAX, Point offset=Point() );
用来将轮廓绘制出来
image:表示目标图像;
contours:表示输入的轮廓组,每一组轮廓由点vector构成;
contourIdx:指明画第几个轮廓,如果该参数为负值,则画全部轮廓;
color:为轮廓的颜色;
thickness:为轮廓的线宽,如果为负值或CV_FILLED表示填充轮廓内部;
lineType:为线型;
第七个参数为轮廓结构信息
第八个参数为maxLevel
empty
inline bool Mat::empty() const { return data == 0 || total() == 0; }
判断当前的mat对象是否为空;
img = imread(FILE_PATH_TEST, 0);//Read the gray image
if(img.empty())
{
cout << "Could not read input image file: " << inputImage << endl;
return -1;
}
fclose
int fclose( FILE *fp );
fclose是一个函数名,功能是关闭一个流。注意:使用fclose()函数就可以把缓冲区内最后剩余的数据输出到内核缓冲区,并释放文件指针和有关的缓冲区。
findContours
void findContours( InputOutputArray image, OutputArrayOfArrays contours,OutputArray hierarchy, int mode,int method, Point offset=Point());
retrieves contours and the hierarchical information from black-n-white image
image:输入图像image必须为一个2值单通道图像;
contours:检测的轮廓数组,每一个轮廓用一个point类型的vector表示
hiararchy:和轮廓个数相同,每个轮廓contours[i]对应4个hierarchy元素hierarchy[ i ][ 0 ] ~hierarchy[ i ][ 3 ],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,该值设置为负数。
mode:表示轮廓的检索模式
CV_RETR_EXTERNAL表示只检测外轮廓
CV_RETR_LIST检测的轮廓不建立等级关系
CV_RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
CV_RETR_TREE建立一个等级树结构的轮廓。
method:为轮廓的近似办法
CV_CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
CV_CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法
offset:表示代表轮廓点的偏移量,可以设置为任意值。对ROI图像中找出的轮廓,并要在整个图像中进行分析时,这个参数还是很有用的。
fopen
FILE * fopen(const char * path,const char * mode)
文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回NULL,并把错误代码存在errno中;
#include<stdio.h>
#define F_PATH "d:\\myfile\\file.dat"
int main(void)
{
FILE*fp=NULL;//需要注意
fp=fopen(F_PATH,"r");
if(NULL==fp)
{
return -1;//要返回错误代码
}
fclose(fp);
fp=NULL;//需要指向空,否则会指向原打开文件地址
return 0;
}
fscanf
int fscanf(FILE*stream,constchar*format,[argument...]);
根据数据格式(format)从输入流(stream)中写入数据(argument)
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int i;
printf("Input an integer:");
/*从标准输入中读取一个整数*/
if(fscanf(stdin, "%d",&i))
printf("The integer read was:%d\n", &i);
else
{
fprintf(stderr, "Error reading an integer from stdin.\n");
exit(1);
}
return 0;
}
返回EOF如果读取到文件结尾。
imread
原型:Mat imread(const string& filename, intflags=1 );
第一个参数,const string&类型的filename,填我们需要载入的图片路径名
在Windows操作系统下,OpenCV的imread函数支持如下类型的图像载入:
1.Windows位图 - .bmp, .dib
2.JPEG文件 - .jpeg, .jpg, *.jpe
3.JPEG 2000文件- *.jp2
4. PNG图片 - *.png
5. 便携文件格式- .pbm, .pgm, *.ppm
6. Sun rasters光栅文件 - .sr, .ras
7.TIFF 文件 - .tiff, .tif
第二个参数,int类型的flags,为载入标识,它指定一个加载图像的颜色类型。可以看到它自带缺省值1.所以有时候这个参数在调用时我们可以忽略,在看了下面的讲解之后,我们就会发现,如果在调用时忽略这个参数,就表示载入三通道的彩色图像,0表示将读入的图像转换成灰度图像。
imshow
原型:void imshow(const string& winname, InputArray mat);
第一个参数,const string&类型的winname,填需要显示的窗口标识名称。
第二个参数,InputArray 类型的mat,填需要显示的图像。
imwrite
原型:bool imwrite(const string& filename,InputArray img, const vector& params=vector() );
第一个参数,const string&类型的filename,填需要写入的文件名就行了,带上后缀,比如,“123.jpg”这样。
第二个参数,InputArray类型的img,一般填一个Mat类型的图像数据就行了。
第三个参数,const vector&类型的params,表示为特定格式保存的参数编码,它有默认值vector(),所以一般情况下不需要填写。
malloc
extern void *malloc(unsigned int num_bytes);;
malloc 向系统申请分配指定size个字节的内存空间,void* 表示未确定类型的指针。C,C++规定,void* 类型可以通过类型转换强制转换为任何其它类型的指针
merge
原型:void merge(const Mat* mv, size_tcount, OutputArray dst)
merge()函数的功能是split()函数的逆向操作,将多个数组组合合并成一个多通道的数组
第一个参数,mv,填需要被合并的输入矩阵或vector容器的阵列,这个mv参数中所有的矩阵必须有着一样的尺寸和深度。
第二个参数,count,当mv为一个空白的C数组时,代表输入矩阵的个数,这个参数显然必须大于1.
第三个参数,dst,即输出矩阵,和mv[0]拥有一样的尺寸和深度,并且通道的数量是矩阵阵列中的通道的总数
namedWindow
原型:void namedWindow( const string& winname, int flags=WINDOW_AUTOSIZE );
第一个参数,const string&型的name,即填被用作窗口的标识符的窗口名称。
第二个参数,int 类型的flags ,窗口的标识,可以填如下的值:
WINDOW_NORMAL设置了这个值,用户便可以改变窗口的大小(没有限制);
WINDOW_AUTOSIZE如果设置了这个值,窗口大小会自动调整以适应所显示的图像,并且不能手动改变窗口大小(默认);
WINDOW_OPENGL 如果设置了这个值的话,窗口创建的时候便会支持OpenGL
namedWindow函数的作用是,通过指定的名字,创建一个可以作为图像和进度条的容器窗口。如果具有相同名称的窗口已经存在,则函数不做任何事情;
rand
int rand(void);
返回一个[0,RAND_MAX]间的随机整数。
Rect
原型:template inline Rect_<Tp>::Rect() : x(0), y(0), width(0), height(0) {}
指定矩形的左上角坐标(构造函数的前两个参数)和矩形的长宽(构造函数的后两个参数)就可以定义一个矩形区域
举例:
Mat imageROI= srcImage1(Rect(100,100,logoImage.cols,logoImage.rows));
获取图像srcImage1的起始位置为100,100,width=logoImage.cols,height=logoImage.rows区域的图像;
size
得到Mat类型img的size,可以使用函数img.size(),注意这里有括号。但是在需得到img的行和列时,不需要使用括号,即使用img.rows和img.cols.
sizeof
是C/C++中的一个操作符(operator),简单的说其作用就是返回一个对象或者类型所占的内存字节数。如在C语言中使用sizeof(char),其结果为1,表示char类型占1个字节(8比特)
split
原型:void split(InputArray m,OutputArrayOfArrays mv);
第一个参数,InputArray类型的m或者const Mat&类型的src,填我们需要进行分离的多通道数组。
第二个参数,OutputArrayOfArrays类型的mv,填函数的输出数组或者输出的vector容器。
waitKey
原型:int waitKey(int delay=0);
zeros
static MatExpr zeros(Size size, int type);//Matlab-style matrix initialization
初始化图像对象为0,如:
Mat dst = Mat::zeros(img.size(), CV_8UC3);
//-----------------------------------【命名空间声明部分】---------------------------------------
// 描述:包含程序所使用的命名空间
//-----------------------------------------------------------------------------------------------
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include <cv.h>
#include <highgui.h>
#include <iostream>
using namespace cv;
using namespace std;
#define FILE_PATH_IMAGE1 "E:\\sunwork\\OpenCVTest\\TestImage\\fhd1.jpg"
#define FILE_PATH_IMAGE2 "E:\\sunwork\\OpenCVTest\\TestImage\\logo.jpg"
#define FILE_PATH_IMAGE3 "E:\\sunwork\\OpenCVTest\\TestImage\\fhd2.jpg"
#define FILE_PATH_TEST "E:\\sunwork\\OpenCVTest\\TestImage\\TEST.jpg"
//-----------------------------------【全局函数声明部分】--------------------------------------
// 描述:全局函数声明
//-----------------------------------------------------------------------------------------------
bool MultiChannelBlending();
//-----------------------------------【main( )函数】--------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------------------------------
int main( )
{
if(MultiChannelBlending())
{
cout<<endl<<"OK";
}
waitKey(0);
return 0;
}
//-----------------------------MultiChannelBlending( )--------------------------------
// Description:
//-----------------------------------------------------------------------------------------------
bool MultiChannelBlending()
{
//【0】定义相关变量
Mat srcImage;
Mat logoImage;
vector<Mat>channels;
Mat imageBlueChannel;
logoImage=imread(FILE_PATH_IMAGE2,0);
srcImage=imread(FILE_PATH_TEST);
if(!logoImage.data ){ printf("Read image wrong\n"); return false; }
if(!srcImage.data ) { printf("Read image wrong\n"); return false; }
split(srcImage,channels);
imageBlueChannel=channels.at(0);//0:Blue
addWeighted(imageBlueChannel(Rect(100,100,logoImage.cols,logoImage.rows)),1.0,
logoImage,0.5,0,imageBlueChannel(Rect(100,100,logoImage.cols,logoImage.rows)));
merge(channels,srcImage);//channels.at(0) have been converted
namedWindow("WindowName");
imshow("WindowName",srcImage);
return true;
}
1、打印测试数据到txt中
FILE *ycocg2rgbOutputData;
ycocg2rgbOutputData=fopen("ycocg2rgbOutputData.txt", "wt");
for(i=0;i<HEIGHT;i++)
{
for(j=0;j<WIDTH;j++)
{
if (j==WIDTH)
{
fprintf(ycocg2rgbOutputData, "\n");//printf new line
}
else
{
fprintf(ycocg2rgbOutputData, "%d,",op->data.rgb.r[i][j]);//printf data to the new file
}
}
}
fclose(ycocg2rgbOutputData);
2、从txt或者csv等文件中读取数据到数组中
思想:使用指针fp指向文件的内容,依次读取文件的字符并拼接成字符串,遇到”,”则表示已经读取完当前内容,则将已经读取到字符串转换成整型或者浮点型放入存储单元中,如果遇到换行符则也对应将数据存放到存储单元新的一行中,做到对应。其中需要注意的是当检测到字符串拼接完成之后需要做清空动作。
这里假设csv数据是480*270,且每一个格子的数据长度不超过30。(将程序中的txt换成csv同样可行)
FILE *fp = NULL;
int numCount=0;
int rows=0;
int cols=0;
int csvdata[480][270];
char c;
char s[30]={0};//csv grid data length is small than 30
fp = fopen("example8bit.txt", "r"); //or csv
if(fp == NULL)
{
printf("file can not be opened or is not correct\n");
exit(0);
}
while((c=getc(fp))!=EOF)
{
if (c==','||c=='\n')
{
numCount=0;
csvdata[rows][cols]=atoi(s);//convert the string to float
cols++;
memset(s,0x00,sizeof (char) * 30);//Reinitial the string
if (c=='\n')
{
rows++;
cols=0;
}
continue;
}
else
{
s[numCount]=c;
numCount++;
}
}
fclose(fp);
fp=NULL;