diff --git a/grc/iqtlabs_image_inference.block.yml b/grc/iqtlabs_image_inference.block.yml index f9100095..6387243f 100644 --- a/grc/iqtlabs_image_inference.block.yml +++ b/grc/iqtlabs_image_inference.block.yml @@ -10,7 +10,7 @@ templates: iqtlabs.image_inference(${tag}, ${vlen}, ${x}, ${y}, ${image_dir}, ${convert_alpha}, ${norm_alpha}, ${norm_beta}, ${norm_type}, ${colormap}, ${interpolation}, ${model_server}, ${model_name}, ${confidence}, - ${max_rows}) + ${max_rows}, ${rotate_secs}, ${n_image}, ${n_inference}) cpp_templates: includes: ['#include '] @@ -19,7 +19,8 @@ cpp_templates: this->${id} = gr::iqtlabs::image_inference::make(${tag}, ${vlen}, ${x}, ${y}, ${image_dir}, ${convert_alpha}, ${norm_alpha}, ${norm_beta}, ${norm_type}, ${colormap}, ${interpolation}, ${model_server}, - ${model_name}, ${confidence}, ${max_rows}); + ${model_name}, ${confidence}, ${max_rows}, ${rotate_secs}, ${n_image}, + ${n_inference}) link: ['libgnuradio-iqtlabs.so'] @@ -66,6 +67,12 @@ parameters: dtype: float - id: max_rows dtype: int + - id: rotate_secs + dtype: int + - id: n_image + dtype: int + - id: n_inference + dtype: int asserts: - ${ tag != "" } diff --git a/include/gnuradio/iqtlabs/image_inference.h b/include/gnuradio/iqtlabs/image_inference.h index 7992303d..bacc6c28 100644 --- a/include/gnuradio/iqtlabs/image_inference.h +++ b/include/gnuradio/iqtlabs/image_inference.h @@ -234,7 +234,7 @@ class IQTLABS_API image_inference : virtual public gr::block { int colormap, int interpolation, int flip, double min_peak_points, const std::string &model_server, const std::string &model_name, double confidence, - int max_rows); + int max_rows, int rotate_secs, int n_image, int n_inference); }; } // namespace iqtlabs diff --git a/lib/image_inference_impl.cc b/lib/image_inference_impl.cc index de03e24d..29d78a41 100644 --- a/lib/image_inference_impl.cc +++ b/lib/image_inference_impl.cc @@ -219,11 +219,12 @@ image_inference::sptr image_inference::make( const std::string &image_dir, double convert_alpha, double norm_alpha, double norm_beta, int norm_type, int colormap, int interpolation, int flip, double min_peak_points, const std::string &model_server, - const std::string &model_name, double confidence, int max_rows) { + const std::string &model_name, double confidence, int max_rows, + int rotate_secs, int n_image, int n_inference) { return gnuradio::make_block_sptr( tag, vlen, x, y, image_dir, convert_alpha, norm_alpha, norm_beta, norm_type, colormap, interpolation, flip, min_peak_points, model_server, - model_name, confidence, max_rows); + model_name, confidence, max_rows, rotate_secs, n_image, n_inference); } image_inference_impl::image_inference_impl( @@ -231,7 +232,8 @@ image_inference_impl::image_inference_impl( const std::string &image_dir, double convert_alpha, double norm_alpha, double norm_beta, int norm_type, int colormap, int interpolation, int flip, double min_peak_points, const std::string &model_server, - const std::string &model_name, double confidence, int max_rows) + const std::string &model_name, double confidence, int max_rows, + int rotate_secs, int n_image, int n_inference) : gr::block("image_inference", gr::io_signature::make(1 /* min inputs */, 1 /* max inputs */, vlen * sizeof(input_type)), @@ -242,8 +244,10 @@ image_inference_impl::image_inference_impl( norm_alpha_(norm_alpha), norm_beta_(norm_beta), norm_type_(norm_type), colormap_(colormap), interpolation_(interpolation), flip_(flip), min_peak_points_(min_peak_points), model_name_(model_name), - confidence_(confidence), max_rows_(max_rows), running_(true), - inference_connected_(false) { + confidence_(confidence), max_rows_(max_rows), rotate_secs_(rotate_secs), + n_image_(n_image), n_inference_(n_inference), running_(true), + inference_connected_(false), image_count_(0), prediction_image_count_(0), + inference_count_(0) { points_buffer_ = new cv::Mat(cv::Size(vlen_, 0), CV_32F, cv::Scalar::all(0)); normalized_buffer_.reset( new cv::Mat(cv::Size(vlen_, 0), CV_32F, cv::Scalar::all(0))); @@ -327,7 +331,8 @@ void image_inference_impl::create_image_() { } std::string image_inference_impl::write_image_( - const std::string &prefix, output_item_type &output_item, + const std::string &secs_image_dir, const std::string &prefix, + output_item_type &output_item, boost::scoped_ptr> &encoded_buffer) { encoded_buffer.reset(new std::vector()); cv::imencode(IMAGE_EXT, *output_item.image_buffer, *encoded_buffer); @@ -336,8 +341,8 @@ std::string image_inference_impl::write_image_( std::to_string(uint64_t(x_)) + "x" + std::to_string(uint64_t(y_)) + "_" + std::to_string(uint64_t(output_item.rx_freq)) + "Hz"; std::string image_file_png = image_file_base + IMAGE_EXT; - std::string dot_image_file_png = image_dir_ + "/." + image_file_png; - std::string full_image_file_png = image_dir_ + "/" + image_file_png; + std::string dot_image_file_png = secs_image_dir + "." + image_file_png; + std::string full_image_file_png = secs_image_dir + image_file_png; std::ofstream image_out; image_out.open(dot_image_file_png, std::ios::binary | std::ios::out); image_out.write((const char *)encoded_buffer->data(), encoded_buffer->size()); @@ -389,12 +394,17 @@ void image_inference_impl::get_inference_() { metadata_json["ts"] = host_now_str_(output_item.ts); metadata_json["rx_freq"] = std::to_string(output_item.rx_freq); metadata_json["orig_rows"] = output_item.points_buffer->rows; - metadata_json["image_path"] = - write_image_("image", output_item, encoded_buffer); + + const std::string secs_image_dir = secs_dir(image_dir_, rotate_secs_); + if (n_image_ == 0 || ++image_count_ % n_image_ == 0) { + metadata_json["image_path"] = + write_image_(secs_image_dir, "image", output_item, encoded_buffer); + } nlohmann::json output_json; - if (host_.size() && port_.size()) { + if ((host_.size() && port_.size()) && + (n_inference_ == 0 || ++inference_count_ % n_inference_ == 0)) { const std::string_view body( reinterpret_cast(encoded_buffer->data()), encoded_buffer->size()); @@ -501,8 +511,11 @@ void image_inference_impl::get_inference_() { } output_json["predictions"] = results_json; if (rendered_predictions) { - metadata_json["predictions_image_path"] = - write_image_("predictions_image", output_item, encoded_buffer); + if (n_image_ == 0 || ++prediction_image_count_ % n_image_ == 0) { + metadata_json["predictions_image_path"] = + write_image_(secs_image_dir, "predictions_image", output_item, + encoded_buffer); + } } } else { output_json["error"] = "invalid json: " + results; diff --git a/lib/image_inference_impl.h b/lib/image_inference_impl.h index e645d6bb..c5ca9dc8 100644 --- a/lib/image_inference_impl.h +++ b/lib/image_inference_impl.h @@ -239,7 +239,9 @@ typedef struct output_item { class image_inference_impl : public image_inference, base_impl { private: - int x_, y_, vlen_, norm_type_, colormap_, interpolation_, flip_, max_rows_; + int x_, y_, vlen_, norm_type_, colormap_, interpolation_, flip_, max_rows_, + rotate_secs_, n_image_, n_inference_, image_count_, + prediction_image_count_, inference_count_; uint64_t last_rx_freq_; double convert_alpha_, norm_alpha_, norm_beta_, last_rx_time_, min_peak_points_, confidence_; @@ -265,7 +267,8 @@ class image_inference_impl : public image_inference, base_impl { void delete_output_item_(output_item_type &output_item); void delete_inference_(); std::string - write_image_(const std::string &prefix, output_item_type &output_item, + write_image_(const std::string &secs_image_dir, const std::string &prefix, + output_item_type &output_item, boost::scoped_ptr> &encoded_buffer); public: @@ -275,7 +278,8 @@ class image_inference_impl : public image_inference, base_impl { int colormap, int interpolation, int flip, double min_peak_points, const std::string &model_server, const std::string &model_name, double confidence, - int max_rows); + int max_rows, int rotate_secs, int n_image, + int n_inference); ~image_inference_impl(); int general_work(int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, diff --git a/python/iqtlabs/bindings/image_inference_python.cc b/python/iqtlabs/bindings/image_inference_python.cc index 12c16802..db683c0f 100644 --- a/python/iqtlabs/bindings/image_inference_python.cc +++ b/python/iqtlabs/bindings/image_inference_python.cc @@ -14,7 +14,7 @@ /* BINDTOOL_GEN_AUTOMATIC(0) */ /* BINDTOOL_USE_PYGCCXML(0) */ /* BINDTOOL_HEADER_FILE(image_inference.h) */ -/* BINDTOOL_HEADER_FILE_HASH(b39ddd6fde28ff8492f4a3e4bcec592a) */ +/* BINDTOOL_HEADER_FILE_HASH(113fcb53cbc7dfe117d41d8af71d3781) */ /***********************************************************************************/ #include @@ -56,6 +56,9 @@ void bind_image_inference(py::module& m) py::arg("model_name"), py::arg("confidence"), py::arg("max_rows"), + py::arg("rotate_secs"), + py::arg("n_image"), + py::arg("n_inference"), D(image_inference, make)) diff --git a/python/iqtlabs/qa_image_inference.py b/python/iqtlabs/qa_image_inference.py index 564d1ad1..bf62f664 100755 --- a/python/iqtlabs/qa_image_inference.py +++ b/python/iqtlabs/qa_image_inference.py @@ -287,6 +287,9 @@ def test_instance(self): model_name, 0.8, 1024, + 30, + 0, + 0 ) c2r = blocks.complex_to_real(1) stream2vector = blocks.stream_to_vector(gr.sizeof_float, fft_size) @@ -306,7 +309,7 @@ def test_instance(self): time.sleep(test_time) self.tb.stop() self.tb.wait() - image_files = [f for f in glob.glob(f"{tmpdir}/*image*png")] + image_files = [f for f in glob.glob(f"{tmpdir}/**/*image*png")] self.assertGreater(len(image_files), 2) for image_file in image_files: stat = os.stat(image_file)