目录
1、UE4中创建几个材质球:其中主要使用到了M_MatColor
1、MyHUD.cpp:添加内容(里面很多的代码暂时没有理解)
1、MyKinect2Test.Build.cs:添加调用的h文件路径、lib文件路径
1、添加dll文件,到时候MyKinect2Test.Build.cs用到什么lib文件,就添加相对应的dll文件。如果少了会报“缺少模块”错误
1、创建蓝图类:Actor类型:BP_MatPlane:显示Kinect抠图画面的plane
2、创建的HUD代码中,先打开kinect、然后运行Kinect、
4、很多代码使用的不理解,直接借鉴参考的项目,复制其中的代码,最终实现了这个效果
5、自己再次做的时候,如果无法实现的话,一定要核对里面的细节:蓝图节点My Mat Dynamic Material、材质名字Tex001 等等
一、目的
1、用Kinect2人物画面抠图显示在UE4中
二、参考
1、固始《三防知识介绍》中的体感项目
三、过程
1、运行效果:
①此时:人物就会在这个plane中抠出来了
1、版本
UE4 4.18.3 (同样的方法在UE4 4.24.3+VS2017上面,vs一直报错1)(同样的方法UE4 4.21.2+VS2015是可以的)(同样的方法UE4 4.23.1+VS2017是可以的)
VS2015
1、新建工程:第三人称类型:MyKinect2Test
MyKinect2Test
1、新建C++类,HUD类型,里面代码都是空的
1、从VS中运行
①点击是
1、UE4中创建几个材质球:其中主要使用到了M_MatColor
My_materials:文件夹
M_CamColor
M_FaceColor
M_MatColor:只设置这个
①param
基础颜色:Tex001,纹理
1、MyHUD.h:添加内容
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "MyKinect2Test.h"//xzy
#include "CoreMinimal.h"
#include "GameFramework/HUD.h"
#include "MyHUD.generated.h"
/**
*
*/
UCLASS()
class MYKINECT2TEST_API AMyHUD : public AHUD
{
GENERATED_BODY()
public:
// Sets default values for this pawn's properties
AMyHUD();
public:
virtual void DrawHUD();
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
// Called every frame
virtual void Tick(float DeltaTime) override;
public:
static void __stdcall CallBackK2Bone(void* pDataSource, void* pClassExample);
static void __stdcall CallBackBodyIndex(INT64 nRelativeTime, BYTE* pBuffer, void* pDataExample);
static void __stdcall CallBackDepth(INT64 nRelativeTime, UINT16* pBuffer, USHORT nDepthMinReliableDistance, USHORT nDepthMaxDistance, void* pDataExample);
static void __stdcall CallBackColor(INT64 nRelativeTime, BYTE* pBuffer, void* pDataExample);
K2_BODY* pBody;
K2_BONE_ADJUST_DATA pParam;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "K2Bone")
bool isTrack;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "K2Bone")
bool bFaceDetect;
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "XZY")
int nDebug;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "XZY")
UTexture2D* MyTex;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "XZY")
UMaterial* MyMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "XZY")
UMaterialInstanceDynamic* MyDynamicMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "XZY")
UTexture2D *MyTexture;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "XZY")
UMaterial* MyFaceMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "XZY")
UMaterialInstanceDynamic* MyFaceDynamicMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "XZY")
UTexture2D *MyFaceTexture;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "XZY")
UMaterial* MyMatMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "XZY")
UMaterialInstanceDynamic* MyMatDynamicMaterial;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "XZY")
UTexture2D *MyMatTexture;
};
1、MyHUD.cpp:添加内容(里面很多的代码暂时没有理解)
①思路:先打开kinect、然后运行Kinect、然后再Tick中不断的设置材质
①构造函数中,设置材质
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyHUD.h"
#include "ConstructorHelpers.h"
#include <iostream>
//Kinect2
float g_nMinX = -0.5f;
float g_nMaxX = 0.5f;
float g_nMinZ = 0.0f;
float g_nMaxZ = 2.0f;
float g_rOffsetX = 0.0f;
float g_rOffsetY = 0.0f;
float g_rScaleX = 1.0f;
float g_rScaleY = 1.0f;
//人脸抠像区间
int g_nFacelumen = 0;
int g_nFaceWidth = 100;
int g_nFaceHeight = 100;
float g_fYaw = 20.0f;
//抠像部分数据
int g_nX = 657;
int g_nY = 0;
int g_nWidth = 706;
int g_nHeight = 1080;
int g_nLumen = 0;
//人脸的中心点
ColorSpacePoint pColorHeadPoint = { 0,0 };
//彩色图像以及人脸对应的数据
char* pColorBodyData = nullptr;
char* pColorBodyFaceData = nullptr;
//抠像
char* pMatData = nullptr;
char* pBodyIndexData = nullptr;
bool bCToDRet = false;
DepthSpacePoint* pColorSP = new DepthSpacePoint[1920 * 1080];
//右手的坐标
float g_cRX = 0;
float g_cRY = 0;
//人脸识别
void* pFace = nullptr;
//Flash
void* pFlash = nullptr;
char fPath[255] = { 0 };
// Sets default values
AMyHUD::AMyHUD()
{
// Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
struct FConstructorStatics
{
ConstructorHelpers::FObjectFinderOptional<UMaterial> mat;
ConstructorHelpers::FObjectFinderOptional<UMaterial> faceMat;
ConstructorHelpers::FObjectFinderOptional<UMaterial> matMat;
FConstructorStatics()
: mat(TEXT("Material'/Game/My_materials/M_CamColor.M_CamColor'")),
faceMat(TEXT("Material'/Game/My_materials/M_FaceColor.M_FaceColor'")),
matMat(TEXT("Material'/Game/My_materials/M_MatColor.M_MatColor'"))
{
}
};
static FConstructorStatics ConstructorStatics;
MyMaterial = ConstructorStatics.mat.Get();
MyFaceMaterial = ConstructorStatics.faceMat.Get();
MyMatMaterial = ConstructorStatics.matMat.Get();
MyTexture = nullptr;
MyDynamicMaterial = nullptr;
MyTex = nullptr;
MyFaceTexture = nullptr;
MyFaceDynamicMaterial = nullptr;
MyMatTexture = nullptr;
MyMatDynamicMaterial = nullptr;
}
void AMyHUD::BeginPlay()
{
Super::BeginPlay();
if (pColorBodyData == nullptr)
{
pColorBodyData = new char[1080 * 1920 * 4];
}
if (pColorBodyFaceData == nullptr)
{
pColorBodyFaceData = new char[g_nFaceHeight * g_nFaceWidth * 4];
}
if (pMatData == nullptr)
{
pMatData = new char[1080 * 1920 * 4];
}
if (pBodyIndexData == nullptr)
{
pBodyIndexData = new char[424 * 512];
}
if (MyTexture == nullptr)
{
MyTexture = UTexture2D::CreateTransient(g_nWidth, g_nHeight, PF_B8G8R8A8);
}
if (MyDynamicMaterial == nullptr)
{
MyDynamicMaterial = UMaterialInstanceDynamic::Create(MyMaterial, this);
}
if (MyFaceDynamicMaterial == nullptr)
{
MyFaceDynamicMaterial = UMaterialInstanceDynamic::Create(MyFaceMaterial, this);
}
if (MyFaceTexture == nullptr)
{
MyFaceTexture = UTexture2D::CreateTransient(g_nFaceWidth, g_nFaceHeight, PF_B8G8R8A8);
}
if (MyMatTexture == nullptr)
{
MyMatTexture = UTexture2D::CreateTransient(g_nWidth, g_nHeight, PF_B8G8R8A8);
}
if (MyMatDynamicMaterial == nullptr)
{
MyMatDynamicMaterial = UMaterialInstanceDynamic::Create(MyMatMaterial, this);
}
isTrack = false;
if (K2Open() != true)
{
int a = -1;
}
if (K2RunBoneBind(this, CallBackK2Bone) != true)
{
}
//运行Kinect
K2Run(this, NULL, CallBackBodyIndex, CallBackDepth, CallBackColor, NULL);
}
void AMyHUD::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
K2Stop();
K2StopBoneBind();
K2Close();
if (pColorBodyData != nullptr)
{
delete[] pColorBodyData;
pColorBodyData = nullptr;
}
if (pColorBodyFaceData != nullptr)
{
delete[] pColorBodyFaceData;
pColorBodyFaceData = nullptr;
}
if (pMatData != nullptr)
{
delete[] pMatData;
pMatData = nullptr;
}
if (pBodyIndexData != nullptr)
{
delete[] pBodyIndexData;
pBodyIndexData = nullptr;
}
}
//测试02:?:扣出人物并且显示在UE4场景中
void AMyHUD::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
//fDeltaTime = DeltaTime;
if (pColorBodyData != nullptr)
{
//更新抠像
if ((g_nX + g_nWidth) > 1920 ||
(g_nY + g_nHeight) > 1080 ||
g_nX < 0 ||
g_nY < 0 ||
g_nWidth <= 0 ||
g_nHeight <= 0 ||
g_nWidth > 1920 ||
g_nHeight > 1080)
{
return;
}
if (pColorBodyData != nullptr)
{
//显示采集的摄像头图像
void* temp_dataPtr = MyMatTexture->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
for (int i = 0; i < g_nHeight; i++)
{
unsigned char* s = (unsigned char*)pMatData + (i + g_nY) * 1920 * 4;
unsigned char* d = (unsigned char*)temp_dataPtr + i * g_nWidth * 4;
for (int j = 0; j < g_nWidth; j++)
{
//从原图的487列往后开始数据更新到目标纹理
d[4 * j + 0] = (s[4 * (j + g_nX) + 0] - g_nLumen) >= 0 ? (s[4 * (j + g_nX) + 0] - g_nLumen) : 0;
d[4 * j + 1] = (s[4 * (j + g_nX) + 1] - g_nLumen) >= 0 ? (s[4 * (j + g_nX) + 1] - g_nLumen) : 0;
d[4 * j + 2] = (s[4 * (j + g_nX) + 2] - g_nLumen) >= 0 ? (s[4 * (j + g_nX) + 2] - g_nLumen) : 0;
d[4 * j + 3] = s[4 * (j + g_nX) + 3];
}
}
MyMatTexture->PlatformData->Mips[0].BulkData.Unlock();
MyMatTexture->UpdateResource();
MyMatDynamicMaterial->SetTextureParameterValue(FName("Tex001"), MyMatTexture);//将MyMatTexture材质中的Text001材质,更改MyMatDynamicMaterial材质
}
}
}
void AMyHUD::DrawHUD()
{
Super::DrawHUD();
}
void AMyHUD::CallBackK2Bone(void* pDataSource, void* pClassExample)
{
AMyHUD* pClass = (AMyHUD*)pClassExample;
K2_BONEBIND_OUT* pData = (K2_BONEBIND_OUT*)pDataSource;
if ((pData == nullptr) || (pClass == nullptr))
{
pClass->isTrack = false;
return;
}
K2_BONE_ADJUST_DATA* pP = pData->adjust;
pClass->pBody = pData->body;
for (int i = 0; i < BODY_COUNT; ++i)
{
if (pClass->pBody[i].trackedid == (UINT64)-1)
{
pClass->isTrack = false;
continue;
}
if (pClass->pBody[i].joints[JointType_SpineMid].Position.Z < g_nMinZ ||
pClass->pBody[i].joints[JointType_SpineMid].Position.Z > g_nMaxZ ||
pClass->pBody[i].joints[JointType_SpineMid].Position.X > g_nMaxX ||
pClass->pBody[i].joints[JointType_SpineMid].Position.X < g_nMinX)
{
pClass->isTrack = false;
continue;
}
if (pClass->pBody[i].joints[JointType_SpineMid].TrackingState != TrackingState_Tracked ||
pClass->pBody[i].joints[JointType_SpineShoulder].TrackingState != TrackingState_Tracked ||
pClass->pBody[i].joints[JointType_ShoulderLeft].TrackingState != TrackingState_Tracked ||
pClass->pBody[i].joints[JointType_ShoulderRight].TrackingState != TrackingState_Tracked ||
pClass->pBody[i].joints[JointType_Neck].TrackingState != TrackingState_Tracked ||
pClass->pBody[i].joints[JointType_Head].TrackingState != TrackingState_Tracked ||
pClass->pBody[i].joints[JointType_KneeLeft].TrackingState != TrackingState_Tracked ||
pClass->pBody[i].joints[JointType_KneeRight].TrackingState != TrackingState_Tracked ||
pClass->pBody[i].joints[JointType_AnkleLeft].TrackingState != TrackingState_Tracked ||
pClass->pBody[i].joints[JointType_AnkleRight].TrackingState != TrackingState_Tracked)
{
pClass->isTrack = false;
continue;
}
if (pClass->pBody[i].joints[JointType_SpineMid].Position.Z <= g_nMaxZ &&
pClass->pBody[i].joints[JointType_SpineMid].Position.Z >= g_nMinZ &&
pClass->pBody[i].joints[JointType_SpineMid].Position.X >= g_nMinX &&
pClass->pBody[i].joints[JointType_SpineMid].Position.X <= g_nMaxX)
{
//tDeltaSum = 0.0f;
pClass->isTrack = true;
//memcpy_s(pColorBodyData, 1080 * 1920 * 4, pData->color, 1080 * 1920 * 4);
memcpy_s(&(pClass->pParam), sizeof(K2_BONE_ADJUST_DATA), &(pP[i]), sizeof(K2_BONE_ADJUST_DATA));
g_cRX = pClass->pBody[i].colorpoints[JointType_HandRight].X / 1920.0f * 1080.0f * g_rScaleX + g_rOffsetX;
g_cRY = pClass->pBody[i].colorpoints[JointType_HandRight].Y / 1080.0f * 1920.0f * g_rScaleY + g_rOffsetY;
memcpy_s(&(pColorHeadPoint), sizeof(ColorSpacePoint), &(pClass->pBody[i].colorpoints[JointType_Head]), sizeof(ColorSpacePoint));
// if (m_nGameStatus == GAME_STATUS::game_wait)
// {
// //待机
// m_nGameStatus = GAME_STATUS::game_count;
//
// if (pFlash != NULL)
// {
// FastFlashPostMouseKeyMessage(pFlash, 0x0100, 32, 0);
// Sleep(100);//单位秒
// }
// }
// else if (m_nGameStatus == GAME_STATUS::game_count)
// {
// //倒计时
//
// }
// else if (m_nGameStatus == GAME_STATUS::game_select || m_nGameStatus == GAME_STATUS::game_run)
// {
// if (g_cRX >= 0 && g_cRX <= 1080 &&
// g_cRY >= 0 && g_cRY <= 1920)
// {
// if (pFlash != NULL)
// {
// FastFlashMCMove(pFlash, "hand_mc", g_cRX, g_cRY);
// }
// }
// }
// break;
}
//GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("height= %f"), height));
}
}
void AMyHUD::CallBackBodyIndex(INT64 nRelativeTime, BYTE* pBuffer, void* pDataExample)
{
if (pBuffer != nullptr)
{
unsigned int len = 512 * 424 * 1;
memcpy_s(pBodyIndexData, len, pBuffer, len);
}
}
void AMyHUD::CallBackDepth(INT64 nRelativeTime, UINT16* pBuffer, USHORT nDepthMinReliableDistance, USHORT nDepthMaxDistance, void* pDataExample)
{
if (pBuffer != nullptr)
{
UINT depthCount = 512 * 424;
UINT colorCount = 1920 * 1080;
bCToDRet = K2ColorToDepth(depthCount, pBuffer, colorCount, pColorSP);
}
}
void AMyHUD::CallBackColor(INT64 nRelativeTime, BYTE* pBuffer, void* pDataExample)
{
if (pBuffer != nullptr)
{
unsigned int len = 1080 * 1920 * 4;
memcpy_s(pColorBodyData, len, pBuffer, len);
if (bCToDRet && pColorSP != nullptr)
{
int colorIndex = 0;
for (unsigned int i = 0; i < 1080; i++)
{
char* pSrc = pColorBodyData + i * 1920 * 4;
char* pDst = pMatData + i * 1920 * 4;
for (unsigned int j = 0; j < 1920; j++)
{
DepthSpacePoint p = pColorSP[colorIndex++];
// Values that are negative infinity means it is an invalid color to depth mapping so we
// skip processing for this pixel
if (p.X != -std::numeric_limits<float>::infinity() && p.Y != -std::numeric_limits<float>::infinity())
{
int depthX = static_cast<int>(p.X + 0.5f);
int depthY = static_cast<int>(p.Y + 0.5f);
if ((depthX >= 0 && depthX < 512) && (depthY >= 0 && depthY < 424))
{
BYTE player = pBodyIndexData[depthX + (depthY * 512)];
// if we're tracking a player for the current pixel, draw from the color camera
if (player != 0xff)
{
// set source for copy to the color pixel
pDst[j * 4 + 0] = pSrc[j * 4 + 0];
pDst[j * 4 + 1] = pSrc[j * 4 + 1];
pDst[j * 4 + 2] = pSrc[j * 4 + 2];
pDst[j * 4 + 3] = pSrc[j * 4 + 3];
}
else
{
// set source for copy to the color pixel
pDst[j * 4 + 0] = 0x00;
pDst[j * 4 + 1] = 0x00;
pDst[j * 4 + 2] = 0x00;
pDst[j * 4 + 3] = 0x00;
}
}
}
else
{
// set source for copy to the color pixel
pDst[j * 4 + 0] = 0x00;
pDst[j * 4 + 1] = 0x00;
pDst[j * 4 + 2] = 0x00;
pDst[j * 4 + 3] = 0x00;
}
}
}
}
}
}
1、MyKinect2Test.Build.cs:添加调用的h文件路径、lib文件路径
// Fill out your copyright notice in the Description page of Project Settings.
using UnrealBuildTool;
using System.IO;
public class VirtualDressMirror : ModuleRules
{
private string ModulePath
{
get { return ModuleDirectory; }
}
public VirtualDressMirror(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
PrivateDependencyModuleNames.AddRange(new string[] { });
// Uncomment if you are using Slate UI
// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
// Uncomment if you are using online features
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
//Fast
PublicIncludePaths.Add(Path.Combine(ModulePath, "../../ThirdParty/Fast/include"));
PublicAdditionalLibraries.Add(Path.Combine(ModulePath, "../../ThirdParty/Fast/lib/Fast_Config.lib"));
PublicAdditionalLibraries.Add(Path.Combine(ModulePath, "../../ThirdParty/Fast/lib/Fast_Flash.lib"));
PublicAdditionalLibraries.Add(Path.Combine(ModulePath, "../../ThirdParty/Fast/lib/FastFaceDetect.lib"));
//TKinect2.0
PublicIncludePaths.Add(Path.Combine(ModulePath, "../../ThirdParty/Kinect2"));
PublicAdditionalLibraries.Add(Path.Combine(ModulePath, "../../ThirdParty/Kinect2/K2.lib"));
}
}
1、文件夹设置:添加lib文件和头文件
1、添加dll文件,到时候MyKinect2Test.Build.cs用到什么lib文件,就添加相对应的dll文件。如果少了会报“缺少模块”错误
1、MyKinect2Test.h:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "AllowWindowsPlatformTypes.h"
#include <windows.h>
#include "HideWindowsPlatformTypes.h"
//Kinect2
#include "../../ThirdParty/Kinect2/K2.h"
#include "../../ThirdParty/Kinect2/K2Matting.h"
#include "../../ThirdParty/Kinect2/K2Bone.h"
#include "../../ThirdParty/Kinect2/K2Face.h"
#define K2Vec32FVector(v) FVector((v).x, (v).y, (v).z)
#define FVector2K2Vec3(v) K2Vec3((v).X, (v).Y, (v).Z)
#define K2Quat2FQuat(q) FQuat((q).x, (q).y, (q).z, (q).w)
#define FQuat2K2Quat(q) K2Quat((q).X, (q).Y, (q).Z, (q).W)
#define K2Quat2FRotator(q) FRotator(K2Quat2FQuat(q))
#define FRotator2K2Quat(r) FQuat2K2Quat(FQuat(r))
// UE与Kinect2坐标系转换
FVector WINAPI K2Coordinate2UECoordinate(FVector k2v);
FQuat WINAPI K2Coordinate2UECoordinate(FQuat k2q);
FVector WINAPI UECoordinate2K2Coordinate(FVector uev);
FQuat WINAPI UECoordinate2K2Coordinate(FQuat ueq);
1、MyKinect2Test.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyKinect2Test.h"
#include "Modules/ModuleManager.h"
IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, MyKinect2Test, "MyKinect2Test" );
//xzy
FVector WINAPI K2Coordinate2UECoordinate(FVector k2v)
{
return FVector(k2v.X, -k2v.Z, k2v.Y);
}
FQuat WINAPI K2Coordinate2UECoordinate(FQuat k2q)
{
float angle;
FVector axis;
k2q.ToAxisAndAngle(axis, angle);
axis = K2Coordinate2UECoordinate(axis);
return FQuat(axis, angle);
}
FVector WINAPI UECoordinate2K2Coordinate(FVector uev)
{
return FVector(uev.X, uev.Z, -uev.Y);
}
FQuat WINAPI UECoordinate2K2Coordinate(FQuat ueq)
{
float angle;
FVector axis;
ueq.ToAxisAndAngle(axis, angle);
axis = UECoordinate2K2Coordinate(axis);
return FQuat(axis, angle);
}
1、创建蓝图类:Actor类型:BP_MatPlane:显示Kinect抠图画面的plane
1、设置显示Kinect人物画面的位置
1、创建基于C++的MyHUD创建蓝图:BP_myHUD
①因为C++的MyHUD类的构造函数中:直接找到了这三个材质球
①创建变量: pBPMatPlane,让其显示体感画面,因为BP_MatPlane里的plane材质会在代码中不断修改获得Kinect的人物抠图画面
①初始化:获得这个组件、Tick里面不断的刷新组件材质
1、设置地图
①想在什么场景中显示,需要进行设置
1、UE4设置:HUD Class
①如果没有自定义的GameMode,那么自定义一个,目的是让游戏类型的HUDClass设置为自己创建的HUD
三、注意:
1、代码中使用到了公司的Kinect库
2、创建的HUD代码中,先打开kinect、然后运行Kinect、
3、里面材质转换的代码,还在研究中,很多地方不理解
4、很多代码使用的不理解,直接借鉴参考的项目,复制其中的代码,最终实现了这个效果