한달 전쯤인가 언리얼에서 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를 등록

 

 

 

 

 

실행결과

+ Recent posts