한달 전쯤인가 언리얼에서 opencv사용하겠다고 한참 해맸는데 정리차 다시 남김
어디 자료 참고했는지는 ppt에 남겨놓긴 했는데 여기다 다시 정리하긴 귀찬아서 돌아가는것까지만 바로간다
새프로젝트 만들고
빈레벨 만들고 플러그인 ㄱㄱ
opencv 검색한뒤 체크, yes
재시작 하라면 재시작하고
대충 새로만든 map을 디폴트로 설정하고
C++ Class로
게임모드베이스 desktopgamemodebase
메인위젯 mainwidget
액터 screen
어떻게 만들지는 나중에 보고 일단 이렇게 생성
메인위젯은 화면 그리기 용도
스크린은 위젯컴포넌트 추가할 액터
c++ 클래스 다만들고 BP도 생성
일단 게임모드베이스에서 웹캠읽어오도록 열고
opencv 인클루드 해보자
플러그인 추가했는데도 못찾는다하면
리프레시 한번 시켜주자
그런데 아직도 안된다.
빌드cs에opencvhelper, opencv 추가하는걸 잊음
추가하고 VS끈다음에 다시 리프레시 VS프로젝트하자
그래도 여전히 DesktopGameModeBase에서 문제가 생겼는데
해더를 이렇게 안하고
#include "PreOpenCVHeaders.h"
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include "PostOpenCVHeaders.h"
평소 opencv 쓸때처럼 opencv.hpp만 넣었기 때문
#include <opencv2/opencv.hpp>
imgproc나 highgui는 필요없는데
PreOpencCVHeaders.h와 PostOpenCVHeaders.h가 꼭 있어야 제대로 빌드된다.
ref : https://forums.unrealengine.com/t/using-unreal-engine-5-0-3-or-5-1-0-built-in-opencv-plugin/744951/2
이걸 추가하는 이유는 기억 잘 안나는데
opencv에서 쓰는거랑 unreal에서 opencv 사용할땐 동작 하는게 다르다고한 일본, 중국인 글을 봤었는데
위 링크 말곤 어디엇는지 몰겟다.
아무튼 mat.hpp도 찾아와 들어와짐
웹캠 스트리밍할수 있도록
헤더는 이렇게 작성
capture, image는 그렇고
블루프린트로 everytick 마다 read frame 호출하도록 UFUNCTION
유저 위젯에 띄우기 위해서 cv::Mat을 UTexture2*D로 바꾸는 함수추가
타 위젯에 쓸수있도록 imageTexutre를 UPROPERTY 등록
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "PreOpenCVHeaders.h"
#include <opencv2/opencv.hpp>
#include "PostOpenCVHeaders.h"
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "DesktopGameModeBase.generated.h"
/**
*
*/
UCLASS()
class HANDDESKTOP_API ADesktopGameModeBase : public AGameModeBase
{
GENERATED_BODY()
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
cv::VideoCapture capture;
cv::Mat image;
UFUNCTION(BlueprintCallable)
void ReadFrame();
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UTexture2D* imageTexture;
UTexture2D* MatToTexture2D(const cv::Mat InMat);
};
구현 내용은 이런식
MatToTexture2D도 어디서 구글링하다 찾은건데 어디서 했던건지 모르겟네
// Fill out your copyright notice in the Description page of Project Settings.
#include "DesktopGameModeBase.h"
void ADesktopGameModeBase::BeginPlay()
{
Super::BeginPlay();
capture = cv::VideoCapture(0);
if (!capture.isOpened())
{
UE_LOG(LogTemp, Log, TEXT("Open Webcam failed"));
return;
}
else
{
UE_LOG(LogTemp, Log, TEXT("Open Webcam Success"));
}
}
void ADesktopGameModeBase::ReadFrame()
{
if (!capture.isOpened())
{
return;
}
capture.read(image);
imageTexture = MatToTexture2D(image);
}
UTexture2D* ADesktopGameModeBase::MatToTexture2D(const cv::Mat InMat)
{
//create new texture, set its values
UTexture2D* Texture = UTexture2D::CreateTransient(InMat.cols, InMat.rows, PF_B8G8R8A8);
if (InMat.type() == CV_8UC3)//example for pre-conversion of Mat
{
cv::Mat bgraImage;
//if the Mat is in BGR space, convert it to BGRA. There is no three channel texture in UE (at least with eight bit)
cv::cvtColor(InMat, bgraImage, cv::COLOR_BGR2BGRA);
//Texture->SRGB = 0;//set to 0 if Mat is not in srgb (which is likely when coming from a webcam)
//other settings of the texture can also be changed here
//Texture->UpdateResource();
//actually copy the data to the new texture
FTexture2DMipMap& Mip = Texture->GetPlatformData()->Mips[0];
void* Data = Mip.BulkData.Lock(LOCK_READ_WRITE);//lock the texture data
FMemory::Memcpy(Data, bgraImage.data, bgraImage.total() * bgraImage.elemSize());//copy the data
Mip.BulkData.Unlock();
Texture->PostEditChange();
Texture->UpdateResource();
return Texture;
}
//if the texture hasnt the right pixel format, abort.
Texture->PostEditChange();
Texture->UpdateResource();
return Texture;
}
빌드 잘되는걸 확인하면 이제 화면을 띄울준비
(핫 리로드 안되면 수동으로 컴파일)
일단 BP_MainWidget에 들어와서
캔버스 판낼에 이미지 넣고 이름 imageWidget, isVariable 설정, 컴파일
이번엔 BP_Screen으로 들어와
Add로 Widget Component 추가
위젯 컴포넌트 이름을 Screen으로 설정하고
드로 사이즈는 640 x 480
위젯 클레스는 방금 그린 BP_MainWidget
맵에 BP_Screen 추가하고 플레이어 스타트 앞에 배치
프로젝트 세팅스에서 GameMode를 아까 만든 BP_DesktopGameModeBase로 설정
실행해보면 아까 게임보드베이스에 작성했던 Open Webcam Success가 로그로 나온걸 확인 가능
이제 웹캠 영상을 화면에 띄울 준비
데스크탑게임모드베이스 블루프린트에서
이벤트 틱에 리드 프레임 연결
리드프레임에선 이미지 가져와서 텍스쳐로 변환함
MainScreen 변수 추가하고
Get All Actors of Class로 뷰포트에 있는 BP_Screen들 가져오기
첫번째(인덱스0) BP_Screen 액터로 Set Widget 준비
Create (BP Main Widget ) widget을 생성 후 MainScreen에 등록
이 MainScreen을 BP_Screen 액터의 Set Widget에 등록
메인 스크린으로부터 이미지 위젯 가져오기
이미지위젯 -> SetBrushFrom Texture 호출, 리드 프레임과 연결
블루프린트 리드라이트 설정한 imageTexture를 등록
실행결과
'컴퓨터과학 > 언리얼' 카테고리의 다른 글
HandDesktop06 - blaze palm 사용하기 (0) | 2024.01.25 |
---|---|
HandDesktop05 - 손 추정을 위한 blaze 추론 코드 살펴보기 (0) | 2024.01.24 |
HandDesktop04 - 다중 모니터 구현하기 (0) | 2024.01.24 |
HandDesktop03 - 다중 모니터 준비하기, 스트리밍 풀 문제 해결 (0) | 2024.01.24 |
HandDesktop02 - 언리얼에 윈도우 화면 띄우기 (0) | 2024.01.23 |