[Example/OpenCV] Add OpenCV custom filter example: Average (#704)
authorSangjung Woo <again4you@gmail.com>
Sun, 4 Nov 2018 12:14:04 +0000 (21:14 +0900)
committerMyungJoo Ham <myungjoo.ham@gmail.com>
Sun, 4 Nov 2018 12:14:04 +0000 (21:14 +0900)
* [Example/OpenCV] Add OpenCV custom filter example: Average

This patch newly adds an OpenCV custom filter example, which calculates
the average value of input tensor for each channel. The shape of the
input tensor is [N][y][x][M] and that of the output tensor is
[N][1][1][M].

This example is developed based on
nnstreamer_customfilter_example_average.c file.

Signed-off-by: Sangjung Woo <sangjung.woo@samsung.com>
[Touched up a few typos]
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
nnstreamer_example/custom_example_opencv/CMakeLists.txt
nnstreamer_example/custom_example_opencv/nnstreamer_customfilter_opencv_average.cc [new file with mode: 0644]
tests/nnstreamer_filter_custom/runTest.sh

index 1e82eef..deeb269 100644 (file)
@@ -5,8 +5,19 @@ TARGET_LINK_LIBRARIES(nnstreamer_customfilter_opencv_scaler ${pkgs_LIBRARIES} ${
 TARGET_INCLUDE_DIRECTORIES(nnstreamer_customfilter_opencv_scaler PUBLIC ${pkgs_INCLUDE_DIRS} ${opencv_pkg_INCLUDE_DIRS})
 TARGET_COMPILE_OPTIONS(nnstreamer_customfilter_opencv_scaler PUBLIC ${pkgs_CFLAGS_OTHER})
 
+ADD_LIBRARY(nnstreamer_customfilter_opencv_average SHARED nnstreamer_customfilter_opencv_average.cc)
+TARGET_LINK_LIBRARIES(nnstreamer_customfilter_opencv_average ${pkgs_LIBRARIES} ${opencv_pkg_LIBRARIES})
+TARGET_INCLUDE_DIRECTORIES(nnstreamer_customfilter_opencv_average PUBLIC ${pkgs_INCLUDE_DIRS} ${opencv_pkg_INCLUDE_DIRS})
+TARGET_COMPILE_OPTIONS(nnstreamer_customfilter_opencv_average PUBLIC ${pkgs_CFLAGS_OTHER})
+
 INSTALL(TARGETS nnstreamer_customfilter_opencv_scaler
        RUNTIME DESTINATION ${EXEC_PREFIX}
        LIBRARY DESTINATION ${LIB_INSTALL_DIR}
        ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
 )
+
+INSTALL(TARGETS nnstreamer_customfilter_opencv_average
+       RUNTIME DESTINATION ${EXEC_PREFIX}
+       LIBRARY DESTINATION ${LIB_INSTALL_DIR}
+       ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
+)
diff --git a/nnstreamer_example/custom_example_opencv/nnstreamer_customfilter_opencv_average.cc b/nnstreamer_example/custom_example_opencv/nnstreamer_customfilter_opencv_average.cc
new file mode 100644 (file)
index 0000000..18ba2ba
--- /dev/null
@@ -0,0 +1,143 @@
+/**
+ * NNStreamer OpenCV Custom Filter Example: Average
+ * Copyright (C) 2018 Sangjung Woo <sangjung.woo@samsung.com>
+ *
+ * LICENSE: LGPL-2.1
+ *
+ * @file  nnstreamer_customfilter_opencv_average.cc
+ * @date  25 Oct 2018
+ * @brief  OpenCV Custom NNStreamer Filter Example: Average
+ * @author  Sangjung Woo <sangjung.woo@samsung.com>
+ * @bug  No known bugs
+ * @see  nnstreamer_customfilter_example_average.c
+ * 
+ * This example calculates the average value of input tensor for 
+ * each channel (i.e. R, G & B). The shape of the input tensor is
+ * [N][y][x][M] and that of the output tensor is [N][1][1][M]. 
+ */
+
+#include <opencv2/opencv.hpp>
+
+#include <glib.h>
+#include <tensor_filter_custom.h>
+#include <tensor_common.h>
+
+/**
+ * @brief _pt_data Internal data structure
+ */
+typedef struct _pt_data
+{
+  uint32_t in_height;  /***< height of input tensor */
+  uint32_t in_width;   /***< width of input tensor */
+  uint32_t in_channel; /***< channel of input tensor */
+} pt_data;
+
+/**
+ * @brief pt_init
+ */
+static void *
+pt_init (const GstTensorFilterProperties * prop)
+{
+  pt_data *pdata = g_new(pt_data, 1);
+
+  return pdata;
+}
+
+/**
+ * @brief pt_exit
+ */
+static void
+pt_exit (void *private_data, const GstTensorFilterProperties * prop)
+{
+  pt_data *pdata = static_cast<pt_data *> (private_data);
+  g_assert (pdata);
+  g_free (pdata);
+}
+
+/**
+ * @brief set_inputDim
+ */
+static int
+set_inputDim (void *private_data, const GstTensorFilterProperties * prop,
+    const GstTensorsInfo * in_info, GstTensorsInfo * out_info)
+{
+  int i;
+  pt_data *pdata = static_cast<pt_data *> (private_data);
+
+  g_assert (pdata);
+  g_assert (in_info);
+  g_assert (out_info);
+
+  out_info->num_tensors = 1;
+
+  for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++)
+    out_info->info[0].dimension[i] = in_info->info[0].dimension[i];
+
+  /* Save width, height and channel size of an input tensor */
+  pdata->in_width = in_info->info[0].dimension[1];
+  pdata->in_height = in_info->info[0].dimension[2];
+  pdata->in_channel = in_info->info[0].dimension[0];
+
+  /* Update output dimension [1] and [2] with new-x, new-y */
+  out_info->info[0].dimension[1] = 1;
+  out_info->info[0].dimension[2] = 1;
+
+  out_info->info[0].type = in_info->info[0].type;
+  return 0;
+}
+
+/**
+ * @brief pt_invoke
+ */
+static int
+pt_invoke (void *private_data, const GstTensorFilterProperties * prop,
+    const GstTensorMemory * input, GstTensorMemory * output)
+{
+  pt_data *pdata = static_cast<pt_data *> (private_data);
+  size_t in_size;
+  uint8_t *optr;
+  cv::Mat img_src;
+  std::vector<cv::Mat> channels;
+  cv::Scalar mean_result;
+  void *buffer;
+  
+  g_assert (pdata);
+  g_assert (input);
+  g_assert (output);
+
+  in_size = gst_tensor_info_get_size (&prop->input_meta.info[0]);
+  buffer = g_malloc (in_size);
+
+  /* Get Mat object from input tensor */
+  memcpy (buffer, input[0].data, in_size);
+  img_src = cv::Mat (pdata->in_height, pdata->in_width, CV_8UC3, buffer);
+
+  /* Get the channel info from Mat object */
+  cv::split(img_src, channels);
+
+  /* Calculate an average of each channel */
+  optr = static_cast<uint8_t *> (output[0].data);
+  for (uint32_t i = 0; i < pdata->in_channel; ++i) {
+    mean_result = cv::mean(channels[i]);
+    *optr = static_cast<uint8_t> (mean_result[0]);
+    optr++;
+  }
+
+  g_assert (input[0].data != output[0].data);
+  g_free(buffer);
+
+  return 0;
+}
+
+static NNStreamer_custom_class NNStreamer_custom_body = {
+  .initfunc = pt_init,
+  .exitfunc = pt_exit,
+  .getInputDim = NULL,
+  .getOutputDim = NULL,
+  .setInputDim = set_inputDim,
+  .invoke = pt_invoke,
+  .allocate_invoke = NULL,
+};
+
+/* The dyn-loaded object */
+NNStreamer_custom_class *NNStreamer_custom = &NNStreamer_custom_body;
index 1ad1933..f6cd5fa 100644 (file)
@@ -106,4 +106,15 @@ gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} videotestsrc num-buffers=1 ! video/
 python checkScaledTensor.py testcase14.direct.log 640 480 testcase14.scaled.log 1920 1080 3
 testResult $? 14 "Golden test comparison" 0 1
 
+# Test average using OpenCV (15)
+# custom version
+PATH_TO_MODEL_A="../../build/nnstreamer_example/custom_example_average/libnnstreamer_customfilter_average.so"
+gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} videotestsrc num-buffers=1 ! video/x-raw,format=RGB,width=640,height=480,framerate=0/1 ! videoconvert ! video/x-raw, format=RGB ! tensor_converter ! tensor_filter framework=\"custom\" model=\"${PATH_TO_MODEL_A}\" ! filesink location=\"testcase15.average.log\" sync=true" 15
+
+# OpenCV version
+PATH_TO_MODEL_A="../../build/nnstreamer_example/custom_example_opencv/libnnstreamer_customfilter_opencv_average.so"
+gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} videotestsrc num-buffers=1 ! video/x-raw,format=RGB,width=640,height=480,framerate=0/1 ! videoconvert ! video/x-raw, format=RGB ! tensor_converter ! tensor_filter framework=\"custom\" model=\"${PATH_TO_MODEL_A}\" ! filesink location=\"testcase15.opencv.average.log\" sync=true" 15
+
+compareAll testcase15.opencv.average.log testcase15.average.log 15
+
 report