CARLA
Loading...
Searching...
No Matches
DVSCamera.cpp
Go to the documentation of this file.
1// Copyright (c) 2020 Robotics and Perception Group (GPR)
2// University of Zurich and ETH Zurich
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
8#include "Carla.h"
10
12#include "carla/ros2/ROS2.h"
13#include <carla/Buffer.h>
14#include <carla/BufferView.h>
16
17#include <util/ue-header-guard-begin.h>
19#include "Async/ParallelFor.h"
20#include "Misc/App.h"
21#include <util/ue-header-guard-end.h>
22
23#include <random>
24#include <cmath>
25#include <algorithm>
26
27static float FColorToGrayScaleFloat(FColor Color)
28{
29 const int32 Sum = 2989 * Color.R + 5870 * Color.G + 1140 * Color.B;
30 return static_cast<float>(Sum * 0.0001);
31}
32
33ADVSCamera::ADVSCamera(const FObjectInitializer &ObjectInitializer)
34 : Super(ObjectInitializer)
35{
38 TEXT("Material'/Carla/PostProcessingMaterials/PhysicLensDistortion.PhysicLensDistortion'"));
39
40 RandomEngine = CreateDefaultSubobject<URandomEngine>(TEXT("RandomEngine"));
41}
42
44{
45 constexpr bool bEnableModifyingPostProcessEffects = true;
46 auto Definition = UActorBlueprintFunctionLibrary::MakeCameraDefinition(TEXT("dvs"), bEnableModifyingPostProcessEffects);
47
49 Cp.Id = TEXT("positive_threshold");
51 Cp.RecommendedValues = { TEXT("0.3") };
52 Cp.bRestrictToRecommended = false;
53
55 Cm.Id = TEXT("negative_threshold");
57 Cm.RecommendedValues = { TEXT("0.3") };
58 Cm.bRestrictToRecommended = false;
59
60 FActorVariation Sigma_Cp;
61 Sigma_Cp.Id = TEXT("sigma_positive_threshold");
63 Sigma_Cp.RecommendedValues = { TEXT("0.0") };
64 Sigma_Cp.bRestrictToRecommended = false;
65
66 FActorVariation Sigma_Cm;
67 Sigma_Cm.Id = TEXT("sigma_negative_threshold");
69 Sigma_Cm.RecommendedValues = { TEXT("0.0") };
70 Sigma_Cm.bRestrictToRecommended = false;
71
72 FActorVariation Refractory_Period;
73 Refractory_Period.Id = TEXT("refractory_period_ns");
74 Refractory_Period.Type = EActorAttributeType::Int;
75 Refractory_Period.RecommendedValues = { TEXT("0") };
76 Refractory_Period.bRestrictToRecommended = false;
77
78 FActorVariation Use_Log;
79 Use_Log.Id = TEXT("use_log");
81 Use_Log.RecommendedValues = { TEXT("True") };
82 Use_Log.bRestrictToRecommended = false;
83
84 FActorVariation Log_EPS;
85 Log_EPS.Id = TEXT("log_eps");
87 Log_EPS.RecommendedValues = { TEXT("0.001") };
88 Log_EPS.bRestrictToRecommended = false;
89
90 Definition.Variations.Append({ Cp, Cm, Sigma_Cp, Sigma_Cm, Refractory_Period, Use_Log, Log_EPS });
91
92 return Definition;
93}
94
95void ADVSCamera::Set(const FActorDescription &Description)
96{
97 Super::Set(Description);
98
100 "positive_threshold",
101 Description.Variations,
102 0.5f);
103
105 "negative_threshold",
106 Description.Variations,
107 0.5f);
108
110 "sigma_positive_threshold",
111 Description.Variations,
112 0.0f);
113
115 "sigma_negative_threshold",
116 Description.Variations,
117 0.0f);
118
120 "refractory_period_ns",
121 Description.Variations,
122 0.0);
123
125 "use_log",
126 Description.Variations,
127 true);
128
130 "log_eps",
131 Description.Variations,
132 1e-03);
133}
134
135void ADVSCamera::PostPhysTick(UWorld *World, ELevelTick TickType, float DeltaTime)
136{
137 TRACE_CPUPROFILER_EVENT_SCOPE(ADVSCamera::PostPhysTick);
138 Super::PostPhysTick(World, TickType, DeltaTime);
139 check(CaptureRenderTarget != nullptr);
140 // This path does not go through ASceneCaptureSensor::ShouldCaptureThisFrame(),
141 // so it needs its own check for a process without an RHI (-nullrhi).
142 if (!HasActorBegunPlay() || !IsValid(this) || !AreClientsListening() || !FApp::CanEverRender())
143 {
144 return;
145 }
146
147 /// Immediate enqueues render commands of the scene at the current time.
149
150 //Super (ASceneCaptureSensor) Capture the Scene in a (UTextureRenderTarget2D) CaptureRenderTarge from the CaptureComponent2D
151 /** Read the image **/
152 TArray<FColor> RawImage;
153 this->ReadPixels(RawImage);
154
155 /** Convert image to gray scale **/
156 if (this->config.use_log)
157 {
158 this->ImageToLogGray(RawImage);
159 }
160 else
161 {
162 this->ImageToGray(RawImage);
163 }
164
165 /** DVS Simulator **/
166 ADVSCamera::DVSEventArray events = this->Simulation(DeltaTime);
167
168 auto FrameIndex = FCarlaEngine::GetFrameCounter();
169 auto DataStream = GetDataStream(*this);
170 DataStream.SetFrameNumber(FrameIndex);
171 auto Buffer = DataStream.PopBufferFromPool();
172
173 // serialize data
174 carla::Buffer BufferReady(carla::sensor::SensorRegistry::Serialize(*this, events, std::move(Buffer)));
175 carla::SharedBufferView BufView = carla::BufferView::CreateFrom(std::move(BufferReady));
176
177 // ROS2
178 #if defined(WITH_ROS2)
179 auto ROS2 = carla::ros2::ROS2::GetInstance();
180 if (ROS2->IsEnabled())
181 {
182 TRACE_CPUPROFILER_EVENT_SCOPE_STR("ROS2 Send");
184 {
185 // get resolution of camera
186 int W = -1, H = -1;
187 float Fov = -1.0f;
188 auto WidthOpt = GetAttribute("image_size_x");
189 if (WidthOpt.has_value())
190 W = FCString::Atoi(*WidthOpt->Value);
191 auto HeightOpt = GetAttribute("image_size_y");
192 if (HeightOpt.has_value())
193 H = FCString::Atoi(*HeightOpt->Value);
194 auto FovOpt = GetAttribute("fov");
195 if (FovOpt.has_value())
196 Fov = FCString::Atof(*FovOpt->Value);
197 AActor* ParentActor = GetAttachParentActor();
198 if (ParentActor)
199 {
200 FTransform LocalTransformRelativeToParent = GetActorTransform().GetRelativeTransform(ParentActor->GetActorTransform());
201 ROS2->ProcessDataFromDVS(DataStream.GetSensorType(), StreamId, LocalTransformRelativeToParent, BufView, W, H, Fov, this);
202 }
203 else
204 {
205 ROS2->ProcessDataFromDVS(DataStream.GetSensorType(), StreamId, DataStream.GetSensorTransform(), BufView, W, H, Fov, this);
206 }
207 }
208 }
209 #endif
210 if (events.size() > 0)
211 {
212 TRACE_CPUPROFILER_EVENT_SCOPE_STR("ADVSCamera Stream Send");
213 /** Send the events **/
214 DataStream.Send(*this, BufView);
215 }
216}
217
218void ADVSCamera::ImageToGray(const TArray<FColor> &image)
219{
220 /** Sanity check **/
221 if (image.Num() != (this->GetImageHeight() * this->GetImageWidth()))
222 return;
223
224 /** Reserve HxW elements **/
225 last_image.SetNumUninitialized(image.Num());
226
227 /** Convert image to gray raw image values, one row per task **/
228 const FColor *Src = image.GetData();
229 float *Dst = last_image.GetData();
230 const int32 Width = this->GetImageWidth();
231 ParallelFor(this->GetImageHeight(), [Src, Dst, Width](int32 Row)
232 {
233 for (int32 i = Row * Width; i < (Row + 1) * Width; ++i)
234 {
235 Dst[i] = FColorToGrayScaleFloat(Src[i]);
236 }
237 });
238}
239
240void ADVSCamera::ImageToLogGray(const TArray<FColor> &image)
241{
242 /** Sanity check **/
243 if (image.Num() != (this->GetImageHeight() * this->GetImageWidth()))
244 return;
245
246 /** Reserve HxW elements **/
247 last_image.SetNumUninitialized(image.Num());
248
249 /** Convert image to log gray values, one row per task **/
250 const FColor *Src = image.GetData();
251 float *Dst = last_image.GetData();
252 const int32 Width = this->GetImageWidth();
253 const float LogEps = this->config.log_eps;
254 ParallelFor(this->GetImageHeight(), [Src, Dst, Width, LogEps](int32 Row)
255 {
256 for (int32 i = Row * Width; i < (Row + 1) * Width; ++i)
257 {
258 Dst[i] = std::log(LogEps + (FColorToGrayScaleFloat(Src[i]) / 255.0));
259 }
260 });
261}
262
264{
265 /** Array of events **/
267
268 /** Sanity check **/
269 if (this->last_image.Num() != (this->GetImageHeight() * this->GetImageWidth()))
270 return events;
271
272 /** Check initialization **/
273 if(this->prev_image.Num() == 0)
274 {
275 /** Set the first rendered image **/
276 this->ref_values = this->last_image;
277 this->prev_image = this->last_image;
278
279 /** Resizes array to given number of elements. New elements will be zeroed.**/
280 this->last_event_timestamp.SetNumZeroed(this->last_image.Num());
281
282 /** Reset current time **/
283 this->current_time = dvs::secToNanosec(this->GetEpisode().GetElapsedGameTime());
284
285 return events;
286 }
287
288 static constexpr float tolerance = 1e-6;
289
290 /** delta time in nanoseconds **/
291 const std::uint64_t delta_t_ns = dvs::secToNanosec(
292 this->GetEpisode().GetElapsedGameTime()) - this->current_time;
293
294 /** Loop along the image size **/
295 for (uint32 y = 0; y < this->GetImageHeight(); ++y)
296 {
297 for (uint32 x = 0; x < this->GetImageWidth(); ++x)
298 {
299 const uint32 i = (this->GetImageWidth() * y) + x;
300 const float itdt = this->last_image[i];
301 const float it = this->prev_image[i];
302 const float prev_cross = this->ref_values[i];
303
304 if (std::fabs (it - itdt) > tolerance)
305 {
306 const float pol = (itdt >= it) ? +1.0 : -1.0;
307 float C = (pol > 0) ? this->config.Cp : this->config.Cm;
308 const float sigma_C = (pol > 0) ? this->config.sigma_Cp : this->config.sigma_Cm;
309
310 if(sigma_C > 0)
311 {
312 C += RandomEngine->GetNormalDistribution(0, sigma_C);
313 constexpr float minimum_contrast_threshold = 0.01;
314 C = std::max(minimum_contrast_threshold, C);
315 }
316 float curr_cross = prev_cross;
317 bool all_crossings = false;
318
319 do
320 {
321 curr_cross += pol * C;
322
323 if ((pol > 0 && curr_cross > it && curr_cross <= itdt)
324 || (pol < 0 && curr_cross < it && curr_cross >= itdt))
325 {
326 const std::uint64_t edt = (curr_cross - it) * delta_t_ns / (itdt - it);
327 const std::int64_t t = this->current_time + edt;
328
329 // check that pixel (x,y) is not currently in a "refractory" state
330 // i.e. |t-that last_timestamp(x,y)| >= refractory_period
331 const std::int64_t last_stamp_at_xy = dvs::secToNanosec(this->last_event_timestamp[i]);
332 if (t >= last_stamp_at_xy)
333 {
334 const std::uint64_t dt = t - last_stamp_at_xy;
335 if(this->last_event_timestamp[i] == 0 || dt >= this->config.refractory_period_ns)
336 {
337 events.push_back(::carla::sensor::data::DVSEvent(x, y, t, pol > 0));
339 }
340 else
341 {
342 /** Dropping event because time since last event < refractory_period_ns **/
343 }
344 this->ref_values[i] = curr_cross;
345 }
346 }
347 else
348 {
349 all_crossings = true;
350 }
351 } while (!all_crossings);
352 } // end tolerance
353 } // end for each pixel
354 }
355
356 /** Update current time **/
357 this->current_time = dvs::secToNanosec(this->GetEpisode().GetElapsedGameTime());
358
359 this->prev_image = this->last_image;
360
361 // Sort the events by increasing timestamps, since this is what
362 // most event processing algorithms expect
363 std::sort(events.begin(), events.end(), [](const ::carla::sensor::data::DVSEvent& it1, const ::carla::sensor::data::DVSEvent& it2){return it1.t < it2.t;});
364
365 return events;
366}
float y
float x
static float FColorToGrayScaleFloat(FColor Color)
Definition DVSCamera.cpp:27
static bool IsValid(const ACarlaWheeledVehicle *Vehicle)
std::vector<::carla::sensor::data::DVSEvent > DVSEventArray
Definition DVSCamera.h:49
ADVSCamera(const FObjectInitializer &ObjectInitializer)
Definition DVSCamera.cpp:33
TArray< float > prev_image
Definition DVSCamera.h:64
dvs::Config config
DVS simulation configuration.
Definition DVSCamera.h:76
void Set(const FActorDescription &ActorDescription) override
Definition DVSCamera.cpp:95
TArray< double > last_event_timestamp
Image containing time of last event in seconds.
Definition DVSCamera.h:70
ADVSCamera::DVSEventArray Simulation(float DeltaTime)
static FActorDefinition GetSensorDefinition()
Definition DVSCamera.cpp:43
void ImageToLogGray(const TArray< FColor > &image)
TArray< float > last_image
Images containing last (current) and previous image.
Definition DVSCamera.h:64
void ImageToGray(const TArray< FColor > &image)
TArray< float > ref_values
Image containing the last reference value to trigger event.
Definition DVSCamera.h:67
virtual void PostPhysTick(UWorld *World, ELevelTick TickType, float DeltaTime) override
std::int64_t current_time
Current time in nanoseconds.
Definition DVSCamera.h:73
bool ReadPixels(TArray< FColor > &BitMap) const
Use for debugging purposes only.
TObjectPtr< UTextureRenderTarget2D > CaptureRenderTarget
Render target necessary for scene capture.
void EnablePostProcessingEffects(bool Enable=true)
uint32 GetImageHeight() const
uint32 GetImageWidth() const
void WaitForRenderThreadToFinish()
Blocks until the render thread has finished all it's tasks.
auto GetToken() const
Return the token that allows subscribing to this sensor's stream.
FAsyncDataStream GetDataStream(SensorType &&Self)
Return the FDataStream associated with this sensor.
std::optional< FActorAttribute > GetAttribute(const FString Name)
Definition Sensor.cpp:59
URandomEngine * RandomEngine
Random Engine used to provide noise for sensor output.
bool AddPostProcessingMaterial(const FString &Path)
Load the UMaterialInstanceDynamic at the given Path and append it to the list of shaders with Weight.
static uint64_t GetFrameCounter()
Definition CarlaEngine.h:73
static int32 RetrieveActorAttributeToInt(const FString &Id, const TMap< FString, FActorAttribute > &Attributes, int32 Default)
static FActorDefinition MakeCameraDefinition(const FString &Id, bool bEnableModifyingPostProcessEffects=false)
static float RetrieveActorAttributeToFloat(const FString &Id, const TMap< FString, FActorAttribute > &Attributes, float Default)
static bool RetrieveActorAttributeToBool(const FString &Id, const TMap< FString, FActorAttribute > &Attributes, bool Default)
float GetNormalDistribution(float Mean, float StandardDeviation)
static std::shared_ptr< BufferView > CreateFrom(Buffer &&buffer)
Definition BufferView.h:56
A piece of raw data.
static std::shared_ptr< ROS2 > GetInstance()
Definition ROS2.h:61
static Buffer Serialize(Sensor &sensor, Args &&... args)
Serialize the arguments provided into a Buffer by calling to the serializer registered for the given ...
Serializes a stream endpoint.
std::shared_ptr< BufferView > SharedBufferView
Definition BufferView.h:151
constexpr std::int64_t secToNanosec(double seconds)
Definition DVSCamera.h:32
constexpr double nanosecToSecTrunc(std::int64_t nanoseconds)
Definition DVSCamera.h:37
A definition of a Carla Actor with all the variation and attributes.
A description of a Carla Actor with all its variation.
TMap< FString, FActorAttribute > Variations
User selected variations of the actor.
float sigma_Cp
Definition DVSCamera.h:25
std::uint64_t refractory_period_ns
Definition DVSCamera.h:27
bool use_log
Definition DVSCamera.h:28
float log_eps
Definition DVSCamera.h:29
float sigma_Cm
Definition DVSCamera.h:26