.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7d68e09
--- /dev/null
+++ b/README.md
@@ -0,0 +1,38 @@
+
+
+
+Reusable Utilities in Single Headers is a collection of header-only utilities for C++
+
+
+
+## ⚙️ Using RUSH in Your Project
+```bash
+git submodule add -b submodule https://github.com/raultapia/rush include/rush
+```
+
+## 🖥️ List of Utilities
+|Name|Include|Namespace|
+|:-|:-|:-:|
+|Chrono|`#include `|`rush::chrono`|
+|OpenCV HighGUI|`#include `|`rush::cv`|
+|ROS-OpenCV Bridge|`#include `|`rush::roscv`|
+|ROS Parameter Manager|`#include `|`rush::ros`|
+
+## 📚 Documentation
+RUSH documentation can be found [here](https://raultapia.github.io/rush).
+
+## 📝 License
+
+Distributed under the GPLv3 License. See [`LICENSE`](https://github.com/raultapia/rush/tree/main/LICENSE) for more information.
+
+## 📬 Contact
+
+[Raul Tapia](https://raultapia.com) - raultapia@us.es
diff --git a/docs/Doxyfile b/docs/Doxyfile
new file mode 100644
index 0000000..663b29f
--- /dev/null
+++ b/docs/Doxyfile
@@ -0,0 +1,9 @@
+PROJECT_NAME = RUSH
+PROJECT_BRIEF = "Reusable Utilities in Single Headers is a collection of header-only utilities for C++"
+PROJECT_LOGO = rush.png
+USE_MDFILE_AS_MAINPAGE = ../README.md
+GENERATE_HTML = YES
+USE_MATHJAX = YES
+RECURSIVE = YES
+INPUT = ..
+OUTPUT_DIRECTORY = .
diff --git a/docs/rush.png b/docs/rush.png
new file mode 100644
index 0000000..c47acf2
Binary files /dev/null and b/docs/rush.png differ
diff --git a/include/rush/chrono.hpp b/include/rush/chrono.hpp
new file mode 100644
index 0000000..bfff657
--- /dev/null
+++ b/include/rush/chrono.hpp
@@ -0,0 +1,116 @@
+/**
+ * @file chrono.hpp
+ * @brief This library provides chrono utilities.
+ * @author Raul Tapia (raultapia.com)
+ */
+#ifndef RUSH_CHRONO_HPP
+#define RUSH_CHRONO_HPP
+
+#include
+#include
+#include
+#include
+#include
+
+namespace rush::chrono {
+
+/*! \cond INTERNAL */
+#define DEFINE_UNIT_MACRO(name, unit) \
+ template <> \
+ struct Unit { \
+ static constexpr const char *str() { \
+ return unit; \
+ } \
+ };
+
+template
+struct Unit;
+
+DEFINE_UNIT_MACRO(std::nano, "ns")
+DEFINE_UNIT_MACRO(std::micro, "us")
+DEFINE_UNIT_MACRO(std::milli, "ms")
+DEFINE_UNIT_MACRO(std::ratio<1>, "s")
+DEFINE_UNIT_MACRO(std::ratio<60>, "min")
+DEFINE_UNIT_MACRO(std::ratio<3600>, "h")
+DEFINE_UNIT_MACRO(std::ratio<86400>, "day")
+/*! \endcond */
+
+using ns = std::nano; ///< Convenience alias for nanoseconds
+using us = std::micro; ///< Convenience alias for microseconds
+using ms = std::milli; ///< Convenience alias for milliseconds
+using s = std::ratio<1>; ///< Convenience alias for seconds
+using min = std::ratio<60>; ///< Convenience alias for minutes
+using hour = std::ratio<3600>; ///< Convenience alias for hours
+using day = std::ratio<86400>; ///< Convenience alias for days
+
+/**
+ * @brief A simple chrono class to measure elapsed time.
+ *
+ * @tparam T Unit of time (default to seconds).
+ */
+template
+class Chrono {
+public:
+ Chrono() : t0_(std::chrono::high_resolution_clock::now()) {}
+ ~Chrono() = default;
+ Chrono(const Chrono &) = delete;
+ Chrono(Chrono &&) noexcept = delete;
+ Chrono &operator=(const Chrono &) = delete;
+ Chrono &operator=(Chrono &&other) noexcept = delete;
+
+ /**
+ * @brief Reset the chrono timer.
+ *
+ */
+ inline void tic() {
+ t0_ = std::chrono::high_resolution_clock::now();
+ }
+
+ /**
+ * @brief Get elapsed time since last tic.
+ *
+ * @return Elapsed time in the specified unit.
+ */
+ [[nodiscard]] inline double toc() const {
+ return std::chrono::duration_cast>(std::chrono::high_resolution_clock::now() - t0_).count();
+ }
+
+private:
+ std::chrono::time_point t0_;
+};
+
+/**
+ * @brief A chrono class that automatically prints elapsed time.
+ *
+ * @tparam T Unit of time (default to seconds).
+ */
+template
+class Chronometer : public Chrono {
+public:
+ /**
+ * @brief Constructor.
+ *
+ * @param name Optional name to be printed along with elapsed time.
+ */
+ explicit Chronometer(std::string name = "") : name_{std::move(name)} {}
+
+ ~Chronometer() {
+ double t = Chrono::toc();
+ if(!name_.empty()) {
+ std::cout << "[" << name_ << "] ";
+ }
+ std::cout << "Elapsed time: " << t << " " << Unit().str() << std::endl;
+ }
+
+ Chronometer(const Chronometer &) = delete;
+ Chronometer(Chronometer &&) noexcept = delete;
+ Chronometer &operator=(const Chronometer &) = delete;
+ Chronometer &operator=(Chronometer &&other) noexcept = delete;
+
+private:
+ std::string name_;
+};
+
+} // namespace rush::chrono
+
+#endif // RUSH_CHRONO_HPP
diff --git a/include/rush/cv-highgui.hpp b/include/rush/cv-highgui.hpp
new file mode 100644
index 0000000..0e9064d
--- /dev/null
+++ b/include/rush/cv-highgui.hpp
@@ -0,0 +1,80 @@
+/**
+ * @file cv-highgui.hpp
+ * @brief This library extends OpenCV's HighGUI functionalities.
+ * @author Raul Tapia (raultapia.com)
+ */
+#ifndef RUSH_CV_HIGHGUI_HPP
+#define RUSH_CV_HIGHGUI_HPP
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace rush::cv {
+
+/**
+ * @brief Create a montage from a matrix of images.
+ *
+ * This function takes a vector of vectors of images and creates a montage by resizing and concatenating them.
+ *
+ * @param images Vector of vectors of images.
+ * @return A single montage image.
+ */
+inline ::cv::Mat montage(std::vector> &images) {
+ ::cv::Mat montage;
+ ::cv::Size ref{images[0][0].size()};
+ std::size_t max_col = 0;
+
+ for(const std::vector<::cv::Mat> &v : images) {
+ for(const ::cv::Mat &i : v) {
+ if(i.size().area() < ref.area()) {
+ ref = i.size();
+ }
+ max_col = std::max(max_col, v.size());
+ }
+ }
+
+ std::vector<::cv::Mat> rows;
+ for(std::vector<::cv::Mat> &v : images) {
+ for(::cv::Mat &i : v) {
+ ::cv::resize(i, i, ref);
+ }
+ while(v.size() < max_col) {
+ v.emplace_back(ref, images[0][0].type(), ::cv::Scalar(0));
+ }
+ rows.emplace_back(v.size() * ref.width, ref.height, images[0][0].type());
+ ::cv::hconcat(v.data(), v.size(), rows.back());
+ }
+ ::cv::vconcat(rows.data(), rows.size(), montage);
+ return montage;
+}
+
+/**
+ * @brief Create a montage from a vector of images with a specified step.
+ *
+ * This function takes a vector of images and creates a montage with a specified step by calling the main montage function.
+ *
+ * @param images Vector of images.
+ * @param step Step size for selecting images.
+ * @return A single montage image.
+ * @see montage(std::vector> &images)
+ */
+inline ::cv::Mat montage(std::vector<::cv::Mat> &images, std::size_t step = 0) {
+ std::vector> img_vector;
+ if(!static_cast(step)) {
+ step = images.size();
+ }
+ for(std::size_t i = 0; i < images.size(); i += step) {
+ img_vector.emplace_back(images.begin() + static_cast(i), std::min(images.begin() + static_cast(i + step), images.end()));
+ }
+ return montage(img_vector);
+}
+
+} // namespace rush::cv
+
+#endif // RUSH_CV_HIGHGUI_HPP
diff --git a/include/rush/ros-cv-bridge.hpp b/include/rush/ros-cv-bridge.hpp
new file mode 100644
index 0000000..612bc2f
--- /dev/null
+++ b/include/rush/ros-cv-bridge.hpp
@@ -0,0 +1,96 @@
+/**
+ * @file ros-cv-bridge.hpp
+ * @brief This library provides an easier-to-use ROS-OpenCV bridge.
+ * @author Raul Tapia (raultapia.com)
+ */
+#ifndef RUSH_ROS_CV_BRIDGE_HPP
+#define RUSH_ROS_CV_BRIDGE_HPP
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace rush::roscv {
+
+class Encoding {
+public:
+ Encoding() = delete;
+
+ static inline std::string get(const cv::Mat &mat, const bool invert = true) {
+ switch(mat.type()) {
+ case CV_8UC1:
+ return sensor_msgs::image_encodings::MONO8;
+ case CV_8UC3:
+ return invert ? sensor_msgs::image_encodings::BGR8 : sensor_msgs::image_encodings::RGB8;
+ case CV_8UC4:
+ return invert ? sensor_msgs::image_encodings::BGRA8 : sensor_msgs::image_encodings::RGBA8;
+ case CV_16UC1:
+ return sensor_msgs::image_encodings::MONO16;
+ case CV_16UC3:
+ return invert ? sensor_msgs::image_encodings::BGR16 : sensor_msgs::image_encodings::RGB16;
+ case CV_16UC4:
+ return invert ? sensor_msgs::image_encodings::BGRA16 : sensor_msgs::image_encodings::RGBA16;
+ default:
+ return {};
+ }
+ }
+};
+
+/**
+ * @brief Converts an OpenCV Mat to a ROS Image message.
+ * @param cv The input OpenCV Mat.
+ * @param ros The output ROS Image message.
+ * @param header The header for the ROS Image message.
+ */
+inline void cv2ros(const cv::Mat &cv, sensor_msgs::Image &ros, const std_msgs::Header &header = std_msgs::Header()) {
+ cv_bridge::CvImage(header, Encoding::get(cv), cv).toImageMsg(ros);
+}
+
+/**
+ * @brief Converts a ROS Image message to an OpenCV Mat.
+ * @param ros The input ROS Image message.
+ * @param cv The output OpenCV Mat.
+ */
+inline void ros2cv(const sensor_msgs::Image &ros, cv::Mat &cv) {
+ const cv_bridge::CvImagePtr cv_ptr = cv_bridge::toCvCopy(ros, ros.encoding);
+ (cv_ptr->image).copyTo(cv);
+}
+
+/**
+ * @brief This class extends ros::Publisher to directly publish OpenCV matrices.
+ */
+class Publisher : public ros::Publisher {
+ using ros::Publisher::Publisher;
+
+public:
+ Publisher &operator=(const ros::Publisher &x) {
+ ros::Publisher::operator=(x);
+ return *this;
+ }
+
+ /**
+ * @brief Publishes an OpenCV Mat as a ROS Image message.
+ * @param img The input OpenCV Mat to be published.
+ * @param time The ROS time to be associated with the message.
+ * @param frame_id The frame ID for the ROS message.
+ */
+ void publish(const cv::Mat &img, const ros::Time &time = ros::Time::now(), const std::string &frame_id = "") {
+ std_msgs::Header header;
+ header.stamp = time;
+ header.frame_id = frame_id;
+ sensor_msgs::Image msg;
+ cv2ros(img, msg, header);
+ ros::Publisher::publish(msg);
+ }
+};
+
+} // namespace rush::roscv
+
+#endif // RUSH_ROS_CV_BRIDGE_HPP
diff --git a/include/rush/ros-parameter-manager.hpp b/include/rush/ros-parameter-manager.hpp
new file mode 100644
index 0000000..13384b6
--- /dev/null
+++ b/include/rush/ros-parameter-manager.hpp
@@ -0,0 +1,186 @@
+/**
+ * @file ros-parameter-manager.hpp
+ * @brief These library provides functionalities for loading, accessing, and manipulating ROS parameters.
+ * @author Raul Tapia (raultapia.com)
+ */
+#ifndef RUSH_ROS_PARAMETER_MANAGER_HPP
+#define RUSH_ROS_PARAMETER_MANAGER_HPP
+
+#include
+#include
+#include
+#include
+#include