15#include "NiagaraComponent.h"
16#include "Components/PrimitiveComponent.h"
17#include "Materials/Material.h"
18#include "ImageUtils.h"
19#include "Async/Async.h"
20#include "HighResScreenshot.h"
21#include "ImageWriteTask.h"
22#include "ImageWriteQueue.h"
23#include "Misc/DateTime.h"
24#include "Math/Color.h"
25#include "Blueprint/UserWidget.h"
26#include "GameFramework/PlayerController.h"
27#include "GeoReferencingSystem.h"
29ACamera::ACamera(
const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
31 PrimaryActorTick.bCanEverTick =
true;
32 PrimaryActorTick.TickGroup = TG_PostUpdateWork;
34 CaptureRenderTarget = CreateDefaultSubobject<UTextureRenderTarget2D>(FName(*FString::Printf(TEXT(
"CaptureRenderTarget"))));
42 CaptureComponent2D = CreateDefaultSubobject<USceneCaptureComponent2D>(FName(*FString::Printf(TEXT(
"SceneCaptureComponent2D"))));
44 CaptureComponent2D->PrimitiveRenderMode = ESceneCapturePrimitiveRenderMode::PRM_RenderScenePrimitives;
57 UMaterial* PostProcessingMat = Cast<UMaterial>(StaticLoadObject(UMaterial::StaticClass(),
nullptr, *Path));
61 PostProcessSettings.AddBlendable(PostProcessingMat, Weight);
66 FString Msg =
"Failed to add Post processing material to " + Sensor;
76 PostProcessSettings.RemoveBlendable(Material);
106 LogFile = NewObject<ULogFile>(ULogFile::StaticClass());
109 FString FileName =
"camera_metadata";
116 WriteToLogFile(
"image_name, X location, Y location, Z location, yaw rotation, pitch rotation, roll rotation, GPS latitude, GPS longitude, GPS altitude");
120 WriteToLogFile(
"image_name, X location, Y location, Z location, yaw rotation, pitch rotation, roll rotation");
130 UE_LOG(LogTemp, Warning, TEXT(
"Camera.cpp: CaptureComponent2D is nullptr!"));
151 const FString Path =
"/Game/Agrarsense/Materials/PostProcessingMaterials/PhysicLensDistortion.PhysicLensDistortion";
152 PhysicLensDistortion = Cast<UMaterial>(StaticLoadObject(UMaterial::StaticClass(),
nullptr, *Path));
158 UE_LOG(LogTemp, Warning, TEXT(
"Camera.cpp: Added physics lens distortion effect."));
168 UE_LOG(LogTemp, Warning, TEXT(
"Camera.cpp: Removed physics lens distortion effect."));
176 const FString Path =
"/Game/Agrarsense/Materials/PostProcessingMaterials/CameraPostProcessEffects/m_ice_lens_effect";
177 UMaterial* LoadedIceMaterial = Cast<UMaterial>(StaticLoadObject(UMaterial::StaticClass(),
nullptr, *Path));
186 UE_LOG(LogTemp, Warning, TEXT(
"Camera.cpp: Added ice lens effect."));
196 IceMatInstance->SetScalarParameterValue(FName(
"Angle"), parameters.
IceLensEffectAngle);
198 UE_LOG(LogTemp, Warning, TEXT(
"Camera.cpp: Changed ice lens effect parameters."));
208 PostProcessSettings.RemoveBlendable(IceMatInstance);
212 UE_LOG(LogTemp, Warning, TEXT(
"Camera.cpp: Removed ice lens effect."));
227 PostProcessSettings.bOverride_AutoExposureMethod = UsePostProcessingEffects;
228 PostProcessSettings.bOverride_AutoExposureBias = UsePostProcessingEffects;
229 PostProcessSettings.bOverride_AutoExposureMinBrightness = UsePostProcessingEffects;
230 PostProcessSettings.bOverride_AutoExposureMaxBrightness = UsePostProcessingEffects;
231 PostProcessSettings.bOverride_AutoExposureSpeedUp = UsePostProcessingEffects;
232 PostProcessSettings.bOverride_AutoExposureSpeedDown = UsePostProcessingEffects;
233 PostProcessSettings.bOverride_HistogramLogMin = UsePostProcessingEffects;
234 PostProcessSettings.bOverride_HistogramLogMax = UsePostProcessingEffects;
235 PostProcessSettings.bOverride_CameraShutterSpeed = UsePostProcessingEffects;
236 PostProcessSettings.bOverride_CameraISO = UsePostProcessingEffects;
237 PostProcessSettings.bOverride_DepthOfFieldFstop = UsePostProcessingEffects;
238 PostProcessSettings.bOverride_DepthOfFieldMinFstop = UsePostProcessingEffects;
239 PostProcessSettings.bOverride_DepthOfFieldBladeCount = UsePostProcessingEffects;
240 PostProcessSettings.bOverride_FilmSlope = UsePostProcessingEffects;
241 PostProcessSettings.bOverride_FilmToe = UsePostProcessingEffects;
242 PostProcessSettings.bOverride_FilmShoulder = UsePostProcessingEffects;
243 PostProcessSettings.bOverride_FilmWhiteClip = UsePostProcessingEffects;
244 PostProcessSettings.bOverride_FilmBlackClip = UsePostProcessingEffects;
245 PostProcessSettings.bOverride_MotionBlurAmount = UsePostProcessingEffects;
246 PostProcessSettings.bOverride_MotionBlurMax = UsePostProcessingEffects;
247 PostProcessSettings.bOverride_MotionBlurPerObjectSize = UsePostProcessingEffects;
248 PostProcessSettings.bOverride_WhiteTemp = UsePostProcessingEffects;
249 PostProcessSettings.bOverride_WhiteTint = UsePostProcessingEffects;
250 PostProcessSettings.bOverride_ColorContrast = UsePostProcessingEffects;
251 PostProcessSettings.bOverride_SceneFringeIntensity = UsePostProcessingEffects;
252 PostProcessSettings.bOverride_ChromaticAberrationStartOffset = UsePostProcessingEffects;
253 PostProcessSettings.bOverride_AmbientOcclusionIntensity = UsePostProcessingEffects;
254 PostProcessSettings.bOverride_AmbientOcclusionRadius = UsePostProcessingEffects;
255 PostProcessSettings.bOverride_AmbientOcclusionStaticFraction = UsePostProcessingEffects;
256 PostProcessSettings.bOverride_AmbientOcclusionFadeDistance = UsePostProcessingEffects;
257 PostProcessSettings.bOverride_AmbientOcclusionPower = UsePostProcessingEffects;
258 PostProcessSettings.bOverride_AmbientOcclusionBias = UsePostProcessingEffects;
259 PostProcessSettings.bOverride_AmbientOcclusionQuality = UsePostProcessingEffects;
260 PostProcessSettings.bOverride_BloomMethod = UsePostProcessingEffects;
261 PostProcessSettings.bOverride_BloomIntensity = UsePostProcessingEffects;
262 PostProcessSettings.bOverride_BloomThreshold = UsePostProcessingEffects;
263 PostProcessSettings.bOverride_LensFlareIntensity = UsePostProcessingEffects;
264 PostProcessSettings.bOverride_DepthOfFieldFocalDistance = UsePostProcessingEffects;
265 PostProcessSettings.bOverride_DepthOfFieldDepthBlurAmount = UsePostProcessingEffects;
266 PostProcessSettings.bOverride_DepthOfFieldDepthBlurRadius = UsePostProcessingEffects;
305 FString Encoding =
"bgra8";
308 Encoding = Enable16BitFormat ?
"16UC1" :
"8UC1";
313 ImageMsg = MakeShared<ROSMessages::sensor_msgs::Image>();
314 ImageMsg->header.frame_id =
"world";
334 FSoftClassPath WidgetClassPath(TEXT(
"/Game/Agrarsense/Widgets/Camera/WBP_CameraControlsMenu.WBP_CameraControlsMenu_C"));
335 UClass* WidgetClass = WidgetClassPath.TryLoadClass<UUserWidget>();
337 APlayerController* PlayerController = UGameplayStatics::GetPlayerController(GetWorld(), 0);
339 if (WidgetClass && PlayerController)
341 UCameraWidgetBase* WidgetInstance = CreateWidget<UCameraWidgetBase>(PlayerController, WidgetClass);
344 bool ShowGuide =
false;
351 WidgetInstance->
Setup(
this, ShowGuide);
357 bool Resized =
false;
388 SetActorTickEnabled(
false);
393 SetActorTickEnabled(
true);
399 for (int32 i = 0; i < Components.Num(); i++)
401 UPrimitiveComponent* Primitive = Components[i].Get();
413 Super::EndPlay(EndPlayReason);
520 TArray<FCapturedFrameData> Frames =
FrameGrabber->GetCapturedFrames();
523 FCapturedFrameData& LastFrame = Frames.Last();
524 TArray<FColor>& ImageBuffer = LastFrame.ColorBuffer;
531 AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [
this, ImageBuffer]()
560 UE_LOG(LogTemp, Warning, TEXT(
"Camera.cpp: UnrealWindow is nullptr!"));
571 if (SceneViewport.IsValid())
573 EPixelFormat pixelFormat = GetPixelFormatFromRenderTargetFormat(
TextureFormat);
575 FIntPoint Size = SceneViewport->GetSize();
584 FrameGrabber = MakeShareable(
new FFrameGrabber(SceneViewport.ToSharedRef(), Size, pixelFormat));
615 || FrameBuffer.IsEmpty())
625 ImageMsg->data =
const_cast<uint8*
>(
reinterpret_cast<const uint8*
>(FrameBuffer.GetData()));
634 if (FrameBuffer.IsEmpty() || Width == 0 || Height == 0)
639 int32 Size = Width * Height;
640 if (FrameBuffer.Num() != Size)
642 FString Msg =
"Camera sensor: Unable to save Image to disk. FrameBuffer size and resolution don't match!";
647 FString ImageName = FString::Printf(TEXT(
"image_%d.png"),
ImageNumber);
648 FString fullFileName = FString::Printf(TEXT(
"%s%s"), *
FileSavePath, *ImageName);
653 FIntPoint DestSize(Width, Height);
654 TImagePixelData<FColor> PixelData(DestSize);
655 PixelData.Pixels = FrameBuffer;
658 TUniquePtr<FImageWriteTask> ImageTask = MakeUnique<FImageWriteTask>();
659 ImageTask->PixelData = MakeUnique<TImagePixelData<FColor>>(PixelData);
660 ImageTask->Filename = fullFileName;
661 ImageTask->Format = EImageFormat::PNG;
662 ImageTask->CompressionQuality = (int32)EImageCompressionQuality::Default;
663 ImageTask->bOverwriteFile =
true;
664 ImageTask->PixelPreProcessors.Add(TAsyncAlphaWrite<FColor>(255));
667 FHighResScreenshotConfig& HighResScreenshotConfig = GetHighResScreenshotConfig();
668 TFuture<bool> CompletionFuture = HighResScreenshotConfig.ImageWriteQueue->Enqueue(MoveTemp(ImageTask));
679 const FVector ActorPosition = GetActorLocation();
680 const FRotator ActorRotation = GetActorRotation();
687 MetaData = FString::Printf(TEXT(
"%s, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.6f, %.6f, %.2f"), *ImageName, ActorPosition.X, ActorPosition.Y, ActorPosition.Z,
688 ActorRotation.Pitch, ActorRotation.Yaw, ActorRotation.Roll,
689 GeoCoordinates.Latitude, GeoCoordinates.Longitude, GeoCoordinates.Altitude);
693 MetaData = FString::Printf(TEXT(
"%s, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f"), *ImageName, ActorPosition.X, ActorPosition.Y, ActorPosition.Z,
694 ActorRotation.Pitch, ActorRotation.Yaw, ActorRotation.Roll);
704 UE_LOG(LogTemp, Warning, TEXT(
"Camera.cpp: Camera window closed. Destroying Camera sensor.."));
735 CameraShowFlags.SetDynamicShadows(RenderShadows);
736 CameraShowFlags.SetContactShadows(RenderShadows);
737 CameraShowFlags.SetCapsuleShadows(RenderShadows);
746 CameraShowFlags.SetTemporalAA(SetTemporal);
752 if (Width == 0 || Height == 0)
static auto BindTick(ObjectType *Object, FunctionType Function)
void AddPostProcessingMaterial(const FString &Path, float Weight=1.0f)
TSharedPtr< FFrameGrabber > FrameGrabber
void ChangeCameraParameters(FCameraBaseParameters newParameters)
virtual ESensorTypes GetSensorType() const override
FCameraBaseParameters CameraParameters
FOnWindowClosed OnWindowClosedDelegate
virtual void Init(FCameraBaseParameters parameters, bool SimulateSensor=true)
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override
USceneCaptureComponent2D * CaptureComponent2D
void RemovePostProcessingMaterial(UMaterial *Material)
void SaveCameraMetaDataToDisk(const FString &ImageName)
AGeoReferencingSystem * GeoReferencingSystem
void ResizeCamera(int Width=1280, int Height=720)
void SaveImageToDisk(const TArray< FColor > FrameBuffer, int32 Width, int32 Height)
FDelegateHandle OnPostTickDelegate
bool ShouldSimulateCamera
void SetShadowRendering(bool RenderShadows)
void OnWindowClosed(const TSharedRef< SWindow > &Window)
void FrameGrabberCapture()
virtual void SendImageDataToROS(const TArray< FColor > &FrameBuffer, int32 Width, int32 Height)
FDelegateHandle OnPreTickDelegate
UTextureRenderTarget2D * CaptureRenderTarget
void AddWidgetToWindow(UWidget *WidgetToAdd)
TSharedPtr< ROSMessages::sensor_msgs::Image > ImageMsg
bool SaveCurrentFrameToDiskRequested
void SetTemporalAA(bool SetTemporal)
void CreateLogFile() override
UTexture2D * CaptureFrameTexture
void SetupCamera(FCameraBaseParameters parameters)
TWeakObjectPtr< UMaterial > PhysicLensDistortion
void RemoveWidgetFromWindow(UWidget *WidgetToRemove)
FCameraDelegate_OnWindowResized OnCameraWindowResized
void HidePrimitiveComponent(UPrimitiveComponent *PrimitiveComponent)
TEnumAsByte< ETextureRenderTargetFormat > TextureFormat
void ReleaseFrameGrabber()
virtual void EndOfFrameParellel(float DeltaTime)
virtual void AddProcessingToFrameBuffer(TArray< FColor > &buffer)
TSharedPtr< FUnrealWindow > UnrealWindow
virtual void EndOfFrame(UWorld *World, ELevelTick TickType, float DeltaSeconds)
ACamera(const FObjectInitializer &ObjectInitializer)
virtual void PreActorTick(UWorld *World, ELevelTick TickType, float DeltaSeconds)
FCameraDelegate_OnWindowClosed OnCameraWindowClosed
virtual void BeginPlay() override
TWeakObjectPtr< UMaterialInstanceDynamic > IceMaterialInstance
bool ShouldSimulate(const float DeltaSeconds)
bool CanSimulateSensor() const
static FPrimitiveAdded OnPrimitiveAdded
FString GetSensorIdentifier() const
virtual void CreateDataSavePath()
FString GetSensorName() const
void SetSimulateSensor(bool SimulateSensor)
UTopic * GetROSTopic() const
bool IsROSConnected() const
static TArray< TWeakObjectPtr< UPrimitiveComponent > > GetComponentsToHide()
void WriteToLogFile(const FString &Message)
virtual void CreateROSTopic()
static void RemoveTick(FTickEntry TickEntry)
static FTickEntry AddTick(UObject *Object, std::function< void(float)> Function, ETickType Type)
static void Log(const FString &Message, bool LogToTextFile=true, bool LogToROS=true)
static FGeographicCoordinates UnrealToGeographicCoordinates(AGeoReferencingSystem *GeoReferencingSystem, const FVector &Position)
void Create(const FString &FileNameWithoutExtension, FLogFileSettings Settings)
bool UsePhysicLensDistortionEffect
float ExposureMaxBrightness
float IceLensEffectStrength
float MotionBlurMinObjSize
float ExposureMinBrightness
float MotionBlurIntensity
bool PostProcessingEffects
float ChromAberrIntensity
FFileWriteOptions FileWriteOptions
FFileCreationOptions FileCreationOptions