test:python3 multithreaded python script as a filter (CV2)
authorMyungJoo Ham <myungjoo.ham@samsung.com>
Fri, 19 Aug 2022 06:36:07 +0000 (15:36 +0900)
committerSangjung Woo <again4you@gmail.com>
Tue, 6 Sep 2022 02:25:51 +0000 (11:25 +0900)
With the fear of regressions related with #3822 as
described in #3885, added a test case for multithreaded python
script of CV2.

TODO: add similar cases for converter and decoder
TODO: add negative cases

Fixes #3885

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
tests/nnstreamer_filter_python3/cv2_availability.py [new file with mode: 0644]
tests/nnstreamer_filter_python3/runTest.sh
tests/test_models/models/passThrough_CV.py [new file with mode: 0644]

diff --git a/tests/nnstreamer_filter_python3/cv2_availability.py b/tests/nnstreamer_filter_python3/cv2_availability.py
new file mode 100644 (file)
index 0000000..7d18b93
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/env python3
+##
+# SPDX-License-Identifier: LGPL-2.1-only
+#
+# Copyright (C) 2022 Samsung Electronics
+#
+# @file    cv2_availability.py
+# @brief   Check if cv2 is available for python
+# @author  MyungJoo Ham <myungjoo.ham@samsung.com>
+
+import sys
+
+def main():
+  try:
+    import cv2
+  except ImportError:
+    return 1
+
+  return 0
+
+sys.exit(main())
index 90ea09a..dc5c9db 100755 (executable)
@@ -81,6 +81,19 @@ gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} videotestsrc num-buffers=1 ! video/
 python3 checkScaledTensor.py testcase3.direct.log 640 480 testcase3.scaled.log 1280 960 3
 testResult $? 3 "Golden test comparison" 0 1
 
+# Passthrough with CV (multithreaded)
+python3 cv2_availability.py
+CV2=$?
+IGNORE=0
+if [ "$CV2" == "0" ]; then
+  IGNORE=0
+else
+  IGNORE=1
+fi
+PATH_TO_SCRIPT="../test_models/models/passThrough_CV.py"
+gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} videotestsrc num-buffers=1 ! video/x-raw,format=RGB,width=280,height=40,framerate=0/1 ! videoconvert ! video/x-raw, format=RGB ! tensor_converter ! tee name=t ! queue ! tensor_filter framework=\"${FRAMEWORK}\" model=\"${PATH_TO_SCRIPT}\" input=\"3:280:40:1\" inputtype=\"uint8\" output=\"3:280:40:1\" outputtype=\"uint8\" ! filesink location=\"testcase4.passthrough.log\" sync=true t. ! queue ! filesink location=\"testcase4.direct.log\" sync=true" 4-1 $IGNORE 0 $PERFORMANCE
+callCompareTest testcase4.direct.log testcase4.passthrough.log 4-2 "Multithreaded python script as a filter (CV2)" 0 $IGNORE
+
 rm *.log
 
 report
diff --git a/tests/test_models/models/passThrough_CV.py b/tests/test_models/models/passThrough_CV.py
new file mode 100644 (file)
index 0000000..f0c675d
--- /dev/null
@@ -0,0 +1,58 @@
+#!/bin/env python3
+##
+# SPDX-License-Identifier: LGPL-2.1-only
+#
+# @file         passThrough_CV.py
+# @brief        A trivial python custom filter to test the usage of CV2 in python script, which tests multithreading in a script as well.
+# @author       beto-gulliver @ github
+
+import numpy as np
+import nnstreamer_python as nns
+
+D1 = 3
+D2 = 280
+D3 = 40
+D4 = 1
+
+USE_CV2 = True # [NG] XXX: 'cv2' halts!!! -->  github issue (threads' race condition/deadlock? release GIL? ???)
+#USE_CV2 = False # [OK]
+if USE_CV2 : import cv2
+
+class CustomFilter(object):
+    def __init__(self, *args):
+        self.input_dims  = [nns.TensorShape([D1, D2, D3, D4], np.uint8)]
+        self.output_dims = [nns.TensorShape([D1, D2, D3, D4], np.uint8)]
+
+    def getInputDim(self):
+        return self.input_dims
+
+    def getOutputDim(self):
+        return self.output_dims
+
+    def invoke(self, input_array):
+        # passthrough, just return.
+        print(f"--- USE_CV2:{USE_CV2}", __file__, input_array[0].shape)
+        if USE_CV2 : cv2.imwrite("/tmp/x.png", np.zeros((240, 320, 3), dtype=np.uint8)) # [NG] XXX: 'cv2' halts!!! -->  github issue (threads' race condition/deadlock? release GIL? ???)
+        return input_array
+
+# ----------------------------------------------------------------------
+def main():
+    import sys
+    cf = CustomFilter()
+    print(cf)
+    shape, dtype = [D1, D2, D3, D4], "uint8"
+    if 1 :
+        input_dims = [nns.TensorShape(shape, dtype)]
+#        cf.setInputDim(input_dims) # callback
+    for idx in range(10) :
+        in_ = np.ones(shape).astype(np.uint8)
+        in_ = (np.random.random(shape) * 255).astype(np.uint8)
+        in_ = [np.ravel(in_)] # as buffer (memory)
+        print(idx, f"USE_CV2:{USE_CV2} in_ {in_}", __file__)
+        out = cf.invoke(in_)
+        print(idx, f"USE_CV2:{USE_CV2} out {out}", __file__)
+
+# voila!
+if __name__ == '__main__':
+    main()
+# ----------------------------------------------------------------------