您的位置:首页 > 运维架构

Opencv基础学习笔记

2017-03-20 19:52 330 查看

GUI指令

创建和定位一个新窗口:

cvNamedWindow("win1",CV_WINDOW_AUTOSIZE);
cvMoveWindow("win1",100,100);//从屏幕的左上开始偏移

载入图像:

IPlImage* img = 0;
img = cvLoadImage(filename);
if(!img)
printf("Could not load image file: %s\n",filename);

显示图像:

cvShowImage("win1,img");

关闭窗口:

cvDestroyWindow("win1");

改变窗口大小:

cvResizeWindow("win1",100,100);//新的窗口大小

输入处理

(1) 处理鼠标事件:

1 定义一个鼠标处理程序(监听):

void mouseHandler(
int event,	//各种鼠标事件:CV_EVENT_LBUTTONDOWN
CV_EVENT_RBUTTONDOWN
……

int x,
int y,		//x,y相当于左上角的像素坐标
int flags,	//
void* param)


例子:

e.g.
void mouseHandler(int event,int x,int y,int flags,void* param)
{
switch(event)
{
case CV_EVENT_LBUTTONDOWN:
{
if(flags & CV_EVENT_FLAG_CTRLKEY)
printf("Left button down with CTRL pressed\n");
break;
}
case CV_EVENT_LBUTTONUP:
{
printf("Left button up!\n");//左键按住了
break;
}
}
}


2 注册该事件处理程序(响应):

mouseParam = 5;
cvSetMouseCallback("win1",mouseHandler,&mouseParam);


 处理键盘事件

//1 按一定时间间隔检测键盘输入(适用于循环体中)
int key;
key = cvWaitKey(10);

//2 中止程序等待键盘输入:
int key;
key = cvWaitKey(0);

例子:

e.g.
while(1)
{
key = cvWaitKey(10);//返回值为按下的码键
if(key == 27)
break;
switch(key)
{
case 'h':
...
break;
case 'i':
...
break;
}
}


处理滑动条事件

//1 定义一个滑动条处理程序:
void trackbarHandler(int pos)
{
printf("Trackbar position: %d\n",pos);
}

//2 注册该事件的处理程序:
int trackbarVal = 25;
int maxVal = 100;
cvCreateTrackbar("bar1","win1",&trackbarVal,maxVal,trackbarHandler);

//3 获取当前滑动条的位置:
int pos = cvGetTrackbarPos("bar1","win1");
//4 设置滑动条的位置:
cvSetTrackbarPos("bar1","win1",25);

例子:

e.g. one
//弹出一个窗口并显示图片
#include<cv.h>
#include<highgui.h>

int main(int argc,char* argv[])
{
IPlImage* image;
if(argc != 2)
return -1;
image = cvLoadImage(argv[1]);
if(!image)
return -1;

cvNamedWindow("Sample",1);
cvShowImage("Sample",image);
cvWaitKey();
cvDestroyWindow("sample");
cvReleaseImage(&image);
return 0;
}

//run:sample example_pic.jpg


OpenCV数据结构

//PlImage:

typedef struct _IplImage
{
int nSize; /*该结构体的大小*/
int ID; /*图像头的版本=0*/
int nChannels; /*通道数,可取1,3,4。如24位图,即RGB是3通道x8位(depth)。取值4,表示32位位图,有Alpha值,即位图透明度*/
int alphaChannel; /*Alpha通道数,没有取0,有则取4(被OpenCV忽略)*/
int depth; /*每个通道的位数*/
char colorModel[4]; /*颜色模式,有Gray、RGB、RGBA、CMYK等(被OpenCV忽略)*/
char channelSeq[4]; /*通道顺序,如“RGB”、“BGR”等*/
int dataOrder; /*0 - 交叉存取颜色通道, 1 - 分开的颜色通道.数据的排列方式(使用像素格式)
cvCreateImage只能创建交叉存取图像*/
int origin; /*坐标原点,有左上角和左下角两种*/
int align; /*图像行排列 (4 or 8). OpenCV 忽略它,使用 widthStep 代替 */
int width; /*图像的宽*/
int height; /*图像的高*/
struct _IplROI *roi; /*图像感兴趣区域. 当该值非空只对该区域进行处理*/
struct _IplImage *maskROI; /*OpenCV中必须为NULL*/
void *imageId; /*同上*/
struct _IplTileInfo *tileInfo; /*同上*/
int imageSize; /*图像数据大小(在交叉存取格式下imageSize=image->height*image->widthStep),单位字节*/
char *imageData; /*指向图像数据的指针*/
int widthStep; /*排列的图像行大小,以字节为单位*/
int BorderMode[4]; /*边际结束模式, 被OpenCV忽略*/
int BorderConst[4]; /*同上*/
char *imageDataOrigin; /*该指针指向完整的、没有校准的图像*/
}IplImage;

//matrix:

typedef struct CvMat
{ /*一维矩阵*/
int type; /*数据类型(CV_32FC1、CV_8UC3)*/
int step; /*每行数据的字节数:元素个数*元素类型的字节长度*/

/*仅供内部使用*/
int* refcount;
int hdr_refcount;

union
{
uchar* ptr; /*指向date的第一个元素*/
short* s;
int* i;
float* fl;
double* db;
} data;

typedef struct CvMatND /*N-维矩阵*/
{
int type; /*数据类型*/
int dims; /*矩阵维数*/

int* refcount;
int hdr_refcount;

union
{
uchar* ptr;
float* fl;
double* db;
int* i;
short* s;
} data;

struct /*各维信息*/
{
int size; /*元素数目*/
int step; /*元素间距:字节*/
}dim[CV_MAX_DIM];
}CvMatND;

//point:

CvPoint p = cvPoint(int x,int y);
CvPoint2D32f p = cvPoint(float x,float y);
p.x = 5.0;
p.y = 5.0;

//矩形框大小:

CvSize r = cvSize(int width,int height);
CvSize2D32f r = cvSize2D32f(float width,float height);

//矩形框的偏置和大小:

CvRect r = cvRect(int x,int y,int width,int height);

图像和视频处理

复制图像:

IPlImage*	img1 = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
IPlImage*	img2;
imag2 = cvCloneImage(img1);/*通过克隆得到的图像也需要使用cvReleaseImage释放内存*/


图像的读写和保存:

Opencv默认将读入的图像转换为一副三通道彩色图像,但可以通过一下方法修改:

Opencv默认将读入的图像转换为一副三通道彩色图像,但可以通过一下方法修改:
img = cvLoadImage(filename,flag);

flag:
>0 将读入的图像强制转换为一幅三通道彩色图像
=0 将读入的图像强制转换为一个单通道灰度图像
<0 读入图像保持原样


保存图像:

cvSaveImage(outfilename,img);//保存的图像格式由outfilename的后缀决定


访问图像像素

假设要访问第K通道,第i行,第j列的像素

way1:间接访问(通用,但效率低,可以访问任意格式的图像)

//a、 对于单通道字节型:
IPlImage*	img = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
CvScalar s;
s = cvGet2D(img,i,j);//获取该图像中第i行,第j列的像素值
printf("intensity = %f\n",s.val[0]);//输出原来的像素值
s.val[0] = 111;//输入最新值
cvSet2D(img,i,j,s);//重置像素值

//b、 对于多通道字节型/浮点型:
IPlImage*	img = cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
CvScalar s;
s = cvGet2D(img,i,j);
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);

way2:直接访问(效率高,但容易出错)

//a、 对于单通道字节型图像:
IPlImage* img = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
((uchar*)(img->imageData + i*img->widthStep))[j] = 111;//偏移地址

//b、 对于多通道字节型图像:
IPlImage* img = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
((uchar*)(img->imagData + i*img->widthStep))[j*img->nChannels + 0] = 111;//B
((uchar*)(img->imagData + i*img->widthStep))[j*img->nChannels + 1] = 112;//B
((uchar*)(img->imagData + i*img->widthStep))[j*img->nChannels + 2] = 113;//B

//c、 对于单通道浮点型图像:
IPlImage* img = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
((float*)(img->imagData + i*img->widthStep))[j*img->nChannels + 0] = 111;//B
((float*)(img->imagData + i*img->widthStep))[j*img->nChannels + 1] = 112;//B
((float*)(img->imagData + i*img->widthStep))[j*img->nChannels + 2] = 113;//B


way3:基于指针的直接访问:(简单高效)

//a、 对于单通道字节型图像:
IPlImage* img = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
int height	  = img->heigth;
int width	  = img->width;
int step	  = img->widthStep/sizeof(uchar);//每一行字节数
uchar* data	  = (uchar*)img->imagData;//获取原图像数据的字节型指针
data[i*step +j] = 111;

//b、 对于多通道字节型图像:
IPlImage* img = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
int height	  = img->heigth;
int width	  = img->width;
int step	  = img->widthStep/sizeof(uchar);//每一行字节数
uchar* data	  = (uchar*)img->imagData;//获取原图像数据的字节型指针
data[i*step +j*channels] = 111;

//c、 对于多通道浮点型图像:假设图像采用4字节行对齐方式,即每行数据的长度必须是四字节的整数倍数
IPlImage* img = cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,1);
int height	  = img->heigth;
int width	  = img->width;
int step	  = img->widthStep/sizeof(float);//每一行字节数
float* float	  = (float*)img->imagData;//获取原图像数据的字节型指针
data[i*step +j*channels] = 111;


 图像转换:

//a、 字节型图像的灰度-彩色转换:
cvConvertImage(src,dst,flags=0);//图像转换函数
src = float/byte grayscale/color imag
data = byte grayscale/color imag
//输入图像的通道数必须是1,3或者4
//输出图像的深度必须是8位的单通道或3通道。
flags:
CV_CVTIMG_FLIP		//(垂直翻转图像)
CV_CVTIMG_SWAP_RB	//(置换R-B通道)

//b、 彩色图像->灰度图像:
//way1:使用函数
cvCvtColor(cimg,gimg,CV_BGR2GRAY);//cimg->gimg

//way2:直接转换
for(i=0;i<cimg->height;i++)
for(j=0;j<cimg->width;j++)
gimgA[i][j] = (uchar)(cimgA[i][j].b*0.114+cimgA[i][j].g*0.587+cimgA[i][j].r*0.299);

//c、 不同彩色空间之间的转换:
cvCvColor(src,dst,code)://src->dst
//格式:code = CV_<X>2<Y>
<X>/<Y> = RGB,BGR,GRAY,HSV,YCrCb,XYZ,Lab,Luv,HLS

e.g.
CV_BGR2GRAY,CV_BGR2HSV,CV_BGR2Lab


绘图指令:

//1 绘制矩形
//在坐标为(100,100)和(200,200)的点之间画一个矩形,边线为红色,宽度为1
cvRectangle(img,cvPoint(100,100),cvPoint(200,200),cvScalar(255,0,0),1);

//2 绘制原形
//圆心坐标(100,100),半径20,圆周为绿色,宽度为1
cvCircle(img,cvPoint(100,100),20,cvScalar(0,255,0),1);

//3 绘制线段
//在坐标为(100,100)和(200,200)的点之间画一条宽为1的绿色线段
cvLine(img,cvPoint(100,100),cvPoint(200,200),cvScalar(0,255,0),1);


e.g.

//获取摄像头图像实例:获取摄像头视频显示在窗口里
#include "stdafx.h"
#include "cv.h"
#include "highgui.h"

int _tmain(int argc, _TCHAR* argv[])				//vs2013中需改为多字节编码方式
{
cvNamedWindow("video", CV_WINDOW_AUTOSIZE);		//创建窗口
CvCapture* caputre;								//该结构体存放一帧图像
if (argc == 1)
caputre = cvCaptureFromCAM(0);				//从摄像头获取视频初始化caputre结构体
else
caputre = cvCreateFileCapture(argv[1]);		//从指定视频文件中获取视频初始化caputre结构体
assert(caputre != NULL);
IplImage* frame;
while (1)
{
frame = cvQueryFrame(caputre);				//从摄像头或者文件中抓取并返回一帧
if (!frame)
break;
cvShowImage("video",frame);					//将一帧画面显示在窗口
char c = cvWaitKey(33);						//每帧显示33ms
if (c == 27)								//ESC退出
break;
}
cvReleaseCapture(&caputre);						//停止读取文件并释放内存
cvDestroyWindow("video");
return 0;
}


效果:



参考:《学习OpenCv》

ps:第一次用目录,貌似有的风格显示不了目录
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  opencv