zoukankan      html  css  js  c++  java
  • 基于OpenCV的视频图像组态 (2) :动画总体

    写在前面

    本系列博客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;
    
    }

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

  • 相关阅读:
    结构体
    指针
    数组
    银行取款机系统
    函数
    基础
    IOS系统的安装和Vi的操作模式以及简单的指令
    1203.4——循环语句 之 for
    1203.3——循环语句 之 while
    1203.2——条件语句 之 switch语句
  • 原文地址:https://www.cnblogs.com/drgraph/p/7635575.html
Copyright © 2011-2022 走看看