大家应该熟悉opencv是一个图像处理或者说是计算机视觉库,但是在opencv中有这么一个头文件highgui.h。这个头文件中封装了很多类似windowsGUI的操作,甚至有时候调用起来逻辑更加清晰。
首先这个头文件中封装了一些简单的图形绘画操作:
cvCircle( CvArr* img, CvPoint center, int radius, CvScalar color, int thickness=1, int line_type=8, int shift=0 );
cvLine( CvArr* img, CvPoint pt1, CvPoint pt2, CvScalar color, int thickness=1, int line_type=8, int shift=0 );
cvRectangle( CvArr* img, CvPoint pt1, CvPoint pt2, CvScalar color,int thickness=1, int line_type=8, int shift=0 ;CvSize min_size=cvSize(0,0);CvSize max=cvSize(0,0));
看名字就能看出来,就是一些按照定点画出圆,线,矩形。
那么我们怎么才能用这些基本操作画出复杂的动画UI呢?
我们知道,动画就是一帧一帧渐变的图像,我们是不是可以这么想,如果我每一帧图像都变一点,最后把所有帧都连起来就是个动画呢。
opencv提供这一基础的函数就是cvWaitkey;
char cvWaitkey(int);
这个函数将返回一个char型的值,作为瞬间响应按钮,我们可以利用这个值对动画的动作进行控制。
而括号里的int值就是等待时间,也就是帧和帧之间的间隔时间,单位是ms;
如果int值为0则表示一直等待char类型按键的响应;
那么首先,我们先画两个可以一直变大的圆锥形;
圆锥其实就是由无数个圆组成的,让圆在特定的直线上慢慢变大就可以形成一个圆锥。
IplImage *img0;
img0=cvLoadImage("test0.jpg");
cvNamedWindow("My Window");//建立窗口
int a=0;
int b=0;
int t=0;
int k=1;
while(true){
cvCircle(img0,cvPoint(b,a),k,CV_RGB(255,0,255),3);//画圆
cvShowImage("My Window", img0);
cvWaitKey(20); //20ms一帧图像
a+=2;
b+=1;
k++;//改变控制圆大小
}
这就可以动态显示一个类似圆锥的图像动画。
接下来我们就可以玩一些高难度的操作。
opencv中没有定义清除函数,这让非常多的动画方案都难以实现,比如说我要显示下雨,但是画了线以后线就留在了那里,没有消失,会越变越多,不能控制。
那么opencv又可以怎么样去显示可清除动态呢?
这里的核心算法就是cvCloneImage。
我把显示的原图作为克隆源,每显示一张就销毁一张,每次画的都是新的图像,这样就可以成功的绕开所谓的清除函数。
还是以原来的那个圆锥举例,现在就可以显示一个慢慢放大的圆形了;
IplImage *img0;
img0=cvLoadImage("test0.jpg");
IplImage *img1=cvCreateImage(cvGetSize(img0),img0->depth,img0->nChannels);
cvNamedWindow("My Window");
int a=0;
int b=0;
int t=0;
int k=1;
while(true){
img1=cvCloneImage(img0);
cvCircle(img1,cvPoint(b,a),k,CV_RGB(255,0,255),3);
cvShowImage("My Window", img1);
cvWaitKey(20);
a+=2;
b+=1;
k++;
}
下面是效果图
最后我们要做一个炫酷的,那就是放大镜。
我们知道放大镜可以跟着鼠标移动,并显示鼠标周围的图像然后放大,这个操作就有些难度了。
我们首先要熟悉鼠标操作,我的另外一篇博客中有写opencv鼠标操作,
这样利于鼠标我们就可以完成这件事了。
首先读入一张图像。
在鼠标函数中复制这张图像,以免在操作时候画在圆图像上。
IplImage *imgx=cvLoadImage("test.jpg");
IplImage *imgcopyx=cvCreateImage(cvGetSize(imgx),imgx->depth,imgx->nChannels);
void onMouse(int Event,int x,int y,int flags,void* param )//====================================响应鼠标点击事件
{
imgcopyx=cvCloneImage(imgx);
}
设置鼠标回调函数,并且实时获取xy坐标。
我们再设置一个区域作为放大区域,这个区域是围绕着xy坐标的;
cvSetImageROI(imgcopyx , cvRect(x-100,y-100,200,200));
这个区域设置必须加上条件,否则就会让区域超出图像导致程序崩溃;
if (x>=100&&y>=100&&x<=imgcopyx->width-100&&y<=imgcopyx->height-100&&edgeshow);
最后我们再将已经设置好区域的图像拷贝到新的,长宽一致的图像中,画上一些标准线就行了;
cvCircle(rectimg,cvPoint(rectimg->width/2,rectimg->height/2),10,CV_RGB(255,255,255),2);
cvLine(rectimg,cvPoint(0,rectimg->height/2),cvPoint(rectimg->width,rectimg->height/2),CV_RGB(255,0,0),1);
cvLine(rectimg,cvPoint(rectimg->width/2,0),cvPoint(rectimg->width/2,imgx->height),CV_RGB(255,0,0),1);
整个程序大致是这样
IplImage *imgx=cvLoadImage("test.jpg");
IplImage *imgcopyx=cvCreateImage(cvGetSize(imgx),imgx->depth,imgx->nChannels);
void onMouse(int Event,int x,int y,int flags,void* param )//====================================响应鼠标点击事件
{
/*printf("( %d, %d) ",x,y);
printf("The Event is : %d ",Event);
printf("The flags is : %d ",flags);
printf("The param is : %d\n",param);*/
imgcopyx=cvCloneImage(imgx);
IplImage *rectimg=cvCreateImage(cvSize(200,200),imgcopyx->depth,imgcopyx->nChannels);
if (x>=100&&y>=100&&x<=imgcopyx->width-100&&y<=imgcopyx->height-100&&edgeshow)
{
cvSetImageROI(imgcopyx , cvRect(x-100,y-100,200,200));
cvCopy(imgcopyx,rectimg);
cvCircle(rectimg,cvPoint(rectimg->width/2,rectimg->height/2),10,CV_RGB(255,255,255),2);
cvLine(rectimg,cvPoint(0,rectimg->height/2),cvPoint(rectimg->width,rectimg->height/2),CV_RGB(255,0,0),1);
cvLine(rectimg,cvPoint(rectimg->width/2,0),cvPoint(rectimg->width/2,imgx->height),CV_RGB(255,0,0),1);
cvNamedWindow("辅助操作窗口",0);
cvResizeWindow("辅助操作窗口",rectimg->width*1.5,rectimg->height*1.5);
cvMoveWindow("辅助操作窗口",x+100,y-300);
//cvMoveWindow("辅助操作窗口",imgcopyx->width+200,imgcopyx->height-300);
cvShowImage("辅助操作窗口",rectimg);
}
cvReleaseImage(&rectimg);
cvReleaseImage(&imgcopyx);
}
效果有些像某些输入法的放大功能,如下:
炫酷吧,其实opencv里面的GUI操作并不少,就看怎么样去结合,去实现自己想要的算法。
很多动画很多事情分解开来其实都很简单。
reference:
http://baike.baidu.com/