openCV实现图片的时钟和中心圆形扩大效果

一、问题描述

 

使用任意方式实现图片的时钟和中心圆形扩大效果。

 

二、问题分析

    在视频的制作中能够看到很多图片切换效果。在本次实验中要求实现图片呈时钟状显示(即新图像顺时针擦除原图像),和中心圆形向外扩散的效果。由于没有要求实现方式,首先需要确定实验平台。处理图像的平台或工具主要有Visual Studio 的GDI(GDI+),图像处理开源库openCV,matlab等。这里选择openCV,进行像素级的处理。openCV中的矩阵,以先行后列的顺序进行储存,左上角为坐标原点,向下为y轴,向右为x轴。将两幅不同的图片存储到矩阵Mat类中,以不同的方式进行像素的替换。绘制时钟擦效果时,需要考虑四个象限角度的变化。绘制中心圆扩散效果时,需要考虑半径的变化。将每一帧的图片写入到视频中,生成图片切换的视频。

算法分析

中心圆放大效果

从画面中心开始,新图像以圆形向外扩大,在这个过程中可以将时间和半径联系起来,t=0时r=0,t_max=r_max,两者始终保持相等。

最大半径即为图像对角线长度的一半,即r_max= 。

首先结果矩阵result赋值为pic0。

对圆的外切正方形进行扫描,根据像素的x,y值计算点到圆心的距离,计算出r=。

If(r<t)

  Result[x][y]=pic1[x][y];

由于使用OpenCV,使用迭代器进行像素的赋值。

时钟擦效果

分别对四个象限进行绘制。由于函数库中的tan参数为弧度制,需要进行角度的转换。定义常量PI为3.14159265。

绘制第一象限时,y的范围是0到y_max/2,x的绘制范围是x_max/2到(y_max / 2 - y)*tan(t*(PI/180))。需要注意边界情况,圆可能扩展到图片范围之外,需要使用min函数限制,x不超过x_max。

绘制第二象限时,y的范围为y_max/2到y_max,x的范围为((y - y_max / 2) / tan(t*(PI / 180)) +x_max / 2)到x_max。由于tan值处于分母的位置,需要保证不为0,因此剔除t=0的情况,单独绘制x轴正半轴的像素。

第三象限, y =y_max/2~ y_max,x= (x_max / 2 -(y - y_max / 2)*tan(t*(PI / 180)))~x_max。

第四象限,同样需要单独绘制x轴的负半轴。

y = 0~ y_max/2-1,x = 0~ (x_max / 2 - (y_max / 2 - y) /tan(t*(PI / 180)))

对于部分由于小数取整产生的填充空缺,在前面绘制完毕后,进行像素的补充填充(分布在x轴附近)。

详细设计(从算法到程序)

1.     主模块设计

主函数中读取两张图片,分别为pic0,pic1。调用图片切换效果函数circleTransition(Mat,Mat)和clockTransition(Mat,Mat)。

2.     圆形中心方法效果circleTransition(Mat pic0,Mat pic1)

设置视频格式,包括压缩帧率和尺寸,此处直接设置为常数,如果需要根据图片设置宽高,也可以方便地读取图片尺寸从而进行设置。

doublefps=20;//视频压缩帧率

      CvSizesize=cvSize(440,440);//图片序列中每张图片的宽高

      CvVideoWriter*writer=cvCreateVideoWriter("CircleTransition.avi",CV_FOURCC('M','J','P','G'),fps,size,true);

 

      设置循环中需要用到的常量和变量:

intr_max=0,r=0;

      intx_max=0,y_max=0;

      intx=0,y=0;

      x_max=pic0.cols;

      y_max=pic0.rows;

      r_max=int(sqrt(pow(float(x_max/2),2)+pow(float(y_max/2),2)));

      intt_max=r_max,t=0;//t=r

初始化result矩阵为pic0,接下来在三重循环中进行图像的扫描和像素的替换。由于圆形不能超过图片范围,需限制循环的终止条件,取半径和长宽一半的最小值。

for(t=0;t<t_max;t++){    //t=r   时间等于半径

            for(x=max(0,x_max/2-t);x<min(x_max/2+t,x_max);x++){//中心正方形,判断起始和终止的值,调用Min,max函数

                  uchar*data=result.ptr<uchar>(x);

                  uchar*p1=pic1.ptr<uchar>(x);

                  for(y=max(0,y_max/2-t);y<min(y_max/2+t,y_max);y++){

                       r=sqrt(pow(float(x-x_max/2),2)+pow(float(y-y_max/2),2));

                       if(r<=t){//如果在中心圆内,绘制新图片

                             data[y*3]=p1[y*3];

                             data[y*3+1]=p1[y*3+1];

                             data[y*3+2]=p1[y*3+2];

                       }

                  }

            }

      cvWriteFrame(writer,&IplImage(result));

      }

最后释放videoWriter。

3.     时钟擦效果clockTransition(Mat pic0,Mat pic1)

同样需要设置视频格式以及循环中需要使用的常量和变量(包括角度a,时间t等)。

doublea_max=360.0,a=0.0;

      intt_max=360,t=0;

      intx=0,y=0;

      intx_max=0,y_max=0;

      Matresult=pic0;

      x_max=result.cols;

      y_max=result.rows;

以第二象限为例,最外层循环为角度,范围是1~90(剔除x轴)。第二层循环为y,因为mat的存储方式先行后列,指针必须一行一行地遍历。

for(t=1;t<90;t++){

            for(y=y_max/2+1;y<y_max;y++){

                  uchar*data=result.ptr<uchar>(y);

                  uchar*p1=pic1.ptr<uchar>(y);

                  for(x=((y-y_max/2)/tan(t*(PI /180))+x_max/2);x<x_max;x++){

                       data[x*3]=p1[x*3];

                       data[x*3+1]=p1[x*3+1];

                       data[x*3+2]=p1[x*3+2];

                  }

            }

            cvWriteFrame(writer,&IplImage(result));

            cout<<"第二象限  角度"<<t<<endl;

      }

对于x轴正半轴,单独进行绘制:

uchar*data=result.ptr<uchar>(y_max/2);

      uchar*p1=pic1.ptr<uchar>(y_max/2);

      for(x=x_max/2;x<x_max;x++){

            data[x*3]=p1[x*3];

            data[x*3+1]=p1[x*3+1];

            data[x*3+2]=p1[x*3+2];

      }

 

调试与测试

由于算法的限制,图片的绘制速度较慢,一张440*440大小的图片,通过中心圆扩散效果需要15秒完成绘制。

当圆超过图片边缘时,同样可以正常绘制。

时钟擦效果,需要花费18s,绘制过程较为流畅。

但在x轴附近会出现一定的抖动,出现缝隙或者是绘制速度较慢。

 

分析与总结

本次实验理解了两种视频切换效果的原理,并利用openCV实现了绘制效果。完成了实验的要求,但绘制速度较慢,这是由算法所局限的。

在进行中心圆扩散的效果实现时,可以进行优化,缩小扫描面积。如果扫面外切正方形,当半径很大时,扫描面积很大,有很多重复填充的操作。可以考虑只扫描圆的外切和内切正方形所包围的平面,这样能够大大缩减扫描面积,从而提高绘制效率。

对于时钟擦效果,也可以减小重复填充的次数,或者考虑其余的绘制方法,例如增加角度时填充线条,而不是扫描行和列进行像素的填充。由于tan函数的特殊性,需要考虑值为无穷或tan值为分母(不能为0)的情况,进行单独的绘制,从而改善绘制效果,避免瑕疵或缝隙的出现。


资源链接:http://download.csdn.net/detail/rachelkong/9735501

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值