소스 검색

Implemented image saver.

jcsyshc 1 년 전
부모
커밋
78ee93fc31

+ 2 - 0
CMakeLists.txt

@@ -12,6 +12,7 @@ add_executable(${PROJECT_NAME} src/main.cpp
         src/impl/apps/remote_ar/remote_ar.cpp
         src/impl/apps/tiny_player/tiny_player.cpp
         src/core/impl/event_timer.cpp
+#        src/core/impl/image_utility_v2.cpp
         src/core/impl/memory_pool.cpp
         src/core/impl/object_manager.cpp
         src/module_v3/registration.cpp
@@ -20,6 +21,7 @@ add_executable(${PROJECT_NAME} src/main.cpp
         src/module/impl/depth_guide_controller.cpp
         src/module/impl/image_augment_helper.cpp
         src/module/impl/image_player.cpp
+        src/module/impl/image_saver.cpp
         src/module/impl/image_viewer.cpp
         src/module/impl/image_streamer.cpp
         src/network_v3/sender_tcp.cpp

+ 26 - 4
src/core/image_utility.hpp

@@ -386,6 +386,14 @@ using image_u8c4 = std::shared_ptr<smart_image<uchar4>>;
 using image_u16c1 = std::shared_ptr<smart_image<ushort1>>;
 using image_f32c1 = std::shared_ptr<smart_image<float1>>;
 
+#define FORALL_IMG_TYPE \
+    impl_func(image_u8c1()); \
+    impl_func(image_u8c2()); \
+    impl_func(image_u8c3()); \
+    impl_func(image_u8c4()); \
+    impl_func(image_u16c1()); \
+    impl_func(image_f32c1())
+
 inline cv::Size get_image_size(obj_name_type name) { // TODO: better dispatch method
     auto ret = cv::Size();
     auto img_type = OBJ_TYPE(name);
@@ -397,10 +405,24 @@ inline cv::Size get_image_size(obj_name_type name) { // TODO: better dispatch me
             ret = img->size();
         }
     };
-    impl_func(image_u8c1());
-    impl_func(image_u8c2());
-    impl_func(image_u8c3());
-    impl_func(image_u8c4());
+    FORALL_IMG_TYPE;
+    return ret;
+}
+
+inline cv::Mat image_as_mat(obj_name_type name,
+                            smart_cuda_stream *stream = nullptr) { // TODO: better dispatch method
+    auto ret = cv::Mat();
+    auto img_type = OBJ_TYPE(name);
+    auto impl_func = [&](auto V) {
+        using T = std::remove_cvref_t<decltype(V)>;
+        if (img_type == typeid(T)) {
+            auto img = OBJ_QUERY(T, name);
+            if (img == nullptr) return;
+            img->sync_create(stream);
+            ret = img->as_mat(stream);
+        }
+    };
+    FORALL_IMG_TYPE;
     return ret;
 }
 

+ 45 - 0
src/core/image_utility_v2.h

@@ -0,0 +1,45 @@
+#ifndef DEPTHGUIDE_IMAGE_UTILITY_V2_H
+#define DEPTHGUIDE_IMAGE_UTILITY_V2_H
+
+#include <memory>
+
+#include <opencv2/core/types.hpp>
+
+enum pixel_enum : uint8_t {
+    PIX_GRAY,
+    PIX_RGB,
+    PIX_RGBA,
+    PIX_NV12
+};
+
+// an image in certain device
+class generic_image_info {
+
+};
+
+// collection of a same image in multiple devices
+class generic_image {
+public:
+
+    struct create_config {
+
+    };
+
+    using pointer = std::shared_ptr<generic_image>;
+
+    pixel_enum pixel_type() const;
+
+    int storage_type() const; // like CV_8UC3
+
+    cv::Size size() const;
+
+    size_t width_in_bytes() const;
+
+private:
+    struct impl;
+    std::unique_ptr<impl> pimpl;
+};
+
+using image_ptr = generic_image::pointer;
+
+#endif //DEPTHGUIDE_IMAGE_UTILITY_V2_H

+ 1 - 0
src/core/impl/image_utility_v2.cpp

@@ -0,0 +1 @@
+#include "image_utility_v2_impl.h"

+ 6 - 0
src/core/impl/image_utility_v2_impl.h

@@ -0,0 +1,6 @@
+#ifndef DEPTHGUIDE_IMAGE_UTILITY_V2_IMPL_H
+#define DEPTHGUIDE_IMAGE_UTILITY_V2_IMPL_H
+
+#include "core/image_utility_v2.h"
+
+#endif //DEPTHGUIDE_IMAGE_UTILITY_V2_IMPL_H

+ 9 - 0
src/impl/apps/remote_ar/remote_ar.cpp

@@ -177,6 +177,11 @@ app_remote_ar::app_remote_ar(const create_config &_conf) {
 //    bg_extra_conf.c_name = guide_img;
 //    bg_extra_conf.d_name = guide_depth;
 //    bg_viewer = std::make_unique<image_viewer>(bg_viewer_conf);
+
+    auto saver_conf = image_saver::create_config{.ctx = asio_ctx};
+    saver_conf.img_list.emplace_back("Left", rgb_left);
+    saver_conf.img_list.emplace_back("Right", rgb_right);
+    debug_saver = std::make_unique<image_saver>(saver_conf);
 }
 
 void app_remote_ar::start_tracking() {
@@ -249,6 +254,10 @@ void app_remote_ar::show_ui() {
                 ImGui::Text("UI Refresh Rate: %.2fms", perf_timer.query().interval);
                 ImGui::TreePop();
             }
+            if (ImGui::TreeNode("Image Saver")) {
+                debug_saver->show();
+                ImGui::TreePop();
+            }
         }
 
         ImGui::PopItemWidth();

+ 3 - 0
src/impl/apps/remote_ar/remote_ar.h

@@ -9,6 +9,7 @@
 #include "module/depth_guide_controller.h"
 #include "module/image_augment_helper.h"
 #include "module/image_player.h"
+#include "module/image_saver.h"
 #include "module/image_streamer.h"
 #include "module/image_viewer.h"
 #include "image_process/image_process_ui.h"
@@ -78,6 +79,8 @@ private:
     std::unique_ptr<versatile_convertor> guide_decode;
     std::unique_ptr<depth_guide_controller> guide_controller;
 
+    std::unique_ptr<image_saver> debug_saver;
+
     camera_module cam_left;
     camera_module cam_right;
 

+ 37 - 0
src/module/image_saver.h

@@ -0,0 +1,37 @@
+#ifndef DEPTHGUIDE_IMAGE_SAVER_H
+#define DEPTHGUIDE_IMAGE_SAVER_H
+
+#include "core/object_manager.h"
+
+#include <memory>
+#include <vector>
+
+class image_saver {
+public:
+
+    struct create_config {
+
+        struct item_type {
+            std::string name;
+            obj_name_type img_name;
+        };
+
+        using img_list_type = std::vector<item_type>;
+        img_list_type img_list;
+
+        using io_context = boost::asio::io_context;
+        io_context *ctx = nullptr;
+    };
+
+    explicit image_saver(const create_config &conf);
+
+    ~image_saver();
+
+    void show();
+
+private:
+    struct impl;
+    std::unique_ptr<impl> pimpl;
+};
+
+#endif //DEPTHGUIDE_IMAGE_SAVER_H

+ 101 - 0
src/module/impl/image_saver.cpp

@@ -0,0 +1,101 @@
+#include "image_saver_impl.h"
+#include "core/image_utility.hpp"
+#include "core/imgui_utility.hpp"
+
+#include <opencv2/imgcodecs.hpp>
+#include <opencv2/imgproc.hpp>
+
+#include <boost/asio/post.hpp>
+
+#include <fmt/format.h>
+
+#include <ranges>
+
+using boost::asio::post;
+
+void image_saver::impl::item_store_type::save_png() {
+    auto file_name = fmt::format("{}_{}.png", ui_name, par->save_cnt);
+    auto img_mat = image_as_mat(img_name, &par->stream);
+
+    // swap channels
+    auto img_type = OBJ_TYPE(img_name);
+    if (img_type == typeid(image_u8c3)) { // rgb -> bgr
+        cv::cvtColor(img_mat, img_mat, cv::COLOR_RGB2BGR);
+    }
+
+    CUDA_API_CHECK(cudaStreamSynchronize(par->stream.cuda));
+    cv::imwrite(file_name, img_mat);
+}
+
+void image_saver::impl::item_store_type::process() { // TODO: move save work to another thread
+    switch (save_type) {
+        // @formatter:off
+        case SAVE_PNG: { save_png(); break; }
+//        case SAVE_JPG: { save_jpg(); break; }
+//        case SAVE_RAW: { save_raw(); break; }
+        // @formatter:on
+    }
+}
+
+image_saver::impl::impl(const create_config &conf) {
+    ctx = conf.ctx;
+    std::ranges::transform(
+            conf.img_list, std::back_inserter(item_list),
+            [par = this](auto item) {
+                return item_store_type{
+                        .ui_name = item.name,
+                        .img_name = item.img_name,
+                        .par = par};
+            });
+}
+
+void image_saver::impl::process_all() {
+    for (auto &item: item_list) {
+        if (item.checked) {
+            item.process();
+        }
+    }
+}
+
+void image_saver::impl::show() {
+    if (ImGui::Button("Save Selected")) {
+        post(*ctx, [this] {
+            ++save_cnt;
+            process_all();
+        });
+    }
+    for (auto &item: item_list) {
+        if (ImGui::TreeNode(item.ui_name.c_str())) {
+            ImGui::Checkbox("##select", &item.checked);
+            ImGui::SameLine();
+            if (ImGui::Button("Save")) {
+                post(*ctx, [ptr = &item, this] {
+                    ++save_cnt;
+                    ptr->process();
+                });
+            }
+
+            // save type
+            ImGui::SameLine();
+            ImGui::RadioButton("PNG", &item.save_type, SAVE_PNG);
+
+            auto guard = imgui_disable_guard(); // not implemented
+            ImGui::SameLine();
+            ImGui::RadioButton("JPG", &item.save_type, SAVE_JPG);
+            ImGui::SameLine();
+            ImGui::RadioButton("RAW", &item.save_type, SAVE_RAW);
+
+            ImGui::TreePop();
+        }
+    }
+}
+
+image_saver::image_saver(const create_config &conf)
+        : pimpl(std::make_unique<impl>(conf)) {
+}
+
+image_saver::~image_saver() = default;
+
+void image_saver::show() {
+    pimpl->show();
+}

+ 49 - 0
src/module/impl/image_saver_impl.h

@@ -0,0 +1,49 @@
+#ifndef DEPTHGUIDE_IMAGE_SAVER_IMPL_H
+#define DEPTHGUIDE_IMAGE_SAVER_IMPL_H
+
+#include "module/image_saver.h"
+#include "core/cuda_helper.hpp"
+
+using boost::asio::io_context;
+
+struct image_saver::impl {
+
+    enum {
+        SAVE_JPG,
+        SAVE_PNG,
+        SAVE_RAW
+    };
+
+    struct item_store_type {
+        std::string ui_name;
+        obj_name_type img_name;
+        bool checked = false;
+        int save_type = SAVE_PNG;
+        impl *par = nullptr;
+
+        void save_jpg();
+
+        void save_png();
+
+        void save_raw();
+
+        void process();
+    };
+
+    using item_list_type = std::vector<item_store_type>;
+    item_list_type item_list;
+
+    io_context *ctx = nullptr;
+    smart_cuda_stream stream;
+
+    size_t save_cnt = 0;
+
+    explicit impl(const create_config &conf);
+
+    void show();
+
+    void process_all();
+
+};
+
+#endif //DEPTHGUIDE_IMAGE_SAVER_IMPL_H