From d07c00f04452d874ea9989c93256f392c5dafcee Mon Sep 17 00:00:00 2001 From: sjourdro Date: Mon, 31 Aug 2026 11:07:33 +0200 Subject: [PATCH 1/7] added Filter.gaussianBlur and Filter.gaussianFilter --- .../bindings/include/core/image_filter.hpp | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/modules/python/bindings/include/core/image_filter.hpp b/modules/python/bindings/include/core/image_filter.hpp index 9f2af62dfa..f27ecf89f1 100644 --- a/modules/python/bindings/include/core/image_filter.hpp +++ b/modules/python/bindings/include/core/image_filter.hpp @@ -414,6 +414,124 @@ Example usage: )doc", py::arg("input"), py::arg("output"), py::arg("filter"), py::arg("size"), py::arg("mask").none(true) = static_cast>>(std::nullopt)); } + + +template +void define_gaussianFilter(py::class_> &pyClass) +{ +#ifdef ENABLE_VISP_NAMESPACE + using namespace VISP_NAMESPACE_NAME; +#endif + + pyClass.def_static( + "gaussianFilter", + [](const vpImage &input, + unsigned int r, + unsigned int c) -> double { + return vpImageFilter::gaussianFilter(input, r, c); + }, R"doc( +Apply a 5x5 Gaussian filter to one image pixel. + +:param input: The image to filter. +:param r: Row coordinate of the pixel. +:param c: Column coordinate of the pixel. + +:return: The filtered pixel value. + +Example usage: + +.. testcode:: + + from visp.core import ImageGray, ImageFilter + + Iin = ImageGray(100, 100, 0) + Iin[25:75, 25:75] = 50 + + filtered_value = ImageFilter.gaussianFilter(Iin, 50, 50) + assert isinstance(filtered_value, float) +)doc", + py::arg("input"), + py::arg("r"), + py::arg("c")); +} + +template +void define_gaussianBlur( + py::class_> &pyClass) +{ +#ifdef ENABLE_VISP_NAMESPACE + using namespace VISP_NAMESPACE_NAME; +#endif + + pyClass.def_static( + "gaussianBlur", + [](const vpImage &input, + vpImage &output, + unsigned int size, + double sigma, + bool normalize, + const std::optional> &mask) -> void { + if (!mask) { + vpImageFilter::gaussianBlur(input, output, size, sigma, normalize, nullptr); + } + else { + vpImageFilter::gaussianBlur( + input, output, size, sigma, normalize, &(mask.value())); + } + }, + R"doc( +Apply a Gaussian blur to an image. + +:param input: The input image. +:param output: The resulting blurred image. +:param size: Filter size. This value should be odd. +:param sigma: Gaussian standard deviation. If it is zero or negative, + it is computed from the filter size as ``(size - 1) / 6``. +:param normalize: If True, normalize the Gaussian filter coefficients. +:param mask: Optional mask indicating which pixels to consider. True + means that the pixel is considered, while False means that it is ignored. + +Example usage: + +.. testcode:: + + from visp.core import ImageGray, ImageDouble, ImageBool, ImageFilter + + Iin = ImageGray(100, 100, 0) + Iin[25:75, 25:75] = 50 + + Iout = ImageDouble() + ImageFilter.gaussianBlur(Iin, Iout) + + assert Iout.getRows() == Iin.getRows() + assert Iout.getCols() == Iin.getCols() + + mask = ImageBool(100, 100, True) + + Iout = ImageDouble() + ImageFilter.gaussianBlur( + Iin, + Iout, + size=7, + sigma=0.0, + normalize=True, + mask=mask + ) + + assert Iout.getRows() == Iin.getRows() + assert Iout.getCols() == Iin.getCols() +)doc", + py::arg("input"), + py::arg("output"), + py::arg("size") = 7, + py::arg("sigma") = 0., + py::arg("normalize") = true, + py::arg("mask").none(true) = static_cast>>(std::nullopt)); +} + + + + /* * vpImageFilter */ @@ -431,5 +549,14 @@ bindings_vpImageFilter(py::class_(pyImageFilter); define_complex_getGradXY(pyImageFilter); define_complex_getGradXY(pyImageFilter); + + define_gaussianFilter(pyImageFilter); + define_gaussianFilter(pyImageFilter); + define_gaussianFilter(pyImageFilter); + + define_gaussianBlur(pyImageFilter); + define_gaussianBlur(pyImageFilter); + define_gaussianBlur(pyImageFilter); + define_gaussianBlur(pyImageFilter); } #endif From 977e981425df0f4bcd6aba3d04d8ae716f40e424 Mon Sep 17 00:00:00 2001 From: sjourdro Date: Mon, 31 Aug 2026 16:39:53 +0200 Subject: [PATCH 2/7] corrected indentation --- .../bindings/include/core/image_filter.hpp | 76 +++++++++---------- 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/modules/python/bindings/include/core/image_filter.hpp b/modules/python/bindings/include/core/image_filter.hpp index f27ecf89f1..0b1d2cd7a4 100644 --- a/modules/python/bindings/include/core/image_filter.hpp +++ b/modules/python/bindings/include/core/image_filter.hpp @@ -420,16 +420,16 @@ template void define_gaussianFilter(py::class_> &pyClass) { #ifdef ENABLE_VISP_NAMESPACE - using namespace VISP_NAMESPACE_NAME; + using namespace VISP_NAMESPACE_NAME; #endif - pyClass.def_static( - "gaussianFilter", - [](const vpImage &input, - unsigned int r, - unsigned int c) -> double { - return vpImageFilter::gaussianFilter(input, r, c); - }, R"doc( + pyClass.def_static( + "gaussianFilter", + [](const vpImage &input, + unsigned int r, + unsigned int c) -> double { + return vpImageFilter::gaussianFilter(input, r, c); + }, R"doc( Apply a 5x5 Gaussian filter to one image pixel. :param input: The image to filter. @@ -457,26 +457,25 @@ Example usage: template void define_gaussianBlur( - py::class_> &pyClass) + py::class_> &pyClass) { #ifdef ENABLE_VISP_NAMESPACE using namespace VISP_NAMESPACE_NAME; #endif - pyClass.def_static( - "gaussianBlur", - [](const vpImage &input, - vpImage &output, - unsigned int size, - double sigma, - bool normalize, - const std::optional> &mask) -> void { - if (!mask) { - vpImageFilter::gaussianBlur(input, output, size, sigma, normalize, nullptr); - } - else { - vpImageFilter::gaussianBlur( - input, output, size, sigma, normalize, &(mask.value())); + pyClass.def_static( + "gaussianBlur", + [](const vpImage &input, + vpImage &output, + unsigned int size, + double sigma, + bool normalize, + const std::optional> &mask) -> void { + if (!mask) { + vpImageFilter::gaussianBlur(input, output, size, sigma, normalize, nullptr); + } + else { + vpImageFilter::gaussianBlur(input, output, size, sigma, normalize, &(mask.value())); } }, R"doc( @@ -485,11 +484,9 @@ Apply a Gaussian blur to an image. :param input: The input image. :param output: The resulting blurred image. :param size: Filter size. This value should be odd. -:param sigma: Gaussian standard deviation. If it is zero or negative, - it is computed from the filter size as ``(size - 1) / 6``. +:param sigma: Gaussian standard deviation. If it is zero or negative, it is computed from the filter size as ``(size - 1) / 6``. :param normalize: If True, normalize the Gaussian filter coefficients. -:param mask: Optional mask indicating which pixels to consider. True - means that the pixel is considered, while False means that it is ignored. +:param mask: Optional mask indicating which pixels to consider. True means that the pixel is considered, while False means that it is ignored. Example usage: @@ -510,28 +507,27 @@ Example usage: Iout = ImageDouble() ImageFilter.gaussianBlur( - Iin, - Iout, - size=7, - sigma=0.0, - normalize=True, - mask=mask + Iin, + Iout, + size=7, + sigma=0.0, + normalize=True, + mask=mask ) assert Iout.getRows() == Iin.getRows() assert Iout.getCols() == Iin.getCols() )doc", - py::arg("input"), - py::arg("output"), - py::arg("size") = 7, - py::arg("sigma") = 0., - py::arg("normalize") = true, - py::arg("mask").none(true) = static_cast>>(std::nullopt)); + py::arg("input"), + py::arg("output"), + py::arg("size") = 7, + py::arg("sigma") = 0., + py::arg("normalize") = true, + py::arg("mask").none(true) = static_cast>>(std::nullopt)); } - /* * vpImageFilter */ From e815ea683dcd9a0b77d8154d9dc0828a66cc659b Mon Sep 17 00:00:00 2001 From: sjourdro Date: Mon, 31 Aug 2026 16:55:33 +0200 Subject: [PATCH 3/7] added 2 of 3 canny methods to ImageFilter --- modules/python/config/core.json | 38 +++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/modules/python/config/core.json b/modules/python/config/core.json index 29f1be308a..7b54de10b4 100644 --- a/modules/python/config/core.json +++ b/modules/python/config/core.json @@ -1092,6 +1092,44 @@ "TypeFilterable" ] ] + }, + { + "static": true, + "signature": "void canny(const vpImage< unsigned char > &, vpImage< unsigned char > &, const unsigned int &, const float &, const float &, const unsigned int &)", + "param_is_input": [ + true, + false, + true, + true, + true, + true + ], + "param_is_output": [ + false, + true, + false, + false, + false, + false + ] + }, + { + "static": true, + "signature": "void canny(const vpImage< unsigned char > &, vpImage< unsigned char > &, const unsigned int &, const float &, const unsigned int &)", + "param_is_input": [ + true, + false, + true, + true, + true + ], + "param_is_output": [ + false, + true, + false, + false, + false + ] } ] }, From 31c2b904223b674b88a9fba1dc1ab0c98e691524 Mon Sep 17 00:00:00 2001 From: sjourdro Date: Tue, 1 Sep 2026 15:31:38 +0200 Subject: [PATCH 4/7] added third canny method --- .../bindings/include/core/image_filter.hpp | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/modules/python/bindings/include/core/image_filter.hpp b/modules/python/bindings/include/core/image_filter.hpp index 0b1d2cd7a4..fdfba9144b 100644 --- a/modules/python/bindings/include/core/image_filter.hpp +++ b/modules/python/bindings/include/core/image_filter.hpp @@ -526,6 +526,71 @@ Example usage: py::arg("mask").none(true) = static_cast>>(std::nullopt)); } +void define_canny( + py::class_> &pyClass) +{ +#ifdef ENABLE_VISP_NAMESPACE + using namespace VISP_NAMESPACE_NAME; +#endif + + pyClass.def_static( + "canny", + [](const vpImage &input, + vpImage &output, + unsigned int gaussianFilterSize, + float lowerThreshold, + float upperThreshold, + unsigned int apertureGradient, + float gaussianStdev, + float lowerThresholdRatio, + float upperThresholdRatio, + bool normalizeGradients, + vpImageFilter::vpCannyBackendType cannyBackend, + vpImageFilter::vpCannyFilteringAndGradientType cannyFilteringSteps, + const std::optional> &mask) -> void + { + if (!mask) { + vpImageFilter::canny(input, output, gaussianFilterSize, lowerThreshold, upperThreshold, apertureGradient, gaussianStdev, + lowerThresholdRatio, upperThresholdRatio, normalizeGradients, cannyBackend, cannyFilteringSteps, nullptr); + } + else { + vpImageFilter::canny(input, output, gaussianFilterSize, lowerThreshold, upperThreshold, apertureGradient, gaussianStdev, + lowerThresholdRatio, upperThresholdRatio, normalizeGradients, cannyBackend, cannyFilteringSteps, &(mask.value())); + } + }, + R"doc( +Apply the Canny edge detector to a grayscale image. + +:param input: The input grayscale image. +:param output: The resulting edge image. Edge pixels have value 255, non-edge pixels have value 0. +:param gaussianFilterSize: Size of the Gaussian filter. Must be odd. +:param lowerThreshold: Lower Canny threshold. If negative, it is computed automatically. +:param upperThreshold: Upper Canny threshold. If negative, it is computed automatically. +:param apertureGradient: Size of the Sobel or Scharr gradient mask. Must be odd. +:param gaussianStdev: Gaussian standard deviation. If non-positive, it is computed from the Gaussian filter size. +:param lowerThresholdRatio: Ratio between the lower and upper thresholds when thresholds are computed automatically. +:param upperThresholdRatio: Ratio used to compute the upper threshold when thresholds are computed automatically. +:param normalizeGradients: Normalize gradients before computing thresholds. +:param cannyBackend: Backend used by the Canny implementation. +:param cannyFilteringSteps: Filtering and gradient operators used by Canny. +:param mask: Optional mask. True pixels are processed and False pixels are ignored. +)doc", + py::arg("input"), + py::arg("output"), + py::arg("gaussianFilterSize"), + py::arg("lowerThreshold"), + py::arg("upperThreshold"), + py::arg("apertureGradient"), + py::arg("gaussianStdev"), + py::arg("lowerThresholdRatio"), + py::arg("upperThresholdRatio"), + py::arg("normalizeGradients"), + py::arg("cannyBackend"), + py::arg("cannyFilteringSteps"), + py::arg("mask").none(true) = static_cast>>(std::nullopt) + ); +} + /* @@ -554,5 +619,7 @@ bindings_vpImageFilter(py::class_(pyImageFilter); define_gaussianBlur(pyImageFilter); define_gaussianBlur(pyImageFilter); + + define_canny(pyImageFilter); } #endif From 0560de665cf9617bc3fd68728a649ec8b9c3458c Mon Sep 17 00:00:00 2001 From: sjourdro Date: Tue, 1 Sep 2026 15:39:16 +0200 Subject: [PATCH 5/7] changed parameters description --- .../bindings/include/core/image_filter.hpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/modules/python/bindings/include/core/image_filter.hpp b/modules/python/bindings/include/core/image_filter.hpp index fdfba9144b..2bd84bc930 100644 --- a/modules/python/bindings/include/core/image_filter.hpp +++ b/modules/python/bindings/include/core/image_filter.hpp @@ -561,19 +561,19 @@ void define_canny( R"doc( Apply the Canny edge detector to a grayscale image. -:param input: The input grayscale image. -:param output: The resulting edge image. Edge pixels have value 255, non-edge pixels have value 0. -:param gaussianFilterSize: Size of the Gaussian filter. Must be odd. -:param lowerThreshold: Lower Canny threshold. If negative, it is computed automatically. -:param upperThreshold: Upper Canny threshold. If negative, it is computed automatically. -:param apertureGradient: Size of the Sobel or Scharr gradient mask. Must be odd. -:param gaussianStdev: Gaussian standard deviation. If non-positive, it is computed from the Gaussian filter size. -:param lowerThresholdRatio: Ratio between the lower and upper thresholds when thresholds are computed automatically. -:param upperThresholdRatio: Ratio used to compute the upper threshold when thresholds are computed automatically. -:param normalizeGradients: Normalize gradients before computing thresholds. -:param cannyBackend: Backend used by the Canny implementation. -:param cannyFilteringSteps: Filtering and gradient operators used by Canny. -:param mask: Optional mask. True pixels are processed and False pixels are ignored. +:param Isrc : The input grayscale image. +:param Ires : The resulting edge image. Edge pixels have value 255, non-edge pixels have value 0. +:param gaussianFilterSize : Size of the Gaussian filter. Must be odd. +:param lowerThreshold : The lower threshold for the Canny operator. Values lower than this value are rejected. If negative, it will be set to one third of the thresholdCanny. +:param upperThreshold : The upper threshold for the Canny operator. Only value greater than this value are marked as an edge. If negative, it will be automatically computed, along with the lower threshold. Otherwise, the lower threshold will be set to one third of the upper threshold. +:param apertureGradient : Size of the Sobel or Scharr gradient mask. Must be odd. +:param gaussianStdev : The standard deviation of the Gaussian filter to apply. If it is non-positive, it is computed from kernel size (gaussianKernelSize parameter) as σ=0.3∗((gaussianKernelSize−1)∗0.5−1)+0.8. +:param lowerThresholdRatio : The ratio of the upper threshold the lower threshold must be equal to. It is used only if the user asks to compute the Canny thresholds. +:param upperThresholdRatio : The ratio of pixels whose absolute gradient is lower or equal to define the upper threshold. It is used only if the user asks to compute the Canny thresholds. +:param normalizeGradients : Needs to be true if asking to compute the upperThreshold, otherwise it depends on the user application and user-defined thresholds. +:param cannyBackend : The backend to use to perform the Canny edge filtering. +:param cannyFilteringSteps : The filtering + gradient operators to apply to compute the gradient in the early stage of the Canny algorithm. +:param p_mask : Optional mask. True pixels are processed and False pixels are ignored. )doc", py::arg("input"), py::arg("output"), From e0c1727639e533b05b231a0e4030d0fbbb71cbd0 Mon Sep 17 00:00:00 2001 From: sjourdro Date: Mon, 7 Sep 2026 09:54:38 +0200 Subject: [PATCH 6/7] updated copyright --- modules/python/bindings/include/core/image_filter.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/python/bindings/include/core/image_filter.hpp b/modules/python/bindings/include/core/image_filter.hpp index 2bd84bc930..4c96690c5f 100644 --- a/modules/python/bindings/include/core/image_filter.hpp +++ b/modules/python/bindings/include/core/image_filter.hpp @@ -1,6 +1,6 @@ /* * ViSP, open source Visual Servoing Platform software. - * Copyright (C) 2005 - 2025 by Inria. All rights reserved. + * Copyright (C) 2005 - 2026 by Inria. All rights reserved. * * This software is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From 68a69e17046c7981582b06155042ddd3ecb18775 Mon Sep 17 00:00:00 2001 From: sjourdro Date: Mon, 7 Sep 2026 10:10:02 +0200 Subject: [PATCH 7/7] corrected typo --- modules/python/bindings/include/core/image_filter.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/python/bindings/include/core/image_filter.hpp b/modules/python/bindings/include/core/image_filter.hpp index 4c96690c5f..f395f55e4b 100644 --- a/modules/python/bindings/include/core/image_filter.hpp +++ b/modules/python/bindings/include/core/image_filter.hpp @@ -573,7 +573,7 @@ Apply the Canny edge detector to a grayscale image. :param normalizeGradients : Needs to be true if asking to compute the upperThreshold, otherwise it depends on the user application and user-defined thresholds. :param cannyBackend : The backend to use to perform the Canny edge filtering. :param cannyFilteringSteps : The filtering + gradient operators to apply to compute the gradient in the early stage of the Canny algorithm. -:param p_mask : Optional mask. True pixels are processed and False pixels are ignored. +:param mask : Optional mask. True pixels are processed and False pixels are ignored. )doc", py::arg("input"), py::arg("output"),