1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-27 22:33:03 +04:00

Merge branch 4.x

This commit is contained in:
Alexander Smorkalov
2025-05-27 16:48:22 +03:00
167 changed files with 7028 additions and 4687 deletions
+42 -3
View File
@@ -47,6 +47,7 @@ endforeach(m)
# header blacklist
ocv_list_filterout(opencv_hdrs "modules/.*\\\\.h$")
ocv_list_filterout(opencv_hdrs "modules/core/include/opencv2/core/fast_math.hpp")
ocv_list_filterout(opencv_hdrs "modules/core/.*/cuda/")
ocv_list_filterout(opencv_hdrs "modules/core/.*/hal/")
ocv_list_filterout(opencv_hdrs "modules/core/.*/opencl/")
@@ -74,12 +75,50 @@ set(cv2_generated_files
"${OPENCV_PYTHON_SIGNATURES_FILE}"
)
string(REPLACE ";" "\n" opencv_hdrs_ "${opencv_hdrs}")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/headers.txt" "${opencv_hdrs_}")
set(config_json_headers_list "")
foreach(header IN LISTS opencv_hdrs)
if(NOT config_json_headers_list STREQUAL "")
set(config_json_headers_list "${config_json_headers_list},\n\"${header}\"")
else()
set(config_json_headers_list "\"${header}\"")
endif()
endforeach()
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVBindingsPreprocessorDefinitions.cmake")
ocv_bindings_generator_populate_preprocessor_definitions(
OPENCV_MODULES_BUILD
opencv_preprocessor_defs
)
set(__config_str
"{
\"headers\": [
${config_json_headers_list}
],
\"preprocessor_definitions\": {
${opencv_preprocessor_defs}
}
}")
set(JSON_CONFIG_FILE_PATH "${CMAKE_CURRENT_BINARY_DIR}/gen_python_config.json")
if(EXISTS "${JSON_CONFIG_FILE_PATH}")
file(READ "${JSON_CONFIG_FILE_PATH}" __content)
else()
set(__content "")
endif()
if(NOT "${__content}" STREQUAL "${__config_str}")
file(WRITE "${JSON_CONFIG_FILE_PATH}" "${__config_str}")
endif()
unset(__config_str)
file(GLOB_RECURSE typing_stubs_generation_files "${PYTHON_SOURCE_DIR}/src2/typing_stubs_generation/*.py")
add_custom_command(
OUTPUT ${cv2_generated_files}
COMMAND "${PYTHON_DEFAULT_EXECUTABLE}" "${PYTHON_SOURCE_DIR}/src2/gen2.py" "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/headers.txt"
COMMAND "${PYTHON_DEFAULT_EXECUTABLE}" "${PYTHON_SOURCE_DIR}/src2/gen2.py"
"--config" "${JSON_CONFIG_FILE_PATH}"
"--output_dir" "${CMAKE_CURRENT_BINARY_DIR}"
DEPENDS "${PYTHON_SOURCE_DIR}/src2/gen2.py"
"${PYTHON_SOURCE_DIR}/src2/hdr_parser.py"
"${typing_stubs_generation_files}"
+2
View File
@@ -43,7 +43,9 @@ typedef std::vector<DMatch> vector_DMatch;
typedef std::vector<String> vector_String;
typedef std::vector<std::string> vector_string;
typedef std::vector<Scalar> vector_Scalar;
#ifdef HAVE_OPENCV_OBJDETECT
typedef std::vector<aruco::Dictionary> vector_Dictionary;
#endif // HAVE_OPENCV_OBJDETECT
typedef std::vector<std::vector<char> > vector_vector_char;
typedef std::vector<std::vector<Point> > vector_vector_Point;
+23
View File
@@ -182,6 +182,29 @@ struct PyOpenCV_Converter
}
};
// There is conflict between "long long" and "int64".
// They are the same type on some 32-bit platforms.
template<typename T>
struct PyOpenCV_Converter
< T, typename std::enable_if< std::is_same<long long, T>::value && !std::is_same<long long, int64>::value >::type >
{
static inline PyObject* from(const long long& value)
{
return PyLong_FromLongLong(value);
}
static inline bool to(PyObject* obj, long long& value, const ArgInfo& info)
{
CV_UNUSED(info);
if(!obj || obj == Py_None)
return true;
else if(PyLong_Check(obj))
value = PyLong_AsLongLong(obj);
else
return false;
return value != (long long)-1 || !PyErr_Occurred();
}
};
// --- uchar
template<> bool pyopencv_to(PyObject* obj, uchar& value, const ArgInfo& info);
+51 -11
View File
@@ -2,6 +2,7 @@
from __future__ import print_function
import hdr_parser, sys, re
import json
from string import Template
from pprint import pprint
from collections import namedtuple
@@ -1109,6 +1110,18 @@ class Namespace(object):
class PythonWrapperGenerator(object):
class Config:
def __init__(self, headers, preprocessor_definitions = None):
self.headers = headers
if preprocessor_definitions is None:
preprocessor_definitions = {}
elif not isinstance(preprocessor_definitions, dict):
raise TypeError(
"preprocessor_definitions should rather dictionary or None. "
"Got: {}".format(type(preprocessor_definitions).__name__)
)
self.preprocessor_definitions = preprocessor_definitions
def __init__(self):
self.clear()
@@ -1327,13 +1340,16 @@ class PythonWrapperGenerator(object):
f.write(buf.getvalue())
def save_json(self, path, name, value):
import json
with open(path + "/" + name, "wt") as f:
json.dump(value, f)
def gen(self, srcfiles, output_path):
def gen(self, srcfiles, output_path, preprocessor_definitions = None):
self.clear()
self.parser = hdr_parser.CppHeaderParser(generate_umat_decls=True, generate_gpumat_decls=True)
self.parser = hdr_parser.CppHeaderParser(
generate_umat_decls=True,
generate_gpumat_decls=True,
preprocessor_definitions=preprocessor_definitions
)
# step 1: scan the headers and build more descriptive maps of classes, consts, functions
for hdr in srcfiles:
@@ -1504,12 +1520,36 @@ class PythonWrapperGenerator(object):
self.save_json(output_path, "pyopencv_signatures.json", self.py_signatures)
if __name__ == "__main__":
srcfiles = hdr_parser.opencv_hdr_list
dstdir = "/Users/vp/tmp"
if len(sys.argv) > 1:
dstdir = sys.argv[1]
if len(sys.argv) > 2:
with open(sys.argv[2], 'r') as f:
srcfiles = [l.strip() for l in f.readlines()]
import argparse
import tempfile
arg_parser = argparse.ArgumentParser(
description="OpenCV Python bindings generator"
)
arg_parser.add_argument(
"-c", "--config",
dest="config_json_path",
required=False,
help="Generator configuration file in .json format"
"Refer to PythonWrapperGenerator.Config for available "
"configuration keys"
)
arg_parser.add_argument(
"-o", "--output_dir",
dest="output_dir",
default=tempfile.gettempdir(),
help="Generated bindings output directory"
)
args = arg_parser.parse_args()
if args.config_json_path is not None:
with open(args.config_json_path, "r") as fh:
config_json = json.load(fh)
config = PythonWrapperGenerator.Config(**config_json)
else:
config = PythonWrapperGenerator.Config(
headers=hdr_parser.opencv_hdr_list
)
generator = PythonWrapperGenerator()
generator.gen(srcfiles, dstdir)
generator.gen(config.headers, args.output_dir, config.preprocessor_definitions)
+179 -14
View File
@@ -33,11 +33,160 @@ where the list of modifiers is yet another nested list of strings
original_return_type is None if the original_return_type is the same as return_value_type
"""
def evaluate_conditional_inclusion_directive(directive, preprocessor_definitions):
"""Evaluates C++ conditional inclusion directive.
Reference: https://en.cppreference.com/w/cpp/preprocessor/conditional
Args:
directive(str): input C++ conditional directive.
preprocessor_definitions(dict[str, int]): defined preprocessor identifiers.
Returns:
bool: True, if directive is evaluated to 1, False otherwise.
>>> evaluate_conditional_inclusion_directive("#ifdef A", {"A": 0})
True
>>> evaluate_conditional_inclusion_directive("#ifdef A", {"B": 0})
False
>>> evaluate_conditional_inclusion_directive("#ifndef A", {})
True
>>> evaluate_conditional_inclusion_directive("#ifndef A", {"A": 1})
False
>>> evaluate_conditional_inclusion_directive("#if 0", {})
False
>>> evaluate_conditional_inclusion_directive("#if 1", {})
True
>>> evaluate_conditional_inclusion_directive("#if VAR", {"VAR": 0})
False
>>> evaluate_conditional_inclusion_directive("#if VAR ", {"VAR": 1})
True
>>> evaluate_conditional_inclusion_directive("#if defined(VAR)", {"VAR": 0})
True
>>> evaluate_conditional_inclusion_directive("#if !defined(VAR)", {"VAR": 0})
False
>>> evaluate_conditional_inclusion_directive("#if defined(VAR_1)", {"VAR_2": 0})
False
>>> evaluate_conditional_inclusion_directive(
... "#if defined(VAR) && VAR", {"VAR": 0}
... )
False
>>> evaluate_conditional_inclusion_directive(
... "#if VAR_1 || VAR_2", {"VAR_1": 1, "VAR_2": 0}
... )
True
>>> evaluate_conditional_inclusion_directive(
... "#if defined VAR && defined (VAR)", {"VAR": 1}
... )
True
>>> evaluate_conditional_inclusion_directive(
... "#if strangedefinedvar", {}
... )
Traceback (most recent call last):
...
ValueError: Failed to evaluate '#if strangedefinedvar' directive, stripped down to 'strangedefinedvar'
"""
OPERATORS = { "!": "not ", "&&": "and", "&": "and", "||": "or", "|": "or" }
input_directive = directive
# Ignore all directives if they contain __cplusplus check
if "__cplusplus" in directive:
return True
directive = directive.strip()
if directive.startswith("#ifdef "):
var = directive[len("#ifdef "):].strip()
return var in preprocessor_definitions
if directive.startswith("#ifndef "):
var = directive[len("#ifndef "):].strip()
return var not in preprocessor_definitions
if directive.startswith("#if "):
directive = directive[len("#if "):].strip()
elif directive.startswith("#elif "):
directive = directive[len("#elif "):].strip()
else:
raise ValueError("{} is not known conditional directive".format(directive))
if directive.isdigit():
return int(directive) != 0
if directive in preprocessor_definitions:
return bool(preprocessor_definitions[directive])
# Converting all `defined` directives to their boolean representations
# they have 2 forms: `defined identifier` and `defined(identifier)`
directive = re.sub(
r"\bdefined\s*(\w+|\(\w+\))",
lambda m: "True" if m.group(1).strip("() ") in preprocessor_definitions else "False",
directive
)
for src_op, dst_op in OPERATORS.items():
directive = directive.replace(src_op, dst_op)
try:
if sys.version_info >= (3, 13):
eval_directive = eval(directive,
globals={"__builtins__": {}},
locals=preprocessor_definitions)
else:
eval_directive = eval(directive,
{"__builtins__": {}},
preprocessor_definitions)
except Exception as e:
raise ValueError(
"Failed to evaluate '{}' directive, stripped down to '{}'".format(
input_directive, directive
)
) from e
if not isinstance(eval_directive, (bool, int)):
raise TypeError(
"'{}' directive is evaluated to unexpected type: {}".format(
input_directive, type(eval_directive).__name__
)
)
if isinstance(eval_directive, bool):
return eval_directive
return eval_directive != 0
class CppHeaderParser(object):
def __init__(self, generate_umat_decls=False, generate_gpumat_decls=False):
def __init__(self, generate_umat_decls = False, generate_gpumat_decls = False,
preprocessor_definitions = None):
self._generate_umat_decls = generate_umat_decls
self._generate_gpumat_decls = generate_gpumat_decls
if preprocessor_definitions is None:
preprocessor_definitions = {}
elif not isinstance(preprocessor_definitions, dict):
raise TypeError(
"preprocessor_definitions should rather dictionary or None. "
"Got: {}".format(type(preprocessor_definitions).__name__)
)
self.preprocessor_definitions = preprocessor_definitions
if "__OPENCV_BUILD" not in self.preprocessor_definitions:
self.preprocessor_definitions["__OPENCV_BUILD"] = 0
if "OPENCV_BINDING_PARSER" not in self.preprocessor_definitions:
self.preprocessor_definitions["OPENCV_BINDING_PARSER"] = 1
if "OPENCV_BINDINGS_PARSER" not in self.preprocessor_definitions:
self.preprocessor_definitions["OPENCV_BINDINGS_PARSER"] = 1
self.BLOCK_TYPE = 0
self.BLOCK_NAME = 1
@@ -192,6 +341,8 @@ class CppHeaderParser(object):
angle_stack[-1] += 1
elif arg_type == "struct":
arg_type += " " + w
elif prev_w in ["signed", "unsigned", "short", "long"] and w in ["char", "short", "int", "long"]:
arg_type += " " + w
elif arg_type and arg_type != "~":
arg_name = " ".join(word_list[wi:])
break
@@ -839,9 +990,8 @@ class CppHeaderParser(object):
"""
self.hname = hname
decls = []
f = io.open(hname, 'rt', encoding='utf-8')
linelist = list(f.readlines())
f.close()
with io.open(hname, 'rt', encoding='utf-8') as f:
linelist = list(f.readlines())
# states:
SCAN = 0 # outside of a comment or preprocessor directive
@@ -859,7 +1009,6 @@ class CppHeaderParser(object):
self.wrap_mode = wmode
depth_if_0 = 0
for l0 in linelist:
self.lineno += 1
#print(state, self.lineno, l0)
@@ -886,22 +1035,35 @@ class CppHeaderParser(object):
continue
state = SCAN
l = re.sub(r'//(.+)?', '', l).strip() # drop // comment
if l in [
'#if 0',
'#if defined(__OPENCV_BUILD)', '#ifdef __OPENCV_BUILD',
'#if !defined(OPENCV_BINDING_PARSER)', '#ifndef OPENCV_BINDING_PARSER',
]:
if l.startswith("#if") or l.startswith("#elif"):
if not evaluate_conditional_inclusion_directive(
l, self.preprocessor_definitions
):
# Condition evaluated to false
state = DIRECTIVE_IF_0
depth_if_0 = 1
elif l.startswith("#else"):
# else in state == DIRECTIVE may occur only if previous
# conditional inclusion directive was evaluated to True
state = DIRECTIVE_IF_0
depth_if_0 = 1
continue
if state == DIRECTIVE_IF_0:
if l.startswith('#'):
l = l[1:].strip()
if l.startswith("if"):
if l.startswith("#"):
if l.startswith("#if"):
depth_if_0 += 1
continue
if l.startswith("endif"):
elif l.startswith("#else") and depth_if_0 == 1:
depth_if_0 = 0
state = SCAN
elif l.startswith("#elif") and depth_if_0 == 1:
if evaluate_conditional_inclusion_directive(
l, self.preprocessor_definitions
):
depth_if_0 = 0
state = SCAN
elif l.startswith("#endif"):
depth_if_0 -= 1
if depth_if_0 == 0:
state = SCAN
@@ -1075,6 +1237,9 @@ class CppHeaderParser(object):
print()
if __name__ == '__main__':
import doctest
doctest.testmod()
parser = CppHeaderParser(generate_umat_decls=True, generate_gpumat_decls=True)
decls = []
for hname in opencv_hdr_list:
@@ -28,6 +28,7 @@ _PREDEFINED_TYPES = (
PrimitiveTypeNode.int_("uint32_t"),
PrimitiveTypeNode.int_("size_t"),
PrimitiveTypeNode.int_("int64_t"),
PrimitiveTypeNode.int_("long long"),
PrimitiveTypeNode.float_("float"),
PrimitiveTypeNode.float_("double"),
PrimitiveTypeNode.bool_("bool"),