Skip to content

feat: add conditional inclusion support to header parser#27325

Merged
asmorkalov merged 1 commit intoopencv:4.xfrom
VadimLevin:dev/vlevin/header-parser-conditional-inclusion-directives-handling
May 20, 2025
Merged

feat: add conditional inclusion support to header parser#27325
asmorkalov merged 1 commit intoopencv:4.xfrom
VadimLevin:dev/vlevin/header-parser-conditional-inclusion-directives-handling

Conversation

@VadimLevin
Copy link
Copy Markdown
Contributor

@VadimLevin VadimLevin commented May 16, 2025

Brings support for conditional inclusion directives evaluation and proper #if/#else/#elif branches support.

Generated diffs are attached:

cv::Feature2D has a valid base class now, because #else is not discarded

#ifdef __EMSCRIPTEN__
class CV_EXPORTS_W Feature2D : public Algorithm
#else
class CV_EXPORTS_W Feature2D : public virtual Algorithm
#endif

Build warning is resolved:

Note: Class Feature2D has more than 1 base class (not supported by Python C extensions)
      Bases:  cv::Algorithm, cv::class, cv::Feature2D, cv::Algorithm
      Only the first base class will be used

Related diff in pyopencv_generated_types.h

# Before
CVPY_TYPE(Feature2D, Feature2D, Ptr<cv::Feature2D>, Ptr, NoBase, 0, "")
# After
CVPY_TYPE(Feature2D, Feature2D, Ptr<cv::Feature2D>, Ptr, Algorithm, 0, "")

Duplicate for cv::RotationWarper::warpPointBackward is removed from function dispatch.

#if CV_VERSION_MAJOR == 4
    virtual Point2f warpPointBackward(const Point2f& pt, InputArray K, InputArray R)
    {
        CV_UNUSED(pt); CV_UNUSED(K); CV_UNUSED(R);
        CV_Error(Error::StsNotImplemented, "");
    }
#else
    virtual Point2f warpPointBackward(const Point2f& pt, InputArray K, InputArray R) = 0;
#endif

Related diff in pyopencv_generated_types_content.h

Before
static PyObject* pyopencv_cv_PyRotationWarper_warpPointBackward(PyObject* self, PyObject* py_args, PyObject* kw)
{
    using namespace cv;


    Ptr<cv::PyRotationWarper> * self1 = 0;
    if (!pyopencv_PyRotationWarper_getp(self, self1))
        return failmsgp("Incorrect type of self (must be 'PyRotationWarper' or its derivative)");
    Ptr<cv::PyRotationWarper> _self_ = *(self1);
    pyPrepareArgumentConversionErrorsStorage(4);

    {
    PyObject* pyobj_pt = NULL;
    Point2f pt;
    PyObject* pyobj_K = NULL;
    Mat K;
    PyObject* pyobj_R = NULL;
    Mat R;
    Point2f retval;

    const char* keywords[] = { "pt", "K", "R", NULL };
    if( PyArg_ParseTupleAndKeywords(py_args, kw, "OOO:PyRotationWarper.warpPointBackward", (char**)keywords, &pyobj_pt, &pyobj_K, &pyobj_R) &&
        pyopencv_to_safe(pyobj_pt, pt, ArgInfo("pt", 0)) &&
        pyopencv_to_safe(pyobj_K, K, ArgInfo("K", 0)) &&
        pyopencv_to_safe(pyobj_R, R, ArgInfo("R", 0)) )
    {
        ERRWRAP2(retval = _self_->warpPointBackward(pt, K, R));
        return pyopencv_from(retval);
    }


        pyPopulateArgumentConversionErrors();
    }
    

    {
    PyObject* pyobj_pt = NULL;
    Point2f pt;
    PyObject* pyobj_K = NULL;
    Mat K;
    PyObject* pyobj_R = NULL;
    Mat R;
    Point2f retval;

    const char* keywords[] = { "pt", "K", "R", NULL };
    if( PyArg_ParseTupleAndKeywords(py_args, kw, "OOO:PyRotationWarper.warpPointBackward", (char**)keywords, &pyobj_pt, &pyobj_K, &pyobj_R) &&
        pyopencv_to_safe(pyobj_pt, pt, ArgInfo("pt", 0)) &&
        pyopencv_to_safe(pyobj_K, K, ArgInfo("K", 0)) &&
        pyopencv_to_safe(pyobj_R, R, ArgInfo("R", 0)) )
    {
        ERRWRAP2(retval = _self_->warpPointBackward(pt, K, R));
        return pyopencv_from(retval);
    }


        pyPopulateArgumentConversionErrors();
    }
    

    {
    PyObject* pyobj_pt = NULL;
    Point2f pt;
    PyObject* pyobj_K = NULL;
    UMat K;
    PyObject* pyobj_R = NULL;
    UMat R;
    Point2f retval;

    const char* keywords[] = { "pt", "K", "R", NULL };
    if( PyArg_ParseTupleAndKeywords(py_args, kw, "OOO:PyRotationWarper.warpPointBackward", (char**)keywords, &pyobj_pt, &pyobj_K, &pyobj_R) &&
        pyopencv_to_safe(pyobj_pt, pt, ArgInfo("pt", 0)) &&
        pyopencv_to_safe(pyobj_K, K, ArgInfo("K", 0)) &&
        pyopencv_to_safe(pyobj_R, R, ArgInfo("R", 0)) )
    {
        ERRWRAP2(retval = _self_->warpPointBackward(pt, K, R));
        return pyopencv_from(retval);
    }


        pyPopulateArgumentConversionErrors();
    }
    

    {
    PyObject* pyobj_pt = NULL;
    Point2f pt;
    PyObject* pyobj_K = NULL;
    UMat K;
    PyObject* pyobj_R = NULL;
    UMat R;
    Point2f retval;

    const char* keywords[] = { "pt", "K", "R", NULL };
    if( PyArg_ParseTupleAndKeywords(py_args, kw, "OOO:PyRotationWarper.warpPointBackward", (char**)keywords, &pyobj_pt, &pyobj_K, &pyobj_R) &&
        pyopencv_to_safe(pyobj_pt, pt, ArgInfo("pt", 0)) &&
        pyopencv_to_safe(pyobj_K, K, ArgInfo("K", 0)) &&
        pyopencv_to_safe(pyobj_R, R, ArgInfo("R", 0)) )
    {
        ERRWRAP2(retval = _self_->warpPointBackward(pt, K, R));
        return pyopencv_from(retval);
    }


        pyPopulateArgumentConversionErrors();
    }
    pyRaiseCVOverloadException("warpPointBackward");

    return NULL;
}
After
static PyObject* pyopencv_cv_PyRotationWarper_warpPointBackward(PyObject* self, PyObject* py_args, PyObject* kw)
{
    using namespace cv;


    Ptr<cv::PyRotationWarper> * self1 = 0;
    if (!pyopencv_PyRotationWarper_getp(self, self1))
        return failmsgp("Incorrect type of self (must be 'PyRotationWarper' or its derivative)");
    Ptr<cv::PyRotationWarper> _self_ = *(self1);
    pyPrepareArgumentConversionErrorsStorage(2);

    {
    PyObject* pyobj_pt = NULL;
    Point2f pt;
    PyObject* pyobj_K = NULL;
    Mat K;
    PyObject* pyobj_R = NULL;
    Mat R;
    Point2f retval;

    const char* keywords[] = { "pt", "K", "R", NULL };
    if( PyArg_ParseTupleAndKeywords(py_args, kw, "OOO:PyRotationWarper.warpPointBackward", (char**)keywords, &pyobj_pt, &pyobj_K, &pyobj_R) &&
        pyopencv_to_safe(pyobj_pt, pt, ArgInfo("pt", 0)) &&
        pyopencv_to_safe(pyobj_K, K, ArgInfo("K", 0)) &&
        pyopencv_to_safe(pyobj_R, R, ArgInfo("R", 0)) )
    {
        ERRWRAP2(retval = _self_->warpPointBackward(pt, K, R));
        return pyopencv_from(retval);
    }


        pyPopulateArgumentConversionErrors();
    }
    

    {
    PyObject* pyobj_pt = NULL;
    Point2f pt;
    PyObject* pyobj_K = NULL;
    UMat K;
    PyObject* pyobj_R = NULL;
    UMat R;
    Point2f retval;

    const char* keywords[] = { "pt", "K", "R", NULL };
    if( PyArg_ParseTupleAndKeywords(py_args, kw, "OOO:PyRotationWarper.warpPointBackward", (char**)keywords, &pyobj_pt, &pyobj_K, &pyobj_R) &&
        pyopencv_to_safe(pyobj_pt, pt, ArgInfo("pt", 0)) &&
        pyopencv_to_safe(pyobj_K, K, ArgInfo("K", 0)) &&
        pyopencv_to_safe(pyobj_R, R, ArgInfo("R", 0)) )
    {
        ERRWRAP2(retval = _self_->warpPointBackward(pt, K, R));
        return pyopencv_from(retval);
    }


        pyPopulateArgumentConversionErrors();
    }
    pyRaiseCVOverloadException("warpPointBackward");

    return NULL;
}
Closes #27250
Closes #27064
Closes #10175
Closes #12972

Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
  • The PR is proposed to the proper branch
  • There is a reference to the original bug report and related work
  • There is accuracy test, performance test and test data in opencv_extra repository, if applicable
    Patch to opencv_extra has the same branch name.
  • The feature is well documented and sample code can be built with the project CMake

@VadimLevin VadimLevin requested a review from asmorkalov May 16, 2025 10:13
@VadimLevin VadimLevin self-assigned this May 16, 2025
@VadimLevin VadimLevin force-pushed the dev/vlevin/header-parser-conditional-inclusion-directives-handling branch from 2392492 to 4a93fbd Compare May 16, 2025 10:25
@dkurt
Copy link
Copy Markdown
Member

dkurt commented May 16, 2025

Some related issues, can you please also check?
#10175
#12972

@VadimLevin VadimLevin force-pushed the dev/vlevin/header-parser-conditional-inclusion-directives-handling branch from 4a93fbd to d32123c Compare May 16, 2025 11:41
@VadimLevin
Copy link
Copy Markdown
Contributor Author

Some related issues, can you please also check? #10175 #12972

Thank you. This patch resolves both mentioned issues. For #10175 if HAVE_OPENCV_FLANN resolves to 0

compile:
    [mkdir] Created dir: /Users/opencv-cn/GHA-OCV-3/_work/opencv/opencv/build/java_test/build/classes
    [javac] Compiling 63 source files to /Users/opencv-cn/GHA-OCV-3/_work/opencv/opencv/build/java_test/build/classes
    [javac] /Users/opencv-cn/GHA-OCV-3/_work/opencv/opencv/build/java_test/src/org/opencv/test/features2d/FlannBasedDescriptorMatcherTest.java:15: error: cannot find symbol
    [javac] import org.opencv.features2d.FlannBasedMatcher;
    [javac]                             ^
    [javac]   symbol:   class FlannBasedMatcher
    [javac]   location: package org.opencv.features2d

@VadimLevin VadimLevin force-pushed the dev/vlevin/header-parser-conditional-inclusion-directives-handling branch 2 times, most recently from 4d8c249 to 4b68d2c Compare May 16, 2025 12:18
@VadimLevin VadimLevin force-pushed the dev/vlevin/header-parser-conditional-inclusion-directives-handling branch from 4b68d2c to 6ac0816 Compare May 16, 2025 12:43
@VadimLevin VadimLevin force-pushed the dev/vlevin/header-parser-conditional-inclusion-directives-handling branch from 6ac0816 to b3e17ea Compare May 19, 2025 07:43
@asmorkalov
Copy link
Copy Markdown
Contributor

@mshabunin @opencv-alalek could you take a look too?

@asmorkalov asmorkalov added this to the 4.12.0 milestone May 20, 2025
@asmorkalov asmorkalov merged commit 23f8e52 into opencv:4.x May 20, 2025
53 of 55 checks passed
"Failed to evaluate '{}' directive, stripped down to '{}'".format(
input_directive, directive
)
) from e
Copy link
Copy Markdown
Member

@dkurt dkurt May 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check failed build https://pullrequest.opencv.org/buildbot/builders/precommit_windows64/builds/109668/steps/compile%20release/logs/stdio:

 Traceback (most recent call last):
    File "C:/build/precommit_windows64/4.x/opencv/modules/java/generator/../generator/gen_java.py", line 1422, in <module>
      import hdr_parser
    File "C:\build\precommit_windows64\4.x\opencv\modules\python\src2\hdr_parser.py", line 154
      ) from e
           ^
  SyntaxError: invalid syntax
  opencv_gapi_SSE4_1.vcxproj -> C:\build\precommit_windows64\build\modules\gapi\opencv_gapi_SSE4_1.dir\Release\opencv_gapi_SSE4_1.lib
  Generate files for Python bindings and documentation
C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140\Microsoft.CppCommon.targets(171,5): error MSB6006: "cmd.exe" exited with code 1. [C:\build\precommit_windows64\build\modules\java_bindings_generator\gen_opencv_java_source.vcxproj]
  Traceback (most recent call last):
    File "C:/build/precommit_windows64/4.x/opencv/modules/python/src2/gen2.py", line 4, in <module>
      import hdr_parser, sys, re
    File "C:\build\precommit_windows64\4.x\opencv\modules\python\src2\hdr_parser.py", line 154
      ) from e
           ^
  SyntaxError: invalid syntax
C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140\Microsoft.CppCommon.targets(171,5): error MSB6006: "cmd.exe" exited with code 1. [C:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It requires Python update. I notified Alexander about it.

@asmorkalov asmorkalov assigned asmorkalov and unassigned VadimLevin May 21, 2025
@vrabaud
Copy link
Copy Markdown
Contributor

vrabaud commented May 24, 2025

Thanks for the patch, that really helps. I have a different build system though (blaze) so I generate the binding files in CMake and then include them in blaze which works fine. Some users might need DNN in the bindings, others might not (typically, Java and Android Java) and one header for both is easier.

Would the following be possible: keep your patch but keep the guards in the bindings instead of removing the guarded sections. This way, the binding headers would be usable for different configurations (e.g. with or without HAVE_OPENCV_DNN being defined).

@asmorkalov asmorkalov mentioned this pull request May 27, 2025
@VadimLevin
Copy link
Copy Markdown
Contributor Author

Would the following be possible: keep your patch but keep the guards in the bindings instead of removing the guarded sections. This way, the binding headers would be usable for different configurations (e.g. with or without HAVE_OPENCV_DNN being defined).

Thank you for suggestion. Your approach requires significant changes in header parser and all bindings generators, because "availability information" should be a part of "function/enum/class/struct" definition. We can consider doing it once we begin reworking the header parser, updating intermediate representation and unifying all bindings generation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

4 participants