本文主要自OpenCVChina,转载请注明出处http://blog.sina.com.cn/lucyloveayu
OpenCV是一个基于C/C++语言的开源图像处理函数库,其特点有:
1. 代码都是经过优化,可以用于实时处理图像;
2. 具有良好的可移植性;
3. 可以进行图像/视频的载入、保存和采集的常规操作;
4. 具有低级和高级的API;
5. 提供了面向Intel IPP高效多媒体函数的接口,可以针对使用的IntelCPU优化代码,提高程序新跟那个(OpenCV自从2.0版本以后已经不需IPP,所以不再提供相关的接口)
【OpenCV功能】
1. 图像数据操作(内存分配与释放,图像复制,设定和转换);
2. 图像/视频的输入和输出(支持文件或者摄像头的输入,图像/视频文件的输出;
3. 矩阵/向量的数据操作以及线性代数运算(矩阵乘积、矩阵方程求解、特征值、
奇异值分解);
4. 支持多种动态数据结构(链表、队列、数据集、树、图);
5. 基本图像处理(去噪、边缘检测、角点检测、采样与插值、色彩变换、形态学处理、直方图、图像金字塔结构);
6. 结构分析(连通域/分支、轮廓处理、距离转换、图像矩、模板匹配、霍夫变幻、多项式逼近、曲线拟合、椭圆拟合、狄劳尼三角化;
7. 摄像头定标(寻找和跟踪定标模式、参数定标、基本矩阵估计、单位矩阵估计、立体视觉匹配);
8. 运动分析(光流、动作分割、目标跟踪);
9. 目标识别(特征方法、HMM模型);
10. 基本的GUI(显示图像/视频、键盘/鼠标操作、滑动条);
11. 图像标注(直线、曲线、多边形、文本标注)。
【OpenCV基本模块】
cv——核心函数库
cvaux——辅助函数库
cxcore——数据结构与线性代数库
highgui——GUI函数库
ml——机器学习函数库
【OpenCV命名规则】
A. 函数名
cvActionTargetMod(…)
Action=核心功能(core functionality)(eg:set,create)
Target=目标图像区域(target image area) (eg:contour,polygon)
Mod=(可选的)调整语(optional modifiers)(eg:argument type)
B. 矩阵数据类型
CV_(S|U|F)
S=符号整形
U=无符号整形
F=浮点型
(eg:CV_8UC1是指一个8位无符号整形单通道矩阵,
CV_32FC2是指一个32位浮点型双通道矩阵)
C. 图像数据类型
IPL_DEPTH(S|U|F)
Eg:
IPL_DEPTH_8U图像像素数据是8位无符号整形。
IPL_DEPTH_32P图像像素数据是32位浮点型。
【头文件包含】
#include——核心函数库
#include——辅助函数库
#include——机器学习库
#include——GUI函数库
#include//一般不需要,因为cv.h已经包含该头文件 数据结构与线性代数库
【OpenCV中的基本数据结构】
1. 图像数据结构
A. IPL图像
IPLImage |
|
Int nChannels |
颜色通道的数目(1,2,3,4) |
Int depth |
像素的位深 IPL_DEPTH_8U IPL_DEPTH_16S IPL_DEPTH_32F IPL_DEPTH_64F |
Int width |
图像宽度(像素为单位) |
Int height |
图像高度 |
Char * imageData |
图像数据指针 彩色图像按照BGR的顺序存储数据 |
Int dataOrder |
0——将像素点不同的通道的值交错排在一起,形成单一的像素平面 1——把所有的像素同通道值排在一起,形成若干个通道平面,再把平面排列起来 |
Int origin |
0 –像素原点=左上角 1 –像素原点为左下角(windows bitmaps Style) |
Int widthStep |
相邻行的同列点之间的字节数 |
Int imageSize |
图像的大小(字节为单位)=height*widthStep |
Struct _IplROI *roi |
图像的感兴区域(ROI),ROI非空的会后对图像的处理仅限于ROI区域 |
Char *imageDataOrigin |
图像数据未对齐时候的数据原点指针 (需要正确地重新分配图像内存) |
Int align |
图像数据的行对齐 :4 or 8 byte alignment |
Char colorModel[4] |
颜色模型(OpenCV中没有此项) |
2. 矩阵:
A.2D矩阵
CvMat(2D矩阵) |
||
int type |
元素类型 |
|
int step |
整行长度字节数 |
|
Int rows,cols |
行、列数 |
|
int height,width |
矩阵高度、宽度、与rows,cols对应 |
|
Union data |
|
|
|
Uchar *ptr |
指向unsigned char矩阵的指针 |
|
Short *s |
指向short矩阵的指针 |
|
Int * i |
指向整形矩阵的指针 |
|
Float *fl |
指向浮点型矩阵的指针 |
|
Double *db |
指向双精度浮点型矩阵的指针 |
B. N维矩阵
CvMatND(N-维矩阵) |
|
Int type |
元素类型(uchar,short,int,float,double) |
Int dims |
矩阵维数 |
Union data |
Uchar *Ptr Short *s Int * I; Float *fl; Double *db |
Struct dim[] |
各维信息 |
|
Size 元素数目 Step 元素间距 字节为单位 |
C. CvSparseMat //N-维稀疏矩阵
D.一般矩阵
CvArr* //仅仅作为函数定义的参数使用
//表明函数可以接受不同类型的矩阵作为参数
//矩阵的类型通过矩阵头部的前4个字节信息来确定
E.标量
CvScalar double val[4]; //4D向量
初始化:
CvScalar s=cvScalar(double val0,double val1=0, double val2=0, double val3=0);
CvScalar s=cvScalar(20.0);
s.val[0]=20.0
3. 点
CvPoint p=cvPoint(int x,int y); //整形二维点
CvPoint 2D32f p=cvPoint2d32f(float x,float y);//浮点型二维点
Cvpoint3D32f p=cvPoint3D32f(float x,float y,float z);//浮点型三维点
4. 矩形框大小 (以像素为精度)
cvSize= cvSize(int width,int height)
CvSize2D32f r=cvSize2D32f(float width,float height);
5. 矩形框的偏置和大小:
CvRect r=cvRect(int x, int y, int width , int height)
【OpenCV的图像读写】
1. 从文件中读入图像:
OpenCV默认将读入的图像强制转换为一副三通道彩色图像:
IplImage * img=0;
Img=cvLoadImage(fileName);
If(!img) printf(“could not load image file :% s\n”,filename);
OpenCV支持图像格式有:BMP、DIB、JPEG、JPE、PNG、PBM、PGM、PPM、SR、RAS、TIFF、TIF
可以按照如下的方式修改读入的方式:
img=cvLoadImage(filename,flag)
flag: >0 将读入的图像强制转换为一副三通道彩色图像
=0 将读入的图像强制转换为一副单通道灰度图像
<0 将读入的图像通道数与所读入的文件相同
2. 保存图像
If(!cvSaveImage(outFileName,img)) printf(“could not save :%s\n”,outFileName)
保存的图像的格式由outFileName中的扩展名确定
【OpenCV访问图像像素】
假设现在需要访问第k通道、第i行,第j列的像素,可以有如下的间接和直接访问两种方式:
1. 间接访问(单通道字节型图像)
IplImage *img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
CvScalar s;
S=cvGet2D(img,i,j);//注意本函数中坐标参数的顺序与其它的openCV函数坐标参数顺序恰好相反,本函数中的i代表height,而j代表width
Printf(“intensity=%f\n”,s.val[0]);
s.val[0]=111;
cvSet2D(img,I,j,s); //设置img(J,i)位置的像素值为s
间接访问(多通道字节型/浮点型图像)
IplImage * img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3)
cvScalar s;
s=cvGet2D(img,I,j) //得到(j,i)位置的像素值
printf(“B=%f,G=%f, R=%f\n”,s.val[0],s.val[1],s.val[2]);
S.val[0]=111;
S.val[1]=111;
S.val[2]=111;
cvSet2D(img,I,j,s)//设置img的(j,i)位置的像素的值为s
2. 直接访问(效率很高,但是很容易出错)
单通道字节型图像:
IplImage *img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
((uchar* )(img->imageData+i*img->widthstep))[j]=111;
多通道字节型图像:
IplImage * img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
((uchar*) (img->imageData+i*img->widthStep))[j*img->nChannels+0]=111;
((ucahr *)(img->imageData+i*img->widthStep))[j*img->nChannels+1]=112;
((uchar *)(img->imageData+i*img->widthStep))[j*img->nChannels+2]=113;
多通道浮点型图像:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0]=111; // B
((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1]=112; // G
((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2]=113; // R
3. 基于指针的直接访问
单通道字节型图像:
IplImage *img=cvCreateImage(cvSIze(640,480),IPL_DEPTH_8U,1)
Int height =img->height;
Int width =img->width;
Int Step =img->widthStep;
Uchar *data =(uchar *)img->imageData
Data[i*setp+j]=111;
多通道浮点型图像(假设图像数据采用4字节(32位)行对齐方式)
IplImage *img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3)
int height =img->height;
int width =img->width;
int step =img->widthStep;
int channels =img->nChanns
float *data =(float *)img->imageData
data[i*step+j*Channels+k]=111
4. 基于C++ wrapper的直接访问(更加简单高效)
首先定义一个C++ wrapper ‘Image’,然后基于Image定义不同类型的图像:
Template class Image
{
Private:
IplImage *imgp;
Public :
Image(IplImage *img=0){imgp=img}
~Image(){imgp=0;}
Void operator=(IplImage *img){imgp=img;}
Inline T * operator[]=(const int rowIndx){
Return ((T *)(imgp->imageData+rowIndx*imgp->widthStep));}
};
Typedef struct{
Unsigned char b,g,r;
}RgbPixel
Typedef struct{
Float b,g,r;
}RgbPixelFloat;
typedef Image RgbImage;
typedef Image RgbImageFloat;
typedef Image BwImage;
typedef image BwImageFloat;
对于单通道字节型图像:
IplImage *img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1)
BwImage imgA(img);
imgA[i][j]=111;
对于多通道字节型图像:
IplImage * img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
RgbImage imgA(img);
imgA[i][j].b=111;
imgA[i][j].g=111;
imgA[i][j].r=111;
对于多通道浮点型图像
IplImage *img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3)
RgbImageFloat imgA(img);
imgA[i][j].b=111;
imgA[i][j].g=111;
imgA[i][j].r=111;
【图像转换】
1) 字节型图像的灰度——彩色转换
cvConcertImage(src,dst,flags=0)
src=float/byte grayscale/color image
dst=byte grayscale/color imae
flags=CV_CVTIMG_FLIP //垂直翻转图像
CV_CVTIMG_SWAP_RB //置换R和B通道
2) 彩色图像->灰度图像
cvCvtColor(cimg,gimg,CV_BGR2GRAY) //cimg->gimg
//使用直接转换
for(i=0;iheight;i++)
for(j=0;jwidth;j++)
gimgA[i][j]=(uchar)(cimgA[i][j].b*0.114+ //直接利用转换关系将图像用灰阶表示
cimgA[i][j].g*0.587+
cimgA[i][j].r*0.299);
3) 不同彩色空间之间的转换
cvCvColor(src,dst,code)
code=CV_2
/=RGB,BGR,GRAY,HSV,YCrCb,XYZ,Lab,Luv,HLS