GetDC로 디바이스 컨텍스트 가져와서
주모니터는 가져와지는데 다른 보조모니터는 어떻게 가져오나 해매다가 좋은 참고자료 찾음
https://stackoverflow.com/questions/53329673/c-getdc-all-monitors
위 링크에 따르면 GetDC(0) 하면 전체 모니터 DC를 가져온다고 하는데
BitBlt에서 좌표 설정해야 된다고 하더라
중앙에 위치한 3번 모니터의 시작점은 1920, 0이므로
BitBlt에서 x1 자리 매개변수 값을 1920으로 고치면 3번 보조모니터의 화면이 나온다.
cv::Mat ADesktopGameModeBase::GetScreenToCVMat()
{
HDC hScreenDC = GetDC(NULL);
HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
int screenWidth = GetDeviceCaps(hScreenDC, HORZRES);
int screenHeight = GetDeviceCaps(hScreenDC, VERTRES);
HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, screenWidth, screenHeight);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemoryDC, hBitmap);
BitBlt(hMemoryDC, 0, 0, screenWidth, screenHeight, hScreenDC, 1920, 0, SRCCOPY);
SelectObject(hMemoryDC, hOldBitmap);
cv::Mat matImage(screenHeight, screenWidth, CV_8UC4);
GetBitmapBits(hBitmap, matImage.total() * matImage.elemSize(), matImage.data);
DeleteDC(hScreenDC);
DeleteDC(hMemoryDC);
DeleteObject(hBitmap);
DeleteObject(hOldBitmap);
return matImage;
}
중앙 보조모니터(3번)
이제 세 모니터를 띄우는게 가능할것같다.
일단 스크린부터 3개로 늘리자
배치후 BP_Screen1, 2, 3으로 이름 변경
BP 데스크탑 게임모드베이스에서 기존 코드는 잠깐때고
한번 디스플레이 이름 출력해보면
순서는 섞였지만 나오긴 나온다.
이 디스플레이 이름 확인해서 넣어주면될듯
일단 1, 3, 4화면을 utexture2d로 변환하는 코드 만들어보면
기존 코드는 가능한 나두고
모니터 가로세로길이
이미지텍스처스크린1,2,3
cvmat 이미지스크린1,2,3
함수로 ScreensToCVMats, CVMatsToTextures
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;
void MatToTexture2D(const cv::Mat InMat);
cv::Mat GetScreenToCVMat();
int monitorWidth = 1920;
int monitorHeight = 1080;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UTexture2D* imageTextureScreen1;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UTexture2D* imageTextureScreen2;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UTexture2D* imageTextureScreen3;
cv::Mat imageScreen1;
cv::Mat imageScreen2;
cv::Mat imageScreen3;
void ScreensToCVMats();
void CVMatsToTextures();
};
비긴 플레이에 초기화 코드 추가
#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"));
}
imageTexture = UTexture2D::CreateTransient(monitorWidth, monitorHeight, PF_B8G8R8A8);
imageScreen1 = cv::Mat(monitorHeight, monitorWidth, CV_8UC4);
imageScreen2 = cv::Mat(monitorHeight, monitorWidth, CV_8UC4);
imageScreen3 = cv::Mat(monitorHeight, monitorWidth, CV_8UC4);
imageTextureScreen1 = UTexture2D::CreateTransient(monitorWidth, monitorHeight, PF_B8G8R8A8);
imageTextureScreen2 = UTexture2D::CreateTransient(monitorWidth, monitorHeight, PF_B8G8R8A8);
imageTextureScreen3 = UTexture2D::CreateTransient(monitorWidth, monitorHeight, PF_B8G8R8A8);
}
리드 프레임 수정
void ADesktopGameModeBase::ReadFrame()
{
/*
if (!capture.isOpened())
{
return;
}
capture.read(image);
cv::Mat desktopImage = GetScreenToCVMat();
MatToTexture2D(desktopImage);
*/
ScreensToCVMats();
CVMatsToTextures();
}
모니터 1, 3, 4를 cv::Mat imageScreen1, 2, 3에 저장하는 코드
void ADesktopGameModeBase::ScreensToCVMats()
{
HDC hScreenDC = GetDC(NULL);
HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
int screenWidth = GetDeviceCaps(hScreenDC, HORZRES);
int screenHeight = GetDeviceCaps(hScreenDC, VERTRES);
HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, screenWidth, screenHeight);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemoryDC, hBitmap);
//screen 1
BitBlt(hMemoryDC, 0, 0, screenWidth, screenHeight, hScreenDC, 0, 0, SRCCOPY);
GetBitmapBits(hBitmap, imageScreen1.total() * imageScreen1.elemSize(), imageScreen1.data);
//screen 2
BitBlt(hMemoryDC, 0, 0, screenWidth, screenHeight, hScreenDC, 1920, 0, SRCCOPY);
GetBitmapBits(hBitmap, imageScreen2.total() * imageScreen2.elemSize(), imageScreen2.data);
//screen 3
BitBlt(hMemoryDC, 0, 0, screenWidth, screenHeight, hScreenDC, 3840, 0, SRCCOPY);
GetBitmapBits(hBitmap, imageScreen3.total() * imageScreen3.elemSize(), imageScreen3.data);
SelectObject(hMemoryDC, hOldBitmap);
DeleteDC(hScreenDC);
DeleteDC(hMemoryDC);
DeleteObject(hBitmap);
DeleteObject(hOldBitmap);
}
imageScreen1,2,3을 imageTextureScreen1,2,3에 저장하는 코드
이런 식으로 만들 필요는 없는데
이미지텍스처 스크린을 언리얼 프로퍼티로 설정해서 BP에서 사용하려다가 좀 이상하게 됨
void ADesktopGameModeBase::CVMatsToTextures()
{
for (int i = 0; i < 3; i++)
{
if (i == 0)
{
FTexture2DMipMap& Mip = imageTextureScreen1->GetPlatformData()->Mips[0];
void* Data = Mip.BulkData.Lock(LOCK_READ_WRITE);//lock the texture data
FMemory::Memcpy(Data, imageScreen1.data, imageScreen1.total() * imageScreen1.elemSize());//copy the data
Mip.BulkData.Unlock();
imageTextureScreen1->PostEditChange();
imageTextureScreen1->UpdateResource();
}
else if (i == 1)
{
FTexture2DMipMap& Mip = imageTextureScreen2->GetPlatformData()->Mips[0];
void* Data = Mip.BulkData.Lock(LOCK_READ_WRITE);//lock the texture data
FMemory::Memcpy(Data, imageScreen2.data, imageScreen2.total() * imageScreen2.elemSize());//copy the data
Mip.BulkData.Unlock();
imageTextureScreen2->PostEditChange();
imageTextureScreen2->UpdateResource();
}
else if (i == 2)
{
FTexture2DMipMap& Mip = imageTextureScreen3->GetPlatformData()->Mips[0];
void* Data = Mip.BulkData.Lock(LOCK_READ_WRITE);//lock the texture data
FMemory::Memcpy(Data, imageScreen3.data, imageScreen3.total() * imageScreen3.elemSize());//copy the data
Mip.BulkData.Unlock();
imageTextureScreen3->PostEditChange();
imageTextureScreen3->UpdateResource();
}
}
}
데스크탑 게임모드베이스 블루프린트로 들어와
Screen1,2,3(BP_MainWidget) StrScreen1,2,3(포 이치 루프에서 이름으로 찾아내기 위함) 추가
StrScreen1,2,3의 디폴트 값으로 BP_Screen1, BP_Screen2 , BP_Screen3 으로 설정
BP_Screen 모든 액터 가져와 포 이치 루프
아까 정의한 StrScreen1,2,3으로 액터 확인, BP MainWidget 생성후 Screen 1,2,3에 등록
Screen 1, 2, 3(BP_MainWidget)을 루프로 가져온 Screen(BP_Screen)에 등록
이벤트 틱에서 각 Screen 변수의 imageWidget과 c++에서 설정한 imageTextureScreen(UProperty)로
SetBrushFromTexture로 텍스쳐 드로잉
전체 스크린에 대해 수행한 결과
정리하면 이런형태
'컴퓨터과학 > 언리얼' 카테고리의 다른 글
HandDesktop06 - blaze palm 사용하기 (0) | 2024.01.25 |
---|---|
HandDesktop05 - 손 추정을 위한 blaze 추론 코드 살펴보기 (0) | 2024.01.24 |
HandDesktop03 - 다중 모니터 준비하기, 스트리밍 풀 문제 해결 (0) | 2024.01.24 |
HandDesktop02 - 언리얼에 윈도우 화면 띄우기 (0) | 2024.01.23 |
HandDesktop01 - 언리얼에서 opencv 사용, 웹캠 스트리밍하기 (0) | 2024.01.23 |