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