基于OpenCV的视频图像组态 (2) :动画总体

来源:互联网 发布:背包问题 python 编辑:程序博客网 时间:2024/04/30 10:49

写在前面

本系列博客URL:

http://www.cnblogs.com/drgraph

http://blog.csdn.net/arwen

配套软件下载地址:

http://www.czwenwu.com/YeeVingSetup.exe

配套软件含三个可执行文件:YeeVingDriver.exe,YeeVingPlayer.exe,WatchDog.exe

其中,YeeVingDriver.exe是双目触控屏的驱动程序,内含键盘鼠标钩子,安装或运行的时候有可能会当成病毒。

WatchDog.exe是无人值守软件

YeeVingPlayer.exe是广告播放软件客户端。

本系列博客是在上述三个软件研发过程中的片面记录,基本上是属于想到哪写到哪的,不系统。主要目的是自己整理归纳一下,并期望与更多朋友交流。

QQ/微信:282397369

EMail: drgraph@qq.com

 

需求

广告播放,一个主要需求是要以多种效果来展示素材。

闭门造车不是一个好选项,可以参照成熟专业软件的实现方式。PPT里的动画就是一个好的可参考对象。

之前已经实现了各种PPT的动画,今天稍微总结一下。

 

Ribbon界面

首先做PPT的动画界面,这个用Ribbon风格控件,就是花点时间的事,没太大的技术含量。

最花时间的是找图标,不过现在别的不好找,代码、图标却是大把。

花了半天时间,虽谈不上是神似,也能算得上是形似的了。具体功能将逐个实现。

   

动画基类

再看下PPT中的动画属性,其界面最终所围绕的也就是这两个

      

分解一下,设计几个数据结构:

复制代码
         typedefstruct tagEnhanceInfo { // 增强选项                      UnicodeStringSoundFileName; // 声音文件                   TEffect_Enhance_AfterPlayAfterPlayMode; // 动画播放后处理方式                   TColorAfterAnimationColor; // 变换为某种颜色,FAfterPlayMode为teapToColor有效                   UnicodeStringAnimationText; // 动画文本                   intDelayPercent; // 字母之间延迟百分比         }ENHANCE_INFO;            typedefstruct tagTimerInfo { // 计时选项                      TEffect_Time_StartStartMode; // 开始选项                   intDelay; // 延迟秒数                   TEffect_Time_PeriodPeriodMode; // 期间选项                   TEffect_Time_RepeatRepeatMode; // 重复选项                   boolQuickBackAfterPlay; // 播完后快退         }TIMER_INFO;   enum TEffect_Enhance_AfterPlay { // 增强选项-动画后播放选项         teapToColor,// 变换为某种颜色                   teapNoDarking,// 不变暗                   teapHide,// 隐藏                   teapHideAfterClick// 下次单击后隐藏         };   enum TEffect_Time_Start { // 计时选项-开始选项         ttsClick,// 单击时                   ttsSameTimeAsPrevOne,// 与上一动画同时                   ttsAfterPrevOne// 上一动画完成之后         };   enum TEffect_Time_Period { // 计时选项-期间         ttpVerySlow,// 非常慢                   ttpSlow,// 慢速                   ttpNormal,// 中速                   ttpFast,// 快速                   ttpVeryFast// 非常快         };   enum TEffect_Time_Repeat { // 计时选项-重复         ttrNone,//                   ttr2,// 2                   ttr3,// 3                   ttr4,// 4                   ttr5,// 5                   ttr10,// 10                   ttrTillNextClick,// 直到下一次单击                   ttrTillEnd// 直到结束         };   enum CbwEffectType { // 效果类型枚举量         cetBase= 0, // TCbwAnimationEffect                   cetAppear= 1, // TCbwAnimationEffect_Appear                   cetFadeOut= 2, // TCbwAnimationEffect_FadeOut                   cetFlyIn= 3, // TCbwAnimationEffect_FlyIn                   cetEnd};   enum CbwEffectDirection { // 动画方向         cedFromBottom= 0, // 自底部                   cedFromLeftBottom= 1, // 自左下部                   cedFromLeft= 2, // 自左侧                   cedFromLeftTop= 3, // 自左上部                   cedFromTop= 4, // 自顶部                   cedFromRightTop= 5, // 自右上部                   cedFromRight= 6, // 自右侧                   cedFromRightBottom= 7 // 自右下部         };
复制代码

 

为了更好地模块化,把对象相关的动画属性提取出来

复制代码
          typedefstruct tagObjectMat {                   TPointLeftTopPosition;                   TCbwObject* Object;                    cv::MatMat;                   cv::MatMask;                    void__fastcall BuildMask(int height, int width);         }OBJECTMAT;
复制代码

绝大部分动画,是控制过程的显示。由OpenCV技术来看,这个过程分为三块:显示区域、显示内容、屏蔽内容。

这样,可以设计动画基类为:

复制代码
/** *@class TCbwAnimationEffect *@brief 动画基类 * * 处理动画基本内容 *@author DrGraph *@version 1.0 *@date 2017-10-07 *@QQ: 282397369 */class TCbwAnimationEffect {         bool__fastcall IsAtEnd();         CbwObjectsFAnimationObjects; // 相关对象            cv::Mat__fastcall Object2Mat(TCbwObject * object, double ratio = 1);         int__fastcall GetRepeateTime();protected:         vector<OBJECTMAT>FDestMats;         intFCurrentIndex; // 当前帧索引         intFPeriodLength; // 周期长度,指动画一个周期内的帧数         intFPosition; // 当前位置,指动画累加索引位置         intFWidth, FHeight; // 长宽尺寸,指显示限制   public:         CbwEffectTypeEffectType;         ENHANCE_INFOEnhanceOption; // 增强选项         TIMER_INFOTimerOption; // 计时选项            __fastcallTCbwAnimationEffect();         staticTCbwAnimationEffect * Build();            void__fastcall Assign(TCbwAnimationEffect * other);            void__fastcall AddToXmlNode(CbwXmlNode * node);         void__fastcall GetFromXmlNode(CbwXmlNode * node);            void__fastcall First();         void__fastcall Next();         void__fastcall SetRelativeObject(CbwObjects relativeObjects,                   TPaintBox* pb, TScrollBox * scrollBox);         void__fastcall SetBounds(int width, int height);            void__fastcall Draw(HWND wnd, BYTE * backData, int width, int height);            cv::MatCurrentMat;         __propertybool Eof = {read = IsAtEnd};   protected:         virtualTRect __fastcall BuildDisplayRect(OBJECTMAT * m);         virtualvoid __fastcall BuildDisplayMat(cv::Mat& destMat, cv::Mat& srcMat);         virtualvoid __fastcall BuildMaskMat(cv::Mat& destMat, cv::Mat& srcMat);};   核心实现代码为:__fastcallTCbwAnimationEffect::TCbwAnimationEffect() {         TimerOption.StartMode= ttsClick;         TimerOption.Delay= 0;         TimerOption.PeriodMode= ttpNormal;         TimerOption.RepeatMode= ttrNone;         TimerOption.QuickBackAfterPlay= false;         EffectType= cetBase;}   TCbwAnimationEffect *TCbwAnimationEffect::Build() {         returnnew TCbwAnimationEffect;}   TRect __fastcallTCbwAnimationEffect::BuildDisplayRect(OBJECTMAT * m) {         TRectresult(m->LeftTopPosition.x, m->LeftTopPosition.y,                   m->LeftTopPosition.x+ m->Mat.cols, m->LeftTopPosition.y + m->Mat.rows);         returnresult;}   void __fastcall TCbwAnimationEffect::BuildDisplayMat(cv::Mat&destMat,         cv::Mat&srcMat) {         destMat= srcMat.clone();}   void __fastcallTCbwAnimationEffect::BuildMaskMat(cv::Mat& destMat,         cv::Mat&srcMat) {         destMat= srcMat.clone();}   void __fastcallTCbwAnimationEffect::Draw(HWND wnd, BYTE * backData, int width,         intheight) {         cv::MatbackGndMat(height, width, CV_8UC3); // 背景         GlobalOpenCVObject->CopyRGBDatasToMat(backGndMat,backData, width,                   height,true);            CBW_ITERATOR(vector<OBJECTMAT>,FDestMats) {                   OBJECTMAT* animationObject = &(*it);                   //以下取得待显示的区域、内容                   TRectanimationDisplayRect = BuildDisplayRect(animationObject); // 目标区域                      cv::MatanimationDisplayMat =                            cv::Mat::zeros(animationDisplayRect.Height(),                            animationDisplayRect.Width(),animationObject->Mat.type());                   BuildDisplayMat(animationDisplayMat,animationObject->Mat); // 待显示内容                      cv::MatmaskMat = cv::Mat::zeros(animationObject->Mask.rows,                            animationObject->Mask.cols,animationObject->Mask.type());                   BuildMaskMat(maskMat,animationObject->Mask); // Mask内容                      TRectsuitableDisplayRect; // 真正的目标显示区域                   suitableDisplayRect.left= max(0, int(animationDisplayRect.left));                   suitableDisplayRect.top= max(0, int(animationDisplayRect.top));                   suitableDisplayRect.right= min(int(animationDisplayRect.right), width);                   suitableDisplayRect.bottom= min(int(animationDisplayRect.bottom),                            height);                      TRectsuitableRectInMat(0, 0, suitableDisplayRect.Width(),                            suitableDisplayRect.Height());                   intdeltaL =                            max(0,int(suitableDisplayRect.left - animationDisplayRect.left));                   if(suitableDisplayRect.left != animationDisplayRect.left) {                            suitableRectInMat.left+= deltaL;                            suitableRectInMat.right+= deltaL;                   }                   intdeltaT =                            max(0,int(suitableDisplayRect.top - animationDisplayRect.top));                   if(suitableDisplayRect.top != animationDisplayRect.top) {                            suitableRectInMat.top+= deltaT;                            suitableRectInMat.bottom+= deltaT;                   }                      cv::MatdestPartMat =                            animationDisplayMat(cv::Rect(suitableRectInMat.left,                            suitableRectInMat.top,suitableRectInMat.Width(),                            suitableRectInMat.Height()));                   cv::MatbackgndPartMat = // 目标背景区域相应矩阵                            backGndMat(cv::Rect(suitableDisplayRect.left,                            suitableDisplayRect.top,suitableDisplayRect.Width(),                            suitableDisplayRect.Height()));                   cv::MatmaskPartMat =                            maskMat(cv::Rect(deltaL,deltaT, suitableDisplayRect.Width(),                            suitableDisplayRect.Height()));                   destPartMat.copyTo(backgndPartMat,maskPartMat);         }         GlobalOpenCVObject->PreviewMat(wnd,backGndMat, width, height);}   void __fastcallTCbwAnimationEffect::Assign(TCbwAnimationEffect * other) {         TimerOption.StartMode= other->TimerOption.StartMode;         TimerOption.Delay= other->TimerOption.Delay;         TimerOption.PeriodMode= other->TimerOption.PeriodMode;         TimerOption.RepeatMode= other->TimerOption.RepeatMode;         TimerOption.QuickBackAfterPlay= other->TimerOption.QuickBackAfterPlay;}   bool __fastcallTCbwAnimationEffect::IsAtEnd() {         boolresult = (FPosition >= FPeriodLength * GetRepeateTime());         returnresult;}   void __fastcall TCbwAnimationEffect::First(){         FPosition= 0;         FCurrentIndex= 0;}   void __fastcall TCbwAnimationEffect::Next(){         ++FPosition;         FCurrentIndex= FPosition % FPeriodLength;}   cv::Mat __fastcallTCbwAnimationEffect::Object2Mat(TCbwObject * object,         doubleratio) {         TCanvas* oldCanvas = object->Canvas;         Graphics::TBitmap* bitmap = new Graphics::TBitmap;         bitmap->PixelFormat= pf24bit;         bitmap->Width= object->Width;         bitmap->Height= object->Height;            TCanvas* canvas = bitmap->Canvas;         boolallowDraw = object->AllowDraw;         boololdDrawBorderFlag = object->DrawBorderFlag;         object->AllowDraw= false; {                   TRestoreleft(object, "Left", 0);                   TRestoretop(object, "Top", 0);                   object->Canvas= canvas;                   object->AllowDraw= allowDraw;                   object->DrawBorderFlag= false;                   object->Draw();                   object->AllowDraw= false;         }object->Canvas = oldCanvas;         object->AllowDraw= allowDraw;         object->DrawBorderFlag= oldDrawBorderFlag;         BYTE* backData = THelper::Graphics::GetBitmapData(bitmap);         cv::Matresult;         GlobalOpenCVObject->CopyRGBDatasToMat(result,backData, bitmap->Width,                   bitmap->Height,true);         deletebitmap;         deletebackData;         returnresult;}   void __fastcallTCbwAnimationEffect::OBJECTMAT::BuildMask(int height, int width){         Mask= cv::Mat(height, width, CV_8UC1);         BYTE* pSrc = Mat.data;         BYTE* pDst = Mask.data;         for(int i = height * width - 1; i >= 0; --i) {                   BYTEB = *pSrc++;                   BYTEG = *pSrc++;                   BYTER = *pSrc++;                   *pDst++= (B == 0xFF && G == 0xFF && R == 0xFF) ? 0 : 255;         }}   void __fastcallTCbwAnimationEffect::SetRelativeObject         (CbwObjectsrelativeObjects, TPaintBox * pb, TScrollBox * scrollBox) {         CBW_ITERATOR(CbwObjects,relativeObjects) {                   cv::Matmat = Object2Mat(*it);                   TPointlt = TPoint((*it)->Left, (*it)->Top);                   lt= pb->ClientToScreen(lt);                   lt= scrollBox->ScreenToClient(lt);                   OBJECTMATm;                   m.Mat= mat;                   m.LeftTopPosition= lt;                   m.Object= *it;                   m.BuildMask((*it)->Height,(*it)->Width);                   FDestMats.push_back(m);         }         FPeriodLength= 50;         FCurrentIndex= 0;         FPosition= 0;}   void __fastcallTCbwAnimationEffect::SetBounds(int width, int height) {         FWidth= width;         FHeight= height;}
复制代码

 

 

调用

 

为方便调用处逻辑简单,可采用:

 

复制代码
typedef TCbwAnimationEffect *(*BuildEffectObject)(); // 智能构造函数typedef std::map<int,BuildEffectObject>EffectObjectMap; // 构造各图元对象映射#define CREATEEFFECTOBJECTif(!CbwEffectObjectMap) CbwEffectObjectMap = new EffectObjectMap;  (*CbwEffectObjectMap)…         CREATEEFFECTOBJECT[cetBase]= TCbwAnimationEffect::Build;         CREATEEFFECTOBJECT[cetAppear]= TCbwAnimationEffect_Appear::Build;         CREATEEFFECTOBJECT[cetFadeOut]= TCbwAnimationEffect_FadeOut::Build;         CREATEEFFECTOBJECT[cetFlyIn]= TCbwAnimationEffect_FlyIn::Build;
复制代码

这样,调用时,简单处理即可:

 

复制代码
         if(!(*CbwEffectObjectMap)[effectType]) {                   THelper::Util::MessageBox(L"本动画效果尚未实现,请稍候!", false);             return;         }         TCbwAnimationEffect* effectItem = (*CbwEffectObjectMap)[effectType](); // 根据类型创建动画对象
复制代码

 

调用,先处理用户选中某个对象后的动画类型逻辑

复制代码
void __fastcall TForm::AddEffect(TdxRibbonGalleryGroupItem*AItem) {         if(cSelectedObjects->MetaNumber== 0) return;         inteffectType = AItem->ImageIndex + 1;         if(!(*CbwEffectObjectMap)[effectType]) {                   THelper::Util::MessageBox(L"本动画效果尚未实现,请稍候!", false);             return;         }         TCbwAnimationEffect* effectItem = (*CbwEffectObjectMap)[effectType](); // 根据类型创建动画对象         effectItem->SetRelativeObject(cSelectedObjects->SubObjects,PaintBox, ScrollBox);         effectItem->SetBounds(ScrollBox->Width,ScrollBox->Height);         Graphics::TBitmap* bitmap = new Graphics::TBitmap;         bitmap->PixelFormat= pf24bit;         bitmap->Width= ScrollBox->Width;         bitmap->Height= ScrollBox->Height;            RECTdisplayRect = Rect(ScrollBox->HorzScrollBar->Position,                   ScrollBox->VertScrollBar->Position,ScrollBox->HorzScrollBar->Position +                   ScrollBox->Width,ScrollBox->VertScrollBar->Position +                   ScrollBox->Height);            Graphics::TBitmap* FPreviewBitmap = new Graphics::TBitmap;         FPreviewBitmap->PixelFormat= pf24bit;         FPreviewBitmap->Width= PaintBox->Width;         FPreviewBitmap->Height= PaintBox->Height;         TCanvas* canvas = FPreviewBitmap->Canvas;         canvas->Rectangle(0,0, 10000, 10000);         CBW_ITERATOR(CbwObjects,Objects)(*it)->Canvas = canvas;            CBW_ITERATOR(CbwObjects,Objects) {                   TCbwObject* object = *it;                   if(!CanObjectBeVisible(object) || !object->CanContinueWithRect                            (displayRect,CBW_CONTINUE_DRAW) || object->Selected)                            continue;                   object->Draw();         }         PostPaint(canvas);         bitmap->Canvas->CopyRect(Rect(0,0, bitmap->Width, bitmap->Height), canvas,                   displayRect);         CBW_ITERATOR(CbwObjects,Objects)(*it)->Canvas = PaintBox->Canvas;            TRestoreApplicationCurrentStatus(TGraphApp::CurrentStatus, cfsAnimation);         BYTE* backData = THelper::Graphics::GetBitmapData(bitmap);         effectItem->First();         while(!effectItem->Eof){                   effectItem->Draw(ScrollBox->Handle,backData, bitmap->Width, bitmap->Height);                   effectItem->Next();                   Sleep(10);         }         deletebackData;         deleteFPreviewBitmap;         deletebitmap;         deleteeffectItem;}
复制代码

 

剩下的事情就是针对各动画类型进行细化。

阅读全文
0 0