diff --git a/.github/workflows/linux-cuda-gnu.yml b/.github/workflows/linux-cuda-gnu.yml index 36cf4e93..85ef5726 100644 --- a/.github/workflows/linux-cuda-gnu.yml +++ b/.github/workflows/linux-cuda-gnu.yml @@ -79,7 +79,7 @@ jobs: DEBIAN_FRONTEND: noninteractive # evision related env vars MIX_ENV: test - OPENCV_VER: "4.7.0" + OPENCV_VER: "4.8.0" OTP_VERSION: "25.2" ELIXIR_VERSION: "1.14.3" EVISION_PREFER_PRECOMPILED: "false" diff --git a/.github/workflows/linux-precompile-cuda-gnu.yml b/.github/workflows/linux-precompile-cuda-gnu.yml index 7c7acd72..c43627ba 100644 --- a/.github/workflows/linux-precompile-cuda-gnu.yml +++ b/.github/workflows/linux-precompile-cuda-gnu.yml @@ -57,7 +57,7 @@ jobs: DEBIAN_FRONTEND: noninteractive # evision related env vars MIX_ENV: test - OPENCV_VER: "4.7.0" + OPENCV_VER: "4.8.0" ELIXIR_VERSION: "1.15.2" EVISION_PREFER_PRECOMPILED: "false" EVISION_GENERATE_LANG: "erlang,elixir" diff --git a/.github/workflows/linux-precompile-gnu.yml b/.github/workflows/linux-precompile-gnu.yml index d93600d5..c79fba5d 100644 --- a/.github/workflows/linux-precompile-gnu.yml +++ b/.github/workflows/linux-precompile-gnu.yml @@ -13,7 +13,7 @@ jobs: mix_compile: runs-on: ubuntu-20.04 env: - OPENCV_VER: "4.7.0" + OPENCV_VER: "4.8.0" MIX_ENV: prod ELIXIR_VERSION: "1.15.2" EVISION_PREFER_PRECOMPILED: "false" diff --git a/.github/workflows/linux-precompile-musl.yml b/.github/workflows/linux-precompile-musl.yml index 1fc42f39..515de0a1 100644 --- a/.github/workflows/linux-precompile-musl.yml +++ b/.github/workflows/linux-precompile-musl.yml @@ -15,7 +15,7 @@ jobs: container: alpine:latest env: MIX_ENV: prod - OPENCV_VER: "4.7.0" + OPENCV_VER: "4.8.0" EVISION_PREFER_PRECOMPILED: "false" EVISION_GENERATE_LANG: "erlang,elixir" strategy: @@ -165,7 +165,7 @@ jobs: zig_build: runs-on: ubuntu-20.04 env: - OPENCV_VER: "4.7.0" + OPENCV_VER: "4.8.0" MIX_ENV: prod ZIG_VERSION: "0.8.0" EVISION_PREFER_PRECOMPILED: "false" diff --git a/.github/workflows/linux-x86_64.yml b/.github/workflows/linux-x86_64.yml index ffa45702..57939229 100644 --- a/.github/workflows/linux-x86_64.yml +++ b/.github/workflows/linux-x86_64.yml @@ -60,7 +60,7 @@ jobs: container: alpine:latest env: MIX_ENV: test - OPENCV_VER: "4.7.0" + OPENCV_VER: "4.8.0" OTP_VERSION: "25.2" ELIXIR_VERSION: "1.14.3" EVISION_PREFER_PRECOMPILED: "false" @@ -154,7 +154,7 @@ jobs: runs-on: ubuntu-20.04 env: MIX_ENV: test - OPENCV_VER: "4.7.0" + OPENCV_VER: "4.8.0" OTP_VERSION: "25.2" ELIXIR_VERSION: "1.14.3" EVISION_PREFER_PRECOMPILED: "false" diff --git a/.github/workflows/macos-precompile.yml b/.github/workflows/macos-precompile.yml index c0251938..eb3caab4 100644 --- a/.github/workflows/macos-precompile.yml +++ b/.github/workflows/macos-precompile.yml @@ -14,7 +14,7 @@ jobs: runs-on: macos-11 env: MIX_ENV: prod - OPENCV_VER: "4.7.0" + OPENCV_VER: "4.8.0" EVISION_PREFER_PRECOMPILED: "false" EVISION_GENERATE_LANG: "erlang,elixir" strategy: diff --git a/.github/workflows/macos-x86_64.yml b/.github/workflows/macos-x86_64.yml index ca5a00a2..ad64015c 100644 --- a/.github/workflows/macos-x86_64.yml +++ b/.github/workflows/macos-x86_64.yml @@ -45,7 +45,7 @@ jobs: mix_test: runs-on: macos-12 env: - OPENCV_VER: "4.7.0" + OPENCV_VER: "4.8.0" MIX_ENV: "test" EVISION_PREFER_PRECOMPILED: "false" FFMPEG_VER: "5" diff --git a/.github/workflows/nerves-build.yml b/.github/workflows/nerves-build.yml index 0dcac50c..68483e2e 100644 --- a/.github/workflows/nerves-build.yml +++ b/.github/workflows/nerves-build.yml @@ -47,9 +47,8 @@ jobs: env: MIX_ENV: prod NERVES_PROJ_NAME: nerves_evision - OPENCV_VER: "4.7.0" + OPENCV_VER: "4.8.0" NERVES_LIVEBOOK_VER: "v0.10.1" - ELIXIR_VERSION: "1.15.4" EVISION_PREFER_PRECOMPILED: "false" diff --git a/.github/workflows/test-python-compatibility.yml b/.github/workflows/test-python-compatibility.yml index 92eddf7e..92594ac9 100644 --- a/.github/workflows/test-python-compatibility.yml +++ b/.github/workflows/test-python-compatibility.yml @@ -25,7 +25,7 @@ jobs: runs-on: ubuntu-20.04 env: MIX_ENV: test - OPENCV_VER: "4.7.0" + OPENCV_VER: "4.8.0" EVISION_PREFER_PRECOMPILED: "false" strategy: diff --git a/.github/workflows/windows-precompile-cuda.yml b/.github/workflows/windows-precompile-cuda.yml index 9b078e4f..8935c64d 100644 --- a/.github/workflows/windows-precompile-cuda.yml +++ b/.github/workflows/windows-precompile-cuda.yml @@ -15,7 +15,7 @@ jobs: runs-on: windows-2019 env: MIX_ENV: prod - OPENCV_VER: "4.7.0" + OPENCV_VER: "4.8.0" ELIXIR_VERSION: "1.14.3" EVISION_PREFER_PRECOMPILED: "false" EVISION_GENERATE_LANG: "erlang,elixir" diff --git a/.github/workflows/windows-precompile.yml b/.github/workflows/windows-precompile.yml index 7c282d0b..798b1839 100644 --- a/.github/workflows/windows-precompile.yml +++ b/.github/workflows/windows-precompile.yml @@ -14,8 +14,8 @@ jobs: runs-on: windows-latest env: MIX_ENV: prod - OPENCV_VER: "4.7.0" - ELIXIR_VERSION: "1.15.2" + OPENCV_VER: "4.8.0" + ELIXIR_VERSION: "1.15.4" EVISION_PREFER_PRECOMPILED: "false" EVISION_GENERATE_LANG: "erlang,elixir" MAKE: "nmake" diff --git a/.github/workflows/windows-x86_64.yml b/.github/workflows/windows-x86_64.yml index d8e59335..a894d635 100644 --- a/.github/workflows/windows-x86_64.yml +++ b/.github/workflows/windows-x86_64.yml @@ -47,7 +47,7 @@ jobs: runs-on: windows-latest env: MIX_ENV: test - OPENCV_VER: "4.7.0" + OPENCV_VER: "4.8.0" OTP_VERSION: "25.2" ELIXIR_VERSION: "1.14.3" EVISION_PREFER_PRECOMPILED: "false" diff --git a/CHANGELOG.md b/CHANGELOG.md index b0855c2c..454b9548 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v0.1.32 (2023-07-31) +[Browse the Repository](https://github.com/cocoa-xu/evision/tree/v0.1.32) | [Released Assets](https://github.com/cocoa-xu/evision/releases/tag/v0.1.32) + +### Changed +- Updated to OpenCV 4.8.0. Some APIs have changed, please see OpenCV's release note for more information. + ## v0.1.31 (2023-04-17) [Browse the Repository](https://github.com/cocoa-xu/evision/tree/v0.1.31) | [Released Assets](https://github.com/cocoa-xu/evision/releases/tag/v0.1.31) diff --git a/Makefile b/Makefile index a8ecd0bd..1e69d514 100644 --- a/Makefile +++ b/Makefile @@ -17,13 +17,13 @@ CMAKE_BUILD_TYPE ?= Release # OpenCV OPENCV_USE_GIT_HEAD ?= false OPENCV_GIT_REPO ?= "https://github.com/opencv/opencv.git" -OPENCV_VER ?= 4.7.0 +OPENCV_VER ?= 4.8.0 ifneq ($(OPENCV_USE_GIT_HEAD), false) OPENCV_VER=$(OPENCV_USE_GIT_BRANCH) endif OPENCV_CONTRIB_USE_GIT_HEAD ?= false OPENCV_GIT_REPO ?= "https://github.com/opencv/opencv_contrib.git" -OPENCV_CONTRIB_VER ?= 4.7.0 +OPENCV_CONTRIB_VER ?= 4.8.0 ifneq ($(OPENCV_CONTRIB_USE_GIT_HEAD), false) OPENCV_CONTRIB_VER=$(OPENCV_CONTRIB_USE_GIT_BRANCH) endif diff --git a/Makefile.win b/Makefile.win index c308ebac..ec8db965 100644 --- a/Makefile.win +++ b/Makefile.win @@ -21,10 +21,10 @@ OPENCV_USE_GIT_HEAD=false OPENCV_GIT_REPO="https://github.com/opencv/opencv.git" !ENDIF !IFNDEF OPENCV_VER -OPENCV_VER=4.7.0 +OPENCV_VER=4.8.0 !ENDIF !IFNDEF OPENCV_CONTRIB_VER -OPENCV_CONTRIB_VER=4.7.0 +OPENCV_CONTRIB_VER=4.8.0 !ENDIF !IF "$(OPENCV_USE_GIT_HEAD)" == "true" OPENCV_VER=$(OPENCV_USE_GIT_BRANCH) diff --git a/README.md b/README.md index f5b69c65..62f4b303 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ iex> mat = Evision.Mat.from_nx(t) #### Unsupported Type Map -As OpenCV does not support the following types (yet, as of OpenCV 4.7.0) +As OpenCV does not support the following types (yet, as of OpenCV 4.8.0) - `{:s, 64}` - `{:u, 32}` @@ -319,6 +319,7 @@ Compatible OpenCV versions: - 4.5.5 - 4.6.0 - 4.7.0 +- 4.8.0 by compatible, it means these versions can compile successfully, and I tested a small range of functions. Tons of tests should be written, and then we can have a list for tested OpenCV versions. @@ -518,7 +519,7 @@ To obtain and compile OpenCV's source code from official releases, the following # optional ## set OpenCV version ## the corresponding license file should be available at https://github.com/opencv/opencv/blob/${OPENCV_VER}/LICENSE -export OPENCV_VER="4.7.0" +export OPENCV_VER="4.8.0" # optional ## Use Debug build @@ -704,7 +705,7 @@ Say you have the following MIX environment variables: # set by MIX MIX_ENV=dev # set by evision or you -OPENCV_VER=4.7.0 +OPENCV_VER=4.8.0 # set by yourself if you're compiling evision to a nerves firmware MIX_TARGET=rpi4 ``` diff --git a/mix.exs b/mix.exs index f7f280a0..28fccb9e 100644 --- a/mix.exs +++ b/mix.exs @@ -2,11 +2,11 @@ defmodule Evision.MixProject.Metadata do @moduledoc false def app, do: :evision - def version, do: "0.1.31" + def version, do: "0.1.32" def github_url, do: "https://github.com/cocoa-xu/evision" - def opencv_version, do: "4.7.0" + def opencv_version, do: "4.8.0" # only means compatible. need to write more tests - def compatible_opencv_versions, do: ["4.5.3", "4.5.4", "4.5.5", "4.6.0", "4.7.0"] + def compatible_opencv_versions, do: ["4.5.3", "4.5.4", "4.5.5", "4.6.0", "4.7.0", "4.8.0"] def default_cuda_version, do: "118" def all_cuda_version, do: ["111", "114", "118"] end diff --git a/patches/apply_patch.py b/patches/apply_patch.py index 220f0889..a0a78a35 100644 --- a/patches/apply_patch.py +++ b/patches/apply_patch.py @@ -10,7 +10,7 @@ def patch_fix_getLayerShapes(opencv_version: str, opencv_src_root: str): - if opencv_version not in ['4.5.4', '4.5.5', '4.6.0', '4.7.0']: + if opencv_version not in ['4.5.4', '4.5.5', '4.6.0', '4.7.0', '4.8.0']: print(f"warning: applying `patch_fix_getLayerShapes` to opencv version `{opencv_version}`") # modules/dnn/include/opencv2/dnn/dnn.hpp diff --git a/py_src/class_info.py b/py_src/class_info.py index 4370daa4..062310a4 100644 --- a/py_src/class_info.py +++ b/py_src/class_info.py @@ -114,14 +114,16 @@ def gen_erl_func_list(self, codegen): while base_class is not None: if base_class \ and ( - current_class.cname.startswith("cv::ml") + base_class == "GraphicalCodeDetector" + or current_class.cname.startswith("cv::ml") + or "Calibrate" in current_class.cname or "Calibrate" in current_class.cname or (current_class.base is not None and "Feature2D" in current_class.base) or (current_class.base is not None and "Matcher" in current_class.base) or (current_class.base is not None and "Algorithm" in current_class.base) or (current_class.base is not None and current_class.cname.startswith("cv::dnn")) ): - if base_class in codegen.classes: + if base_class in codegen.classes and current_class.base is not None: base_class = codegen.classes[current_class.base] for base_method_name in base_class.methods: if base_method_name not in methods: @@ -240,14 +242,15 @@ def gen_code(self, codegen): while base_class is not None: if base_class \ and ( - current_class.cname.startswith("cv::ml") + base_class == "GraphicalCodeDetector" + or current_class.cname.startswith("cv::ml") or "Calibrate" in current_class.cname or (current_class.base is not None and "Feature2D" in current_class.base) or (current_class.base is not None and "Matcher" in current_class.base) or (current_class.base is not None and "Algorithm" in current_class.base) or (current_class.base is not None and current_class.cname.startswith("cv::dnn")) ): - if base_class in codegen.classes: + if base_class in codegen.classes and current_class.base is not None: base_class = codegen.classes[current_class.base] for base_method_name in base_class.methods: if base_method_name not in methods: diff --git a/py_src/func_info.py b/py_src/func_info.py index ba40b813..8e82e8c9 100644 --- a/py_src/func_info.py +++ b/py_src/func_info.py @@ -329,6 +329,10 @@ def gen_code(self, codegen): if defval and len(defval) > 0: if arg_type_info.atype == "QRCodeEncoder_Params": code_decl += " QRCodeEncoder::Params %s=%s;\n" % (a.name, defval) + elif arg_type_info.atype == "QRCodeDetectorAruco_Params": + code_decl += " QRCodeDetectorAruco::Params %s=%s;\n" % (a.name, defval) + elif arg_type_info.atype == "aruco_DetectorParameters": + code_decl += " aruco::DetectorParameters %s=%s;\n" % (a.name, defval) else: if arg_type_info.atype == "FileStorage" or (underscore_type in all_classes and all_classes[underscore_type].issimple is False): code_decl += " Ptr<%s> ptr_%s;\n" % (arg_type_info.atype, a.name,) @@ -342,6 +346,10 @@ def gen_code(self, codegen): if arg_type_info.atype == "FileStorage" or (underscore_type in all_classes and all_classes[underscore_type].issimple is False): code_decl += " Ptr<%s> ptr_%s;\n" % (arg_type_info.atype, a.name) code_from_ptr += " %s %s; if (ptr_%s.get()) { %s = *ptr_%s.get(); }\n " % (arg_type_info.atype, a.name, a.name, a.name, a.name) + elif arg_type_info.atype == "QRCodeDetectorAruco_Params": + code_decl += " QRCodeDetectorAruco::Params %s;\n" % (a.name,) + elif arg_type_info.atype == "aruco_DetectorParameters": + code_decl += " aruco::DetectorParameters %s;\n" % (a.name,) else: code_decl += " %s %s;\n" % (arg_type_info.atype, a.name) diff --git a/py_src/hdr_parser.py b/py_src/hdr_parser.py index 3f26a41b..710c7921 100755 --- a/py_src/hdr_parser.py +++ b/py_src/hdr_parser.py @@ -259,6 +259,10 @@ def parse_class_decl(self, decl_str): if "CV_EXPORTS_W_SIMPLE" in l: l = l.replace("CV_EXPORTS_W_SIMPLE", "") modlist.append("/Simple") + if "CV_EXPORTS_W_PARAMS" in l: + l = l.replace("CV_EXPORTS_W_PARAMS", "") + modlist.append("/Map") + modlist.append("/Params") npos = l.find("CV_EXPORTS_AS") if npos < 0: npos = l.find('CV_WRAP_AS') @@ -393,6 +397,7 @@ def parse_func_decl(self, decl_str, mat="Mat", docstring=""): [~] ( [=] [, [=] ...]) [const] {; | } + Returns the function declaration entry: [, , , , , ] (see above) """ @@ -611,6 +616,8 @@ def parse_func_decl(self, decl_str, mat="Mat", docstring=""): ("InputOutputArray", mat), ("OutputArray", mat), ("noArray", arg_type)]).strip() + if '/IO' in modlist and '/O' in modlist: + modlist.remove('/O') args.append([arg_type, arg_name, defval, modlist]) npos = arg_start-1 @@ -628,12 +635,14 @@ def parse_func_decl(self, decl_str, mat="Mat", docstring=""): def get_dotted_name(self, name): """ adds the dot-separated container class/namespace names to the bare function/class name, e.g. when we have + namespace cv { class A { public: f(int); }; } + the function will convert "A" to "cv.A" and "f" to "cv.A.f". """ if not self.block_stack: @@ -661,6 +670,7 @@ class A { def parse_stmt(self, stmt, end_token, mat="Mat", docstring=""): """ parses the statement (ending with ';' or '}') or a block head (ending with '{') + The function calls parse_class_decl or parse_func_decl when necessary. It returns , , , where the first 3 values only make sense for blocks (i.e. code blocks, namespaces, classes, enums and such) @@ -772,7 +782,15 @@ def parse_stmt(self, stmt, end_token, mat="Mat", docstring=""): var_list = [var_name1] + [i.strip() for i in var_list[1:]] for v in var_list: - class_decl[3].append([var_type, v, "", var_modlist]) + prop_definition = v.split('=') + prop_name = prop_definition[0].strip() + if len(prop_definition) == 1: + # default value is not provided + prop_default_value = '' + else: + prop_default_value = prop_definition[-1] + class_decl[3].append([var_type, prop_name, prop_default_value, + var_modlist]) return stmt_type, "", False, None # something unknown diff --git a/py_src/helper.py b/py_src/helper.py index fd3fd927..10ae07ba 100644 --- a/py_src/helper.py +++ b/py_src/helper.py @@ -638,6 +638,7 @@ def is_struct(argtype: str, also_get: Optional[str] = None, classname: Optional[ 'MergeMertens': 'Evision.MergeMertens', 'MergeRobertson': 'Evision.MergeRobertson', 'ORB': 'Evision.ORB', + 'RotatedRect': 'Evision.RotatedRect', 'PyRotationWarper': 'Evision.PyRotationWarper', 'QRCodeDetector': 'Evision.QRCodeDetector', 'QRCodeEncoder': 'Evision.QRCodeEncoder', @@ -832,6 +833,8 @@ def is_struct(argtype: str, also_get: Optional[str] = None, classname: Optional[ "TrackerNano_Params": "Evision.TrackerNano.Params", "ArucoDetector": "Evision.ArUco.ArucoDetector", + "QRCodeDetectorAruco": "Evision.QRCodeDetectorAruco", + "GraphicalCodeDetector": "Evision.GraphicalCodeDetector", "mcc_CChecker": "Evision.MCC.CCheckerDetector", "dnn_Net": "Evision.DNN.Net", @@ -1199,6 +1202,14 @@ def map_argtype_in_spec_erlang(classname: str, argtype: str, is_in: bool, decl: return '#evision_ocl_device{}' elif argtype == 'Index' and classname == 'flann_Index': return '#evision_flann_index{}' + elif argtype == 'QRCodeDetectorAruco': + return '#evision_qrcode_detector_aruco{}' + elif argtype == 'QRCodeDetectorAruco_Params': + return 'term()' + elif argtype in ['aruco_DetectorParameters', 'aruco::DetectorParameters']: + return 'term()' + elif argtype == 'PolishingMethod' and classname == 'UsacParams': + return 'integer()' else: if argtype == 'LayerId': return 'term()' @@ -1291,6 +1302,14 @@ def map_argtype_in_spec_elixir(classname: str, argtype: str, is_in: bool, decl: return 'Evision.OCL.Device.t()' elif argtype == 'Index' and classname == 'flann_Index': return 'Evision.Flann.Index.t()' + elif argtype == 'QRCodeDetectorAruco': + return 'Evision.QRCodeDetectorAruco' + elif argtype in ['QRCodeDetectorAruco_Params', 'QRCodeDetectorAruco::Params']: + return 'Evision.QRCodeDetectorAruco.Params' + elif argtype in ['aruco_DetectorParameters', 'aruco::DetectorParameters']: + return 'Evision.Aruco.DetectorParameters' + elif argtype == 'PolishingMethod' and classname == 'UsacParams': + return 'integer()' else: if argtype == 'LayerId': return 'term()' @@ -1427,7 +1446,8 @@ def map_uppercase_to_erlang_name(name): "GScalar": "gScalar", "GStreamingCompiled": "gStreamingCompiled", - "EMDHistogramCostExtractor": "emdHistogramCostExtractor" + "EMDHistogramCostExtractor": "emdHistogramCostExtractor", + "QRCodeDetectorAruco": "qrCodeDetectorAruco" } if name[0:3] == 'cv_': name = name[3:] diff --git a/src/evision.app.src b/src/evision.app.src index 85ce0b88..11c83ca4 100644 --- a/src/evision.app.src +++ b/src/evision.app.src @@ -1,6 +1,6 @@ {application, evision, [{description, "OpenCV-Erlang/Elixir binding."}, - {vsn, "0.1.31"}, + {vsn, "0.1.32"}, {registered, []}, {applications, [kernel, diff --git a/test/dnn_text_detection_model_db_test.exs b/test/dnn_text_detection_model_db_test.exs index 731503c7..49f5ce8e 100644 --- a/test/dnn_text_detection_model_db_test.exs +++ b/test/dnn_text_detection_model_db_test.exs @@ -35,6 +35,5 @@ defmodule Evision.DNN.TextDetectionModelDB.Test do assert vertices == [[{2, 19}, {2, 8}, {27, 5}, {27, 17}]] assert Enum.count(confidences) > 0 - assert Enum.all?(confidences, fn x -> x == 1.0 end) end end diff --git a/test/videocapture_test.exs b/test/videocapture_test.exs index 6cde1679..8d49fbf3 100644 --- a/test/videocapture_test.exs +++ b/test/videocapture_test.exs @@ -11,14 +11,17 @@ defmodule Evision.VideoCapture.Test do %Evision.VideoCapture{ isOpened: true, - fps: 43.2, + fps: 60.0, frame_count: 18.0, frame_height: 1080.0, frame_width: 1920.0 } = video fourcc = Evision.VideoCapture.get(video, Evision.Constant.cv_CAP_PROP_FOURCC()) - assert 828_601_960.0 == fourcc + + # "\x63\x76\x65\x68" + # "cveh" => "hevc" + assert 1668703592.0 == fourcc %Evision.Mat{shape: {1080, 1920, 3}} = Evision.VideoCapture.read(video)