基于UE4+ OpenCV 的混合现实 (webCamera, mix-reality, blue screen matting)

总体效果

       类似混合现实,实现展示玩家玩的VR游戏的实况


基本思想

       利用openCV 插件,通过摄像头获取到玩家在蓝幕中玩游戏的场景,再使用蓝幕技术,对图像做处理,获取玩家的图像;最后和游戏场景进行叠加。

具体实现( UE 4.12,  Opencv 2.4.13)

1, 在UE4 中打开 vs,添加一个class,  继承 Actor, WebCameraReader

2. UE4 中使用OpenCV 插件

     方法一: 使用项目的dll 包含,即在项目中包含 OpenCV 文件中的 include, 然后在dll 中包含  \opencv\build\x64\vc12\lib (64位系统); 

     方法二: 把openCV的dll,做成一个插件调用;具体步骤  整理下插件的写法:① 在项目文件中,添加Plugins 文件夹,之后在Plugins 文件夹里面再创建一个插件的文件夹,比如  Plugins\CoolPlugin;   下面是CoolPlugin 的一些文件夹

     

     uplugin 文件中,是需要编辑一些插件的信息,这些后面会显示在UE编辑器的插件信息中,如下所示,可以有一些关于插件的具体信息

   

[html]  view plain  copy
  1. {  
  2.     "FileVersion": 3,  
  3.     "Version": 1,  
  4.     "VersionName": "1.0",  
  5.     "FriendlyName": "Webcamera",  
  6.     "Description": "Adds web camera support",  
  7.     "Category": "WebcamReader",  
  8.     "CreatedBy": "Milen",  
  9.     "CreatedByURL": "http://blog.csdn.net/himilong/article/details/52829231",  
  10.     "DocsURL": "http://blog.csdn.net/himilong/article/details/52829231",  
  11.     "MarketplaceURL": "",  
  12.     "SupportURL": "http://blog.csdn.net/himilong/article/details/52829231",  
  13.     "Modules": [  
  14.         {  
  15.             "Name": "CoolPlugin",  
  16.             "Type": "Editor",  
  17.             "LoadingPhase": "Default"  
  18.         }  
  19.     ],  
  20.     "EnabledByDefault": false,  
  21.     "CanContainContent": false,  
  22.     "IsBetaVersion": false,  
  23.     "Installed": false  
  24. }  
   在文件夹,ThirdParty 创建OpenCV ,里面我们可以加入需要用到的include(OpenCV\Includes) 文件以及  dll, lib文件(OpenCV\Libraries).

    这些准备工作做好之后,就可以在代码中加载需要用到的lib 文件, dll 文件了。 在 CoolPlugin\Source\CoolPlugin 中,创建CoolPlugin.Buid.cs 文件

    

[html]  view plain  copy
  1. using UnrealBuildTool;  
  2. using System.IO;  
  3. public class CoolPlugin : ModuleRules  
  4. {  
  5.     public CoolPlugin(TargetInfo target)  
  6.     {  
  7.         PrivateDependencyModuleNames.AddRange(  
  8.             new string[] {  
  9.                 "Engine",  
  10.                 "UnrealEd",  
  11.                 "InputCore",  
  12.                 "Core",  
  13.                 "Slate",  
  14.                 "SlateCore",  
  15.                 "EditorStyle",  
  16.                 "CoreUObject",  
  17.                 "CoolPlugin"   // add plugin file name   
  18.             });  
  19.   
  20.         PrivateIncludePaths.AddRange(new[] { "CoolPlugin/Private" });  
  21.   
  22.           LoadOpenCV(target);  //load dll or  lib files  
  23.     }  
  24.     //LoadOpenCV(Target);  
  25.   
  26.     private string ModulePath  
  27.     {  
  28.         get  
  29.         {  
  30.             RulesAssembly r;  
  31.             FileReference CheckProjectFile;  
  32.             UProjectInfo.TryGetProjectForTarget("CoolProject", out CheckProjectFile);  
  33.   
  34.             r = RulesCompiler.CreateProjectRulesAssembly(CheckProjectFile);  
  35.             FileReference f = r.GetModuleFileName(this.GetType().Name);  
  36.   
  37.             return Path.GetDirectoryName(f.CanonicalName);  
  38.   
  39.         }  
  40.         //get { return Path.GetDirectoryName(RulesCompiler.GetModuleFilename(this.GetType().Name)); }  
  41.     }  
  42.     private string ThirdPartyPath  
  43.     {  
  44.         get { return Path.GetFullPath(Path.Combine(ModulePath, "../../ThirdParty/")); }  
  45.     }  
  46.   
  47.     public bool LoadOpenCV(TargetInfo Target)  
  48.     {  
  49.         bool isLibrarySupported = false;  
  50.   
  51.         // Create OpenCV Path   
  52.         string OpenCVPath = Path.Combine(ThirdPartyPath, "OpenCV");  
  53.   
  54.         // Get Library Path   
  55.         string LibPath = "";  
  56.         bool isdebug = Target.Configuration == UnrealTargetConfiguration.Debug && BuildConfiguration.bDebugBuildsActuallyUseDebugCRT;  
  57.         if (Target.Platform == UnrealTargetPlatform.Win64)  
  58.         {  
  59.             LibPath = Path.Combine(OpenCVPath, "Libraries", "Win64");  
  60.             isLibrarySupported = true;  
  61.         }  
  62.         else if (Target.Platform == UnrealTargetPlatform.Win32)  
  63.         {  
  64.             LibPath = Path.Combine(OpenCVPath, "Libraries", "Win32");  
  65.             isLibrarySupported = true;  
  66.         }  
  67.         else  
  68.         {  
  69.             string Err = string.Format("{0} dedicated server is made to depend on {1}. We want to avoid this, please correct module dependencies.", Target.Platform.ToString(), this.ToString()); System.Console.WriteLine(Err);  
  70.         }  
  71.        // PublicIncludePaths.AddRange(new string[] { "<Modulename>/Public", "<Modulename>/Classes" });  
  72.   
  73.         //PublicIncludePaths.AddRange(new string[] { Path.Combine(OpenCVPath, "Includes") });  
  74.         if (isLibrarySupported)  
  75.         {  
  76.             //Add Include path   
  77.             PublicIncludePaths.AddRange(new string[] { Path.Combine(OpenCVPath, "Includes") });  
  78.   
  79.             // Add Library Path   
  80.             PublicLibraryPaths.Add(LibPath);    
  81.   
  82.             if (!isdebug)  
  83.             {  
  84.                 PublicAdditionalLibraries.Add("opencv_imgproc2413.lib");  
  85.   
  86.                 //Add Dynamic Libraries (Debug Version)  
  87.                 PublicDelayLoadDLLs.Add("opencv_imgproc2413.dll");  
  88.   
  89.   
  90.                 PublicAdditionalLibraries.Add("opencv_core2413.lib");  
  91.   
  92.                 //Add Dynamic Libraries (Debug Version)  
  93.                 PublicDelayLoadDLLs.Add("opencv_core2413.dll");  
  94.   
  95.                 PublicAdditionalLibraries.Add("opencv_highgui2413.lib");  
  96.   
  97.                 //Add Dynamic Libraries (Debug Version)  
  98.                 PublicDelayLoadDLLs.Add("opencv_highgui2413.dll");  
  99.             }  
  100.             else  
  101.             {  
  102.                 //Add Static Libraries (Debug Version)  
  103.                 //PublicAdditionalLibraries.Add("opencv_ts300d.lib");  
  104.                 PublicAdditionalLibraries.Add("opencv_imgproc2413d.lib");  
  105.   
  106.                 //Add Dynamic Libraries (Debug Version)  
  107.                 PublicDelayLoadDLLs.Add("opencv_imgproc2413d.dll");  
  108.   
  109.                 PublicAdditionalLibraries.Add("opencv_core2413d.lib");  
  110.   
  111.                 //Add Dynamic Libraries (Debug Version)  
  112.                 PublicDelayLoadDLLs.Add("opencv_core2413d.dll");  
  113.   
  114.                 PublicAdditionalLibraries.Add("opencv_highgui2413d.lib");  
  115.   
  116.                 //Add Dynamic Libraries (Debug Version)  
  117.                 PublicDelayLoadDLLs.Add("opencv_highgui2413d.dll");  
  118.             }  
  119.         }  
  120.   
  121.         Definitions.Add(string.Format("WITH_OPENCV_BINDING={0}", isLibrarySupported ? 1 : 0));  
  122.   
  123.         return isLibrarySupported;  
  124.     }  
  125. }  
      最后,在CoolPlugin\Source\CoolPlugin\Private 中添加插件本身需要用到的代码。


3. 在webcamReader.h 中包含 使用到的OpenCV 中文件

[html]  view plain  copy
  1. #include "opencv2/core.hpp"  
  2. #include "opencv2/highgui.hpp"    
  3. #include "opencv2/imgproc.hpp"  
  4. #include "opencv2/video.hpp"  
 

定义后面需要用到的几个主要用到的函数,onNextVideoFrame() 是在每获取到新的一帧图像之后的event, videoTextur 用来保存每次读取到的帧。 update 顾名思义就是不停的读图像,更新帧。

[html]  view plain  copy
  1. // Fill out your copyright notice in the Description page of Project Settings.  
  2.   
  3. UCLASS()  
  4. class MYPROJECT_API AWebcamReader : public AActor  
  5. {  
  6.     GENERATED_BODY()  
  7.       
  8. public:   
  9.     // Sets default values for this actor's properties  
  10.     AWebcamReader();  
  11.   
  12.     // deallocates memory for the opencv fields  
  13.     ~AWebcamReader();  
  14.   
  15.     // Called when the game starts or when spawned  
  16.     virtual void BeginPlay() override;  
  17.       
  18.     // Called every frame  
  19.     virtual void Tick( float DeltaSeconds ) override;  
  20.   
  21.     // The device ID opened by the Video Stream  
  22.     UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Webcam)  
  23.         int32 CameraID ;  
  24.   
  25.     //UPROPERTY(interp, Category = CameraSettingsmeta = (ShowOnlyInnerProperties))   
  26.     //  struct FPostProcessSettings PostProcessSettings;  
  27.   
  28.     UPROPERTY(interp, BlueprintReadWrite, Category = CameraSettings)//, meta = (ShowOnlyInnerProperties))   
  29.         struct FPostProcessSettings PostProcessSettings;  
  30.   
  31.   
  32.     // If the webcam images should be resized every frame  
  33.     UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Webcam)  
  34.         bool ShouldResize;  
  35.   
  36.     // The targeted resize width and height (width, height)  
  37.     UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Webcam)  
  38.         FVector2D ResizeDeminsions;  
  39.   
  40.     // The rate at which the color data array and video texture is updated (in frames per second)  
  41.     UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Webcam)  
  42.         float RefreshRate;  
  43.   
  44.     // The refresh timer  
  45.     UPROPERTY(BlueprintReadWrite, Category = Webcam)  
  46.         float RefreshTimer;  
  47.   
  48.     // Blueprint Event called every time the video frame is updated  
  49.     UFUNCTION(BlueprintNativeEvent, Category = Webcam)  
  50.         void OnNextVideoFrame();  
  51.   
  52.     // OpenCV fields  
  53.     cv::Mat* frame;  
  54.     cv::VideoCapture* stream;  
  55.     cv::Size* size;  
  56.   
  57.     // OpenCV prototypes  
  58.     void UpdateFrame();  
  59.     void UpdateTexture();  
  60.   
  61.     // If the stream has succesfully opened yet  
  62.     UPROPERTY(BlueprintReadWrite, Category = Webcam)  
  63.         bool isStreamOpen;  
  64.   
  65.     // The videos width and height (width, height)  
  66.     UPROPERTY(BlueprintReadWrite, Category = Webcam)  
  67.         FVector2D VideoSize;  
  68.   
  69.     // The current video frame's corresponding texture  
  70.     UPROPERTY(BlueprintReadWrite, Category = Webcam)  
  71.         UTexture2D* VideoTexture;  
  72.   
  73.     // The current data array  
  74.     UPROPERTY(BlueprintReadWrite, Category = Webcam)  
  75.         TArray<FColor> Data;  
  76.   
  77. protected:  
  78.   
  79.     // Use this function to update the texture rects you want to change:  
  80.     // NOTE: There is a method called UpdateTextureRegions in UTexture2D but it is compiled WITH_EDITOR and is not marked as ENGINE_API so it cannot be linked  
  81.     // from plugins.  
  82.     // FROM: https://wiki.unrealengine.com/Dynamic_Textures  
  83.     void UpdateTextureRegions(UTexture2D* Texture, int32 MipIndex, uint32 NumRegions, FUpdateTextureRegion2D* Regions, uint32 SrcPitch, uint32 SrcBpp, uint8* SrcData, bool bFreeData);  
  84.   
  85.     // Pointer to update texture region 2D struct  
  86.     FUpdateTextureRegion2D* VideoUpdateTextureRegion;  
  87.       
  88. };  


4. cpp 文件, 首先初始化这个类,包含摄像机的ID,更新频率 以及程序用到的变量等

[html]  view plain  copy
  1. AWebcamReader::AWebcamReader()  
  2. {  
  3.     // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.  
  4.     PrimaryActorTick.bCanEverTick = true;  
  5.   
  6.     // Initialize OpenCV and webcam properties  
  7.     CameraID = 0;  
  8.     RefreshRate = 15;  
  9.     isStreamOpen = false;  
  10.     VideoSize = FVector2D(0, 0);  
  11.     ShouldResize = false;  
  12.     ResizeDeminsions = FVector2D(320, 240);  
  13.     stream = new cv::VideoCapture();  
  14.     frame = new cv::Mat();  
  15.     RefreshTimer = 1000000.0f;  
  16. }  

在begin 中,打开摄像机,读取第一帧

[html]  view plain  copy
  1. void AWebcamReader::BeginPlay()  
  2. {  
  3.     Super::BeginPlay();  
  4.       
  5.     stream->open(CameraID);  
  6.     if (stream->isOpened())  
  7.     {  
  8.         //Initialize stream  
  9.         isStreamOpen = true;  
  10.         UpdateFrame();  
  11.         VideoSize = FVector2D(frame->cols, frame->rows);  
  12.         size = new cv::Size(ResizeDeminsions.X, ResizeDeminsions.Y);  
  13.         VideoTexture = UTexture2D::CreateTransient(VideoSize.X, VideoSize.Y);  
  14.         VideoTexture->UpdateResource();  
  15.         VideoUpdateTextureRegion = new FUpdateTextureRegion2D(0, 0, 0, 0, VideoSize.X, VideoSize.Y);  
  16.   
  17.         //Initialize data array  
  18.         Data.Init(FColor(0, 0, 0, 255), VideoSize.X * VideoSize.Y);  
  19.     }  
  20. }  

tick() 函数中进行更新,并不断的调用 onNextVideoFrame(), 这个在后面的蓝图中,需要用到。 updateframe() 读数据,updatetexture()更新videotexture。

[html]  view plain  copy
  1. // Called every frame  
  2. void AWebcamReader::Tick( float DeltaTime )  
  3. {  
  4.     Super::Tick( DeltaTime );  
  5.   
  6.     RefreshTimer += DeltaTime;  
  7.     if (isStreamOpen && RefreshTimer >= 1.0f / RefreshRate)  
  8.     {  
  9.         RefreshTimer -1.0f / RefreshRate;  
  10.         UpdateFrame();  
  11.         UpdateTexture();  
  12.         OnNextVideoFrame();  
  13.     }  
  14.   
  15. }  



5, 新建一个material, 作为后期渲染的材质(material domain 设置为 post process), 按如下蓝图,实现对人物意外的背景色的剔除。其中需要注意 创建的texture parameter,这个在后面的作为 settextureparametervalue 的 paramer name. 如下蓝图的主要思想就是对pix 的RGB 进行分流,背景色 使用sceneTexture, 而人物保持不变. 此处背景是绿色,而绿色,人物的皮肤颜色,或者白色衣服等玩家可能出现颜色的G分量都比较大(),综合就采用相加的方法,作为if判断的A变量。背景色 R+ G 比较小,而人物的颜色比较大。从而区分



6. 编译上面的类之后,回到UE4 的编辑中,新建一个 webCamReader 的蓝图类


7, 使用上面的材质,创建 dynamic material instance,然后动态改变其 parameter value。post process 是添加的 component, 用于后期剔除人物背景。

set unbound 勾选,可以实现全屏的后期效果。这些可以在unreal 文档中查询到,不再叙述。


8, 点击 play 就可以实现本文刚开始的功能了!


Plugin Download:

http://download.csdn.net/detail/himilong/9681340


Reference :


uploadvr.com/epic-unreal-engine-4-mixed-reality-support/

opencv-srf.blogspot.com/2013/05/installing-configuring-opencv-with-vs.html

wiki.unrealengine.com/Integrating_OpenCV_Into_Unreal_Engine_4

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值