Image serialization complete pipeline

This commit is contained in:
nsubiron 2018-09-21 18:16:45 +02:00
parent 396894f10b
commit d0629c9381
31 changed files with 612 additions and 351 deletions

View File

@ -63,6 +63,21 @@ file(GLOB libcarla_carla_rpc_headers
"${libcarla_source_path}/carla/rpc/*.h") "${libcarla_source_path}/carla/rpc/*.h")
install(FILES ${libcarla_carla_rpc_headers} DESTINATION include/carla/rpc) install(FILES ${libcarla_carla_rpc_headers} DESTINATION include/carla/rpc)
file(GLOB libcarla_carla_sensor_headers
"${libcarla_source_path}/carla/sensor/*.cpp"
"${libcarla_source_path}/carla/sensor/*.h")
install(FILES ${libcarla_carla_sensor_headers} DESTINATION include/carla/sensor)
file(GLOB libcarla_carla_sensor_data_headers
"${libcarla_source_path}/carla/sensor/data/*.cpp"
"${libcarla_source_path}/carla/sensor/data/*.h")
install(FILES ${libcarla_carla_sensor_data_headers} DESTINATION include/carla/sensor/data)
file(GLOB libcarla_carla_sensor_s11n_headers
"${libcarla_source_path}/carla/sensor/s11n/*.cpp"
"${libcarla_source_path}/carla/sensor/s11n/*.h")
install(FILES ${libcarla_carla_sensor_s11n_headers} DESTINATION include/carla/sensor/s11n)
file(GLOB libcarla_carla_streaming_headers file(GLOB libcarla_carla_streaming_headers
"${libcarla_source_path}/carla/streaming/*.cpp" "${libcarla_source_path}/carla/streaming/*.cpp"
"${libcarla_source_path}/carla/streaming/*.h") "${libcarla_source_path}/carla/streaming/*.h")

View File

@ -23,6 +23,9 @@ install(FILES ${libcarla_carla_rpc_headers} DESTINATION include/carla/rpc)
file(GLOB libcarla_carla_sensor_headers "${libcarla_source_path}/carla/sensor/*.h") file(GLOB libcarla_carla_sensor_headers "${libcarla_source_path}/carla/sensor/*.h")
install(FILES ${libcarla_carla_sensor_headers} DESTINATION include/carla/sensor) install(FILES ${libcarla_carla_sensor_headers} DESTINATION include/carla/sensor)
file(GLOB libcarla_carla_sensor_data_headers "${libcarla_source_path}/carla/sensor/data/*.h")
install(FILES ${libcarla_carla_sensor_data_headers} DESTINATION include/carla/sensor/data)
file(GLOB libcarla_carla_sensor_s11n_headers "${libcarla_source_path}/carla/sensor/s11n/*.h") file(GLOB libcarla_carla_sensor_s11n_headers "${libcarla_source_path}/carla/sensor/s11n/*.h")
install(FILES ${libcarla_carla_sensor_s11n_headers} DESTINATION include/carla/sensor/s11n) install(FILES ${libcarla_carla_sensor_s11n_headers} DESTINATION include/carla/sensor/s11n)

View File

@ -6,26 +6,24 @@
#pragma once #pragma once
// In this namespace, we use boost::shared_ptr for now to make it compatible
// with boost::python, but it would be nice to make an adaptor for
// std::shared_ptr.
#include <boost/enable_shared_from_this.hpp> #include <boost/enable_shared_from_this.hpp>
#include <boost/make_shared.hpp> #include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
namespace carla { namespace carla {
namespace client {
// Use this SharedPtr (boost::shared_ptr) to keep compatibility with
// boost::python, but it would be nice if in the future we can make a Python
// adaptor for std::shared_ptr.
template <typename T>
using SharedPtr = boost::shared_ptr<T>;
template <typename T> template <typename T>
using EnableSharedFromThis = boost::enable_shared_from_this<T>; using EnableSharedFromThis = boost::enable_shared_from_this<T>;
template <typename T>
using SharedPtr = boost::shared_ptr<T>;
template <typename T, typename ... Args> template <typename T, typename ... Args>
static inline auto MakeShared(Args && ... args) { static inline auto MakeShared(Args && ... args) {
return boost::make_shared<T>(std::forward<Args>(args) ...); return boost::make_shared<T>(std::forward<Args>(args) ...);
} }
} // namespace client
} // namespace carla } // namespace carla

View File

@ -7,8 +7,8 @@
#pragma once #pragma once
#include "carla/Debug.h" #include "carla/Debug.h"
#include "carla/Memory.h"
#include "carla/NonCopyable.h" #include "carla/NonCopyable.h"
#include "carla/client/Memory.h"
#include "carla/client/World.h" #include "carla/client/World.h"
#include "carla/rpc/Actor.h" #include "carla/rpc/Actor.h"

View File

@ -8,9 +8,9 @@
#include "carla/Debug.h" #include "carla/Debug.h"
#include "carla/Iterator.h" #include "carla/Iterator.h"
#include "carla/Memory.h"
#include "carla/NonCopyable.h" #include "carla/NonCopyable.h"
#include "carla/client/ActorBlueprint.h" #include "carla/client/ActorBlueprint.h"
#include "carla/client/Memory.h"
#include <type_traits> #include <type_traits>
#include <unordered_map> #include <unordered_map>

View File

@ -6,13 +6,14 @@
#pragma once #pragma once
#include "carla/Memory.h"
#include "carla/NonCopyable.h" #include "carla/NonCopyable.h"
#include "carla/Time.h" #include "carla/Time.h"
#include "carla/Version.h" #include "carla/Version.h"
#include "carla/client/Control.h" #include "carla/client/Control.h"
#include "carla/client/Memory.h"
#include "carla/client/Transform.h" #include "carla/client/Transform.h"
#include "carla/rpc/Client.h" #include "carla/rpc/Client.h"
#include "carla/sensor/Deserializer.h"
#include "carla/streaming/Client.h" #include "carla/streaming/Client.h"
#include <string> #include <string>
@ -51,8 +52,10 @@ namespace client {
} }
template <typename Functor> template <typename Functor>
void SubscribeToStream(const streaming::Token &token, Functor &&callback) { void SubscribeToStream(const streaming::Token &token, Functor callback) {
_streaming_client.Subscribe(token, std::forward<Functor>(callback)); _streaming_client.Subscribe(token, [callback](auto buffer) {
callback(sensor::Deserializer::Deserialize(std::move(buffer)));
});
} }
std::string GetClientVersion() const { std::string GetClientVersion() const {

View File

@ -1,86 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "carla/Debug.h"
#include "carla/client/Image.h"
#include <cstdint>
#include <cstring>
namespace carla {
namespace client {
/// @todo This object should be shared and packed.
struct FImageHeaderData
{
uint64_t FrameNumber;
uint32_t Width;
uint32_t Height;
uint32_t Type;
float FOV;
};
static std::string GetTypeString(uint32_t type) {
switch (type) {
case 0u: return "None";
case 1u: return "SceneFinal";
case 2u: return "Depth";
case 3u: return "SemanticSegmentation";
default: return "Invalid";
}
}
SharedPtr<Image> Image::FromBuffer(Buffer buffer) {
/// @todo We can avoid making another copy of the buffer here.
if (buffer.size() < sizeof(FImageHeaderData)) {
throw std::invalid_argument("buffer too small to be an image");
}
auto begin = reinterpret_cast<const byte_type *>(buffer.data());
auto image = MakeShared<Image>();
FImageHeaderData data;
std::memcpy(&data, begin, sizeof(data));
image->_frame_number = data.FrameNumber;
image->_width = data.Width;
image->_height = data.Height;
image->_type = GetTypeString(data.Type);
image->_fov = data.FOV;
const auto size = image->GetSize();
DEBUG_ASSERT((size + sizeof(FImageHeaderData)) == buffer.size());
auto raw_data = std::make_unique<byte_type[]>(size);
std::memcpy(raw_data.get(), begin + sizeof(FImageHeaderData), size);
image->_raw_data = std::move(raw_data);
return image;
}
Image::Image() {
Clear();
}
Image::Image(Image &&rhs) {
(*this) = std::move(rhs);
}
Image &Image::operator=(Image &&rhs) {
_width = rhs._width;
_height = rhs._height;
_type = rhs._type;
_fov = rhs._fov;
_raw_data = std::move(rhs._raw_data);
rhs.Clear();
return *this;
}
void Image::Clear() {
_frame_number = 0u;
_width = 0u;
_height = 0u;
_type = "Invalid";
_fov = 0.0f;
_raw_data = nullptr;
}
} // namespace client
} // namespace carla

View File

@ -1,82 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "carla/Buffer.h"
#include "carla/NonCopyable.h"
#include "carla/client/Memory.h"
#include <memory>
namespace carla {
namespace client {
class Image
: public EnableSharedFromThis<Image>,
private NonCopyable {
public:
using byte_type = unsigned char;
static SharedPtr<Image> FromBuffer(Buffer buffer);
Image();
Image(Image &&rhs);
Image &operator=(Image &&rhs);
void Clear();
size_t GetFrameNumber() const {
return _frame_number;
}
size_t GetWidth() const {
return _width;
}
size_t GetHeight() const {
return _height;
}
const std::string &GetType() const {
return _type;
}
float GetFOV() const {
return _fov;
}
byte_type *GetData() {
return _raw_data.get();
}
const byte_type *GetData() const {
return _raw_data.get();
}
size_t GetSize() const {
return 4u * _width * _height;
}
private:
size_t _frame_number;
size_t _width;
size_t _height;
std::string _type;
float _fov;
std::unique_ptr<byte_type[]> _raw_data;
};
} // namespace client
} // namespace carla

View File

@ -7,9 +7,9 @@
#pragma once #pragma once
#include "carla/Debug.h" #include "carla/Debug.h"
#include "carla/Memory.h"
#include "carla/NonCopyable.h" #include "carla/NonCopyable.h"
#include "carla/client/Client.h" #include "carla/client/Client.h"
#include "carla/client/Memory.h"
namespace carla { namespace carla {
namespace client { namespace client {

View File

@ -6,34 +6,40 @@
#pragma once #pragma once
#include "carla/Buffer.h"
#include "carla/Memory.h"
#include "carla/sensor/CompileTimeTypeMap.h" #include "carla/sensor/CompileTimeTypeMap.h"
namespace carla { namespace carla {
namespace sensor { namespace sensor {
class SensorData;
template <typename... Items> template <typename... Items>
class CompositeSerializer : public CompileTimeTypeMap<Items...> { class CompositeSerializer : public CompileTimeTypeMap<Items...> {
using Super = CompileTimeTypeMap<Items...>; using Super = CompileTimeTypeMap<Items...>;
public: public:
using interpreted_type = size_t; /// @todo using interpreted_type = SharedPtr<SensorData>;
template <typename Sensor, typename... Args> template <typename Sensor, typename... Args>
static auto Serialize(Sensor &sensor, Args &&... args) { static Buffer Serialize(Sensor &sensor, Args &&... args) {
using TheSensor = typename std::remove_const<Sensor>::type; using TheSensor = typename std::remove_const<Sensor>::type;
using Serializer = typename Super::template get<TheSensor*>::type; using Serializer = typename Super::template get<TheSensor*>::type;
return Serializer::Serialize(sensor, std::forward<Args>(args)...); return Serializer::Serialize(sensor, std::forward<Args>(args)...);
} }
static interpreted_type Deserialize(Buffer data);
private:
template <size_t Index, typename Data> template <size_t Index, typename Data>
static interpreted_type Deserialize(Data &&data) { static interpreted_type Deserialize_impl(Data &&data) {
using Serializer = typename Super::template get_by_index<Index>::type; using Serializer = typename Super::template get_by_index<Index>::type;
return Serializer::Deserialize(std::forward<Data>(data)); return Serializer::Deserialize(std::forward<Data>(data));
} }
private:
template <typename Data, size_t... Is> template <typename Data, size_t... Is>
static interpreted_type Deserialize_impl(size_t i, Data &&data, std::index_sequence<Is...>) { static interpreted_type Deserialize_impl(size_t i, Data &&data, std::index_sequence<Is...>) {
// This function is equivalent to creating a switch statement with a case // This function is equivalent to creating a switch statement with a case
@ -41,13 +47,11 @@ namespace sensor {
// into a jump table. See https://stackoverflow.com/a/46282159/5308925. // into a jump table. See https://stackoverflow.com/a/46282159/5308925.
interpreted_type result; interpreted_type result;
std::initializer_list<int> ({ std::initializer_list<int> ({
(i == Is ? (result = Deserialize<Is>(std::forward<Data>(data))), 0 : 0)... (i == Is ? (result = Deserialize_impl<Is>(std::forward<Data>(data))), 0 : 0)...
}); });
return result; return result;
} }
public:
template <typename Data> template <typename Data>
static interpreted_type Deserialize(size_t index, Data &&data) { static interpreted_type Deserialize(size_t index, Data &&data) {
return Deserialize_impl( return Deserialize_impl(
@ -59,3 +63,19 @@ namespace sensor {
} // namespace sensor } // namespace sensor
} // namespace carla } // namespace carla
#include "carla/sensor/DataMessage.h"
namespace carla {
namespace sensor {
template <typename... Items>
inline typename CompositeSerializer<Items...>::interpreted_type
CompositeSerializer<Items...>::Deserialize(Buffer data) {
DataMessage message{std::move(data)};
size_t index = message.GetSensorTypeId();
return Deserialize(index, std::move(message));
}
} // namespace sensor
} // namespace carla

View File

@ -0,0 +1,71 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "carla/Buffer.h"
#include "carla/sensor/s11n/SensorHeaderSerializer.h"
#include <cstdint>
#include <iterator>
namespace carla {
namespace sensor {
class DataMessage {
using HeaderSerializer = s11n::SensorHeaderSerializer;
private:
const auto &GetHeader() const {
return HeaderSerializer::Deserialize(_buffer);
}
public:
uint64_t GetSensorTypeId() const {
return GetHeader().sensor_type;
}
uint64_t GetFrameNumber() const {
return GetHeader().frame_number;
}
const rpc::Transform &GetSensorTransform() const {
return GetHeader().sensor_transform;
}
auto begin() {
return _buffer.begin() + HeaderSerializer::header_offset;
}
auto begin() const {
return _buffer.begin() + HeaderSerializer::header_offset;
}
auto end() {
return _buffer.end();
}
auto end() const {
return _buffer.end();
}
size_t size() const {
return std::distance(begin(), end());
}
private:
template <typename... Items>
friend class CompositeSerializer;
DataMessage(Buffer buffer) : _buffer(std::move(buffer)) {}
Buffer _buffer;
};
} // namespace sensor
} // namespace carla

View File

@ -0,0 +1,19 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "carla/sensor/Deserializer.h"
#include "carla/sensor/SensorRegistry.h"
namespace carla {
namespace sensor {
SharedPtr<SensorData> Deserializer::Deserialize(Buffer buffer) {
return SensorRegistry::Deserialize(std::move(buffer));
}
} // namespace sensor
} // namespace carla

View File

@ -0,0 +1,24 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "carla/Buffer.h"
#include "carla/Memory.h"
namespace carla {
namespace sensor {
class SensorData;
class Deserializer {
public:
static SharedPtr<SensorData> Deserialize(Buffer buffer);
};
} // namespace sensor
} // namespace carla

View File

@ -0,0 +1,46 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "carla/Memory.h"
#include "carla/NonCopyable.h"
#include "carla/sensor/DataMessage.h"
namespace carla {
namespace sensor {
/// Base class for all the objects containing data generated by a sensor.
class SensorData
: public EnableSharedFromThis<SensorData>,
private NonCopyable {
protected:
explicit SensorData(const DataMessage &message)
: _frame_number(message.GetFrameNumber()),
_sensor_transform(message.GetSensorTransform()) {}
public:
virtual ~SensorData() = default;
size_t GetFrameNumber() const {
return _frame_number;
}
const rpc::Transform &GetSensorTransform() const {
return _sensor_transform;
}
private:
const size_t _frame_number;
const rpc::Transform _sensor_transform;
};
} // namespace sensor
} // namespace carla

View File

@ -0,0 +1,98 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "carla/Debug.h"
#include "carla/sensor/SensorData.h"
#include <type_traits>
#include <iterator>
namespace carla {
namespace sensor {
namespace data {
template <size_t Offset, typename T>
class Array : public SensorData {
public:
using value_type = T;
using iterator = value_type *;
using const_iterator = typename std::add_const<value_type>::type *;
using size_type = typename std::iterator_traits<iterator>::difference_type;
using pointer = typename std::iterator_traits<iterator>::pointer;
using reference = typename std::iterator_traits<iterator>::reference;
iterator begin() {
return reinterpret_cast<iterator>(_message.begin() + Offset);
}
const_iterator cbegin() const {
return reinterpret_cast<const_iterator>(_message.begin() + Offset);
}
const_iterator begin() const {
return cbegin();
}
iterator end() {
return reinterpret_cast<iterator>(_message.end());
}
const_iterator cend() const {
return reinterpret_cast<const_iterator>(_message.end());
}
const_iterator end() const {
return cend();
}
bool empty() const {
return begin() == end();
}
size_type size() const {
return std::distance(begin(), end());
}
value_type *data() {
return begin();
}
const value_type *data() const {
return begin();
}
reference operator[](size_type i) {
return data()[i];
}
const reference operator[](size_type i) const {
return data()[i];
}
protected:
explicit Array(DataMessage message)
: SensorData(message),
_message(std::move(message)) {
DEBUG_ASSERT(_message.size() >= Offset);
DEBUG_ASSERT((_message.size() - Offset) % sizeof(T) == 0u);
}
const DataMessage &GetMessage() const {
return _message;
}
private:
DataMessage _message;
};
} // namespace data
} // namespace sensor
} // namespace carla

View File

@ -0,0 +1,28 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include <cstdint>
namespace carla {
namespace sensor {
namespace data {
#pragma pack(push, 1)
struct Color {
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t a;
};
#pragma pack(pop)
static_assert(sizeof(Color) == sizeof(uint32_t), "Invalid color size!");
} // namespace data
} // namespace sensor
} // namespace carla

View File

@ -0,0 +1,20 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "carla/sensor/data/Color.h"
#include "carla/sensor/data/ImageTmpl.h"
namespace carla {
namespace sensor {
namespace data {
using Image = ImageTmpl<Color>;
} // namespace data
} // namespace sensor
} // namespace carla

View File

@ -0,0 +1,54 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "carla/Debug.h"
#include "carla/sensor/data/Array.h"
#include "carla/sensor/s11n/ImageSerializer.h"
namespace carla {
namespace sensor {
namespace data {
template <typename T>
class ImageTmpl : public Array<s11n::ImageSerializer::header_offset, T> {
using Super = Array<s11n::ImageSerializer::header_offset, T>;
protected:
using Serializer = s11n::ImageSerializer;
friend Serializer;
explicit ImageTmpl(DataMessage message)
: Super(std::move(message)) {
DEBUG_ASSERT(GetWidth() * GetHeight() == Super::size());
}
private:
const auto &GetHeader() const {
return Serializer::DeserializeHeader(Super::GetMessage());
}
public:
auto GetWidth() const {
return GetHeader().width;
}
auto GetHeight() const {
return GetHeader().height;
}
uint64_t GetFOVAngle() const {
return GetHeader().fov_angle;
}
};
} // namespace data
} // namespace sensor
} // namespace carla

View File

@ -0,0 +1,21 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "carla/sensor/s11n/ImageSerializer.h"
#include "carla/sensor/data/Image.h"
namespace carla {
namespace sensor {
namespace s11n {
SharedPtr<SensorData> ImageSerializer::Deserialize(DataMessage message) {
return SharedPtr<data::Image>(new data::Image{std::move(message)});
}
} // namespace s11n
} // namespace sensor
} // namespace carla

View File

@ -6,44 +6,54 @@
#pragma once #pragma once
#include "carla/Buffer.h" #include "carla/Memory.h"
#include "carla/sensor/DataMessage.h"
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
namespace carla { namespace carla {
namespace sensor { namespace sensor {
class SensorData;
namespace s11n { namespace s11n {
class ImageSerializer { class ImageSerializer {
public:
#pragma pack(push, 1) #pragma pack(push, 1)
struct ImageHeader { struct ImageHeader {
uint32_t width; uint32_t width;
uint32_t height; uint32_t height;
uint32_t type; float fov_angle;
float fov;
}; };
#pragma pack(pop) #pragma pack(pop)
public: constexpr static auto header_offset = sizeof(ImageHeader);
constexpr static auto offset_size = sizeof(ImageHeader); static const ImageHeader &DeserializeHeader(const DataMessage &message) {
return *reinterpret_cast<const ImageHeader *>(message.begin());
}
template <typename Sensor> template <typename Sensor>
static Buffer Serialize(const Sensor &sensor, Buffer bitmap) { static Buffer Serialize(const Sensor &sensor, Buffer bitmap);
DEBUG_ASSERT(bitmap.size() > sizeof(ImageHeader));
ImageHeader header = { static SharedPtr<SensorData> Deserialize(DataMessage message);
sensor.GetImageWidth(),
sensor.GetImageHeight(),
0u, /// @todo
sensor.GetFOVAngle()
};
std::memcpy(bitmap.data(), reinterpret_cast<const void *>(&header), sizeof(header));
return bitmap;
}
}; };
template <typename Sensor>
inline Buffer ImageSerializer::Serialize(const Sensor &sensor, Buffer bitmap) {
DEBUG_ASSERT(bitmap.size() > sizeof(ImageHeader));
ImageHeader header = {
sensor.GetImageWidth(),
sensor.GetImageHeight(),
sensor.GetFOVAngle()
};
std::memcpy(bitmap.data(), reinterpret_cast<const void *>(&header), sizeof(header));
return bitmap;
}
} // namespace s11n } // namespace s11n
} // namespace sensor } // namespace sensor
} // namespace carla } // namespace carla

View File

@ -17,27 +17,14 @@ namespace s11n {
return pool.Pop(); return pool.Pop();
} }
#pragma pack(push, 1)
struct Header {
uint64_t sensor_type;
uint64_t frame_counter;
float sensor_transform[6u];
};
#pragma pack(pop)
Buffer SensorHeaderSerializer::Serialize( Buffer SensorHeaderSerializer::Serialize(
const uint64_t index, const uint64_t index,
const uint64_t frame, const uint64_t frame,
const rpc::Transform transform) { const rpc::Transform transform) {
Header h; Header h;
h.sensor_type = index; h.sensor_type = index;
h.frame_counter = frame; h.frame_number = frame;
h.sensor_transform[0u] = transform.location.x; h.sensor_transform = transform;
h.sensor_transform[1u] = transform.location.y;
h.sensor_transform[2u] = transform.location.z;
h.sensor_transform[3u] = transform.rotation.pitch;
h.sensor_transform[4u] = transform.rotation.yaw;
h.sensor_transform[5u] = transform.rotation.roll;
auto buffer = PopBufferFromPool(); auto buffer = PopBufferFromPool();
buffer.copy_from(reinterpret_cast<const unsigned char *>(&h), sizeof(h)); buffer.copy_from(reinterpret_cast<const unsigned char *>(&h), sizeof(h));
return buffer; return buffer;

View File

@ -8,7 +8,6 @@
#include "carla/Buffer.h" #include "carla/Buffer.h"
#include "carla/rpc/Transform.h" #include "carla/rpc/Transform.h"
#include "carla/sensor/SensorRegistry.h"
namespace carla { namespace carla {
namespace sensor { namespace sensor {
@ -17,17 +16,21 @@ namespace s11n {
class SensorHeaderSerializer { class SensorHeaderSerializer {
public: public:
template <typename Sensor> #pragma pack(push, 1)
static Buffer Serialize(const Sensor &sensor, uint16_t frame_counter) { struct Header {
return Serialize( uint64_t sensor_type;
SensorRegistry::template get<Sensor*>::index, uint64_t frame_number;
frame_counter, rpc::Transform sensor_transform;
sensor.GetActorTransform()); };
} #pragma pack(pop)
private: constexpr static auto header_offset = sizeof(Header);
static Buffer Serialize(uint64_t index, uint64_t frame, rpc::Transform transform); static Buffer Serialize(uint64_t index, uint64_t frame, rpc::Transform transform);
static const Header &Deserialize(const Buffer &message) {
return *reinterpret_cast<const Header *>(message.data());
}
}; };
} // namespace s11n } // namespace s11n

View File

@ -5,8 +5,6 @@
// For a copy, see <https://opensource.org/licenses/MIT>. // For a copy, see <https://opensource.org/licenses/MIT>.
#include <carla/client/Actor.h> #include <carla/client/Actor.h>
#include <carla/client/Image.h>
#include <carla/client/Sensor.h>
#include <carla/client/Vehicle.h> #include <carla/client/Vehicle.h>
#include <boost/python.hpp> #include <boost/python.hpp>
@ -14,25 +12,6 @@
#include <ostream> #include <ostream>
#include <iostream> #include <iostream>
/// Aquires a lock on the Python's Global Interpreter Lock, necessary for
/// calling Python code from a different thread.
///
/// https://wiki.python.org/moin/GlobalInterpreterLock
class GILLockGuard {
public:
GILLockGuard()
: _state(PyGILState_Ensure()) {}
~GILLockGuard() {
PyGILState_Release(_state);
}
private:
PyGILState_STATE _state;
};
namespace carla { namespace carla {
namespace client { namespace client {
@ -46,39 +25,12 @@ namespace client {
return out; return out;
} }
std::ostream &operator<<(std::ostream &out, const Sensor &sensor) {
out << "Sensor(id=" << sensor.GetId() << ", type=" << sensor.GetTypeId() << ')';
return out;
}
} // namespace client } // namespace client
} // namespace carla } // namespace carla
void export_actor() { void export_actor() {
using namespace boost::python; using namespace boost::python;
namespace cc = carla::client; namespace cc = carla::client;
namespace cr = carla::rpc;
class_<cc::Image, boost::noncopyable, boost::shared_ptr<cc::Image>>("Image", no_init)
.add_property("frame_number", &cc::Image::GetFrameNumber)
.add_property("width", &cc::Image::GetWidth)
.add_property("height", &cc::Image::GetHeight)
.add_property("type", +[](const cc::Image &self) -> std::string {
return self.GetType();
})
.add_property("fov", &cc::Image::GetFOV)
.add_property("raw_data", +[](cc::Image &self) {
#if PYTHON3X
//NOTE(Andrei): python37
auto *ptr = PyMemoryView_FromMemory(reinterpret_cast<char *>(self.GetData()), self.GetSize(), PyBUF_READ);
#else
//NOTE(Andrei): python2.7
auto *ptr = PyBuffer_FromMemory(self.GetData(), self.GetSize());
#endif
return object(handle<>(ptr));
})
;
class_<cc::Actor, boost::noncopyable, boost::shared_ptr<cc::Actor>>("Actor", no_init) class_<cc::Actor, boost::noncopyable, boost::shared_ptr<cc::Actor>>("Actor", no_init)
.add_property("id", &cc::Actor::GetId) .add_property("id", &cc::Actor::GetId)
@ -99,34 +51,4 @@ void export_actor() {
.def("set_autopilot", &cc::Vehicle::SetAutopilot, (arg("enabled")=true)) .def("set_autopilot", &cc::Vehicle::SetAutopilot, (arg("enabled")=true))
.def(self_ns::str(self_ns::self)) .def(self_ns::str(self_ns::self))
; ;
class_<cc::Sensor, bases<cc::Actor>, boost::noncopyable, boost::shared_ptr<cc::Sensor>>("Sensor", no_init)
.def("listen", +[](cc::Sensor &self, boost::python::object callback) {
// Make sure the callback is actually callable.
if (!PyCallable_Check(callback.ptr())) {
PyErr_SetString(PyExc_TypeError, "callback argument must be callable!");
throw_error_already_set();
return;
}
// Subscribe to the sensor.
self.Listen([callback](auto message) {
cc::SharedPtr<cc::Image> image;
try {
image = cc::Image::FromBuffer(std::move(message));
} catch (const std::exception &e) {
std::cerr << "exception while parsing the image: " << e.what() << std::endl;
return;
}
GILLockGuard gil_lock;
try {
boost::python::call<void>(callback.ptr(), boost::python::object(image));
} catch (const boost::python::error_already_set &e) {
PyErr_Print();
}
});
}, (arg("callback")))
.def(self_ns::str(self_ns::self))
;
} }

View File

@ -0,0 +1,110 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include <carla/client/Sensor.h>
#include <carla/sensor/SensorData.h>
#include <carla/sensor/data/Image.h>
#include <boost/python.hpp>
#include <ostream>
#include <iostream>
/// Aquires a lock on the Python's Global Interpreter Lock, necessary for
/// calling Python code from a different thread.
///
/// https://wiki.python.org/moin/GlobalInterpreterLock
class GILLockGuard {
public:
GILLockGuard()
: _state(PyGILState_Ensure()) {}
~GILLockGuard() {
PyGILState_Release(_state);
}
private:
PyGILState_STATE _state;
};
namespace carla {
namespace client {
std::ostream &operator<<(std::ostream &out, const Sensor &sensor) {
out << "Sensor(id=" << sensor.GetId() << ", type=" << sensor.GetTypeId() << ')';
return out;
}
} // namespace client
namespace sensor {
namespace data {
std::ostream &operator<<(std::ostream &out, const Image &image) {
out << "Image(" << image.GetWidth() << 'x' << image.GetHeight()
<< ", frame=" << image.GetFrameNumber() << ')';
return out;
}
} // namespace data
} // namespace sensor
} // namespace carla
void export_sensor() {
using namespace boost::python;
namespace cc = carla::client;
namespace cs = carla::sensor;
namespace csd = carla::sensor::data;
class_<cs::SensorData, boost::noncopyable, boost::shared_ptr<cs::SensorData>>("SensorData", no_init)
.add_property("frame_number", &cs::SensorData::GetFrameNumber)
.add_property("transform", +[](const cs::SensorData &self) -> carla::rpc::Transform {
return self.GetSensorTransform();
})
;
class_<csd::Image, bases<cs::SensorData>, boost::noncopyable, boost::shared_ptr<csd::Image>>("Image", no_init)
.add_property("width", &csd::Image::GetWidth)
.add_property("height", &csd::Image::GetHeight)
.add_property("fov", &csd::Image::GetFOVAngle)
.add_property("raw_data", +[](csd::Image &self) {
// An image is an Array<Color>, convert back to buffer of chars.
auto *data = reinterpret_cast<unsigned char *>(self.data());
auto size = sizeof(csd::Image::value_type) * self.size();
#if PYTHON3X // NOTE(Andrei): python37
auto *ptr = PyMemoryView_FromMemory(reinterpret_cast<char *>(data), size, PyBUF_READ);
#else // NOTE(Andrei): python2.7
auto *ptr = PyBuffer_FromMemory(data, size);
#endif
return object(handle<>(ptr));
})
.def(self_ns::str(self_ns::self))
;
class_<cc::Sensor, bases<cc::Actor>, boost::noncopyable, boost::shared_ptr<cc::Sensor>>("Sensor", no_init)
.def("listen", +[](cc::Sensor &self, boost::python::object callback) {
// Make sure the callback is actually callable.
if (!PyCallable_Check(callback.ptr())) {
PyErr_SetString(PyExc_TypeError, "callback argument must be callable!");
throw_error_already_set();
return;
}
// Subscribe to the sensor.
self.Listen([callback](auto message) { // Here we retrieve already the deserialized object.
GILLockGuard gil_lock;
try {
boost::python::call<void>(callback.ptr(), boost::python::object(message));
} catch (const boost::python::error_already_set &e) {
PyErr_Print();
}
});
}, (arg("callback")))
.def(self_ns::str(self_ns::self))
;
}

View File

@ -17,8 +17,8 @@ void export_world() {
.def("get_blueprint_library", &cc::World::GetBlueprintLibrary) .def("get_blueprint_library", &cc::World::GetBlueprintLibrary)
.def("get_spectator", &cc::World::GetSpectator) .def("get_spectator", &cc::World::GetSpectator)
.def("try_spawn_actor", &cc::World::TrySpawnActor, .def("try_spawn_actor", &cc::World::TrySpawnActor,
(arg("blueprint"), arg("transform"), arg("attach_to")=cc::SharedPtr<cc::Actor>())) (arg("blueprint"), arg("transform"), arg("attach_to")=carla::SharedPtr<cc::Actor>()))
.def("spawn_actor", &cc::World::SpawnActor, .def("spawn_actor", &cc::World::SpawnActor,
(arg("blueprint"), arg("transform"), arg("attach_to")=cc::SharedPtr<cc::Actor>())) (arg("blueprint"), arg("transform"), arg("attach_to")=carla::SharedPtr<cc::Actor>()))
; ;
} }

View File

@ -11,6 +11,7 @@
#include "Client.cpp" #include "Client.cpp"
#include "Control.cpp" #include "Control.cpp"
#include "Exception.cpp" #include "Exception.cpp"
#include "Sensor.cpp"
#include "Transform.cpp" #include "Transform.cpp"
#include "World.cpp" #include "World.cpp"
@ -22,6 +23,7 @@ BOOST_PYTHON_MODULE(libcarla) {
export_control(); export_control();
export_blueprint(); export_blueprint();
export_actor(); export_actor();
export_sensor();
export_world(); export_world();
export_client(); export_client();
export_exception(); export_exception();

View File

@ -73,7 +73,10 @@ inline FSensorMessageHeader FDataStream::MakeHeader(const TSensor &Sensor)
{ {
check(IsInGameThread()); check(IsInGameThread());
using Serializer = carla::sensor::s11n::SensorHeaderSerializer; using Serializer = carla::sensor::s11n::SensorHeaderSerializer;
return {Serializer::Serialize(Sensor, GFrameCounter)}; return {Serializer::Serialize(
carla::sensor::SensorRegistry::template get<TSensor*>::index,
GFrameCounter,
Sensor.GetActorTransform())};
} }
inline carla::Buffer FDataStream::PopBufferFromPool() inline carla::Buffer FDataStream::PopBufferFromPool()

View File

@ -22,7 +22,7 @@ class UTextureRenderTarget2D;
/// SetUpSceneCaptureComponent function. /// SetUpSceneCaptureComponent function.
/// ///
/// @warning All the setters should be called before BeginPlay. /// @warning All the setters should be called before BeginPlay.
UCLASS(Abstract) UCLASS()
class CARLA_API ASceneCaptureSensor : public ASensor class CARLA_API ASceneCaptureSensor : public ASensor
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@ -10,7 +10,7 @@
// Offset to keep clear in the buffer for later adding the image header by the // Offset to keep clear in the buffer for later adding the image header by the
// serializer. // serializer.
constexpr auto BUFFER_OFFSET = constexpr auto BUFFER_OFFSET =
carla::sensor::SensorRegistry::get<ASceneCaptureSensor *>::type::offset_size; carla::sensor::SensorRegistry::get<ASceneCaptureSensor *>::type::header_offset;
// ============================================================================= // =============================================================================
// -- Local static methods ----------------------------------------------------- // -- Local static methods -----------------------------------------------------

View File

@ -8,14 +8,14 @@
#include "Carla/Sensor/SensorFactory.h" #include "Carla/Sensor/SensorFactory.h"
#include "Carla/Actor/ActorBlueprintFunctionLibrary.h" #include "Carla/Actor/ActorBlueprintFunctionLibrary.h"
#include "Carla/Sensor/SceneCaptureCamera.h" #include "Carla/Sensor/SceneCaptureSensor.h"
TArray<FActorDefinition> ADeprecatedSensorFactory::GetDefinitions() TArray<FActorDefinition> ADeprecatedSensorFactory::GetDefinitions()
{ {
FActorDefinition Cameras; FActorDefinition Cameras;
bool Success = false; bool Success = false;
UActorBlueprintFunctionLibrary::MakeCameraDefinition( UActorBlueprintFunctionLibrary::MakeCameraDefinition(
{TEXT("camera"), ASceneCaptureCamera::StaticClass()}, {TEXT("camera"), ASceneCaptureSensor::StaticClass()},
Success, Success,
Cameras); Cameras);
check(Success); check(Success);
@ -32,7 +32,7 @@ FActorSpawnResult ADeprecatedSensorFactory::SpawnActor(
{ {
return {}; return {};
} }
auto *Sensor = World->SpawnActorDeferred<ASceneCaptureCamera>( auto *Sensor = World->SpawnActorDeferred<ASceneCaptureSensor>(
Description.Class, Description.Class,
Transform, Transform,
this, this,
@ -46,9 +46,10 @@ FActorSpawnResult ADeprecatedSensorFactory::SpawnActor(
ABFL::RetrieveActorAttributeToInt("image_size_y", Description.Variations, 600)); ABFL::RetrieveActorAttributeToInt("image_size_y", Description.Variations, 600));
Sensor->SetFOVAngle( Sensor->SetFOVAngle(
ABFL::RetrieveActorAttributeToFloat("fov", Description.Variations, 90.0f)); ABFL::RetrieveActorAttributeToFloat("fov", Description.Variations, 90.0f));
Sensor->SetPostProcessEffect( /// @todo No post-process effects available.
PostProcessEffect::FromString( // Sensor->SetPostProcessEffect(
ABFL::RetrieveActorAttributeToString("post_processing", Description.Variations, "SceneFinal"))); // PostProcessEffect::FromString(
// ABFL::RetrieveActorAttributeToString("post_processing", Description.Variations, "SceneFinal")));
} }
UGameplayStatics::FinishSpawningActor(Sensor, Transform); UGameplayStatics::FinishSpawningActor(Sensor, Transform);
return FActorSpawnResult{Sensor}; return FActorSpawnResult{Sensor};

View File

@ -7,7 +7,7 @@
#include "Carla.h" #include "Carla.h"
#include "Carla/Server/TheNewCarlaServer.h" #include "Carla/Server/TheNewCarlaServer.h"
#include "Carla/Sensor/DeprecatedSensor.h" #include "Carla/Sensor/Sensor.h"
#include "GameFramework/SpectatorPawn.h" #include "GameFramework/SpectatorPawn.h"
@ -40,35 +40,6 @@ static void AttachActors(AActor *Child, AActor *Parent)
Child->SetOwner(Parent); Child->SetOwner(Parent);
} }
// =============================================================================
// -- FStreamingSensorDataSink -------------------------------------------------
// =============================================================================
class FStreamingSensorDataSink : public ISensorDataSink {
public:
FStreamingSensorDataSink(carla::streaming::Stream InStream)
: TheStream(InStream) {}
~FStreamingSensorDataSink()
{
UE_LOG(LogCarlaServer, Log, TEXT("Destroying sensor data sink"));
}
void Write(const FSensorDataView &SensorData) final {
auto MakeBuffer = [](FReadOnlyBufferView View) {
return carla::Buffer(boost::asio::buffer(View.GetData(), View.GetSize()));
};
TheStream.Write(
MakeBuffer(SensorData.GetHeader()),
MakeBuffer(SensorData.GetData()));
}
private:
carla::streaming::Stream TheStream;
};
// ============================================================================= // =============================================================================
// -- FTheNewCarlaServer::FPimpl ----------------------------------------------- // -- FTheNewCarlaServer::FPimpl -----------------------------------------------
// ============================================================================= // =============================================================================
@ -138,12 +109,12 @@ private:
{ {
if (ActorView.IsValid()) if (ActorView.IsValid())
{ {
auto *Sensor = Cast<ADeprecatedSensor>(ActorView.GetActor()); auto *Sensor = Cast<ASensor>(ActorView.GetActor());
if (Sensor != nullptr) if (Sensor != nullptr)
{ {
UE_LOG(LogCarlaServer, Log, TEXT("Making a new sensor stream for actor '%s'"), *ActorView.GetActorDescription()->Id); UE_LOG(LogCarlaServer, Log, TEXT("Making a new sensor stream for actor '%s'"), *ActorView.GetActorDescription()->Id);
auto Stream = StreamingServer.MakeStream(); auto Stream = StreamingServer.MakeStream();
Sensor->SetSensorDataSink(MakeShared<FStreamingSensorDataSink>(Stream)); Sensor->SetDataStream(Stream);
return {ActorView, Stream.token()}; return {ActorView, Stream.token()};
} }
} }