diff --git a/modules/ximgproc/include/opencv2/ximgproc.hpp b/modules/ximgproc/include/opencv2/ximgproc.hpp index 099205126c..3bf2d81934 100644 --- a/modules/ximgproc/include/opencv2/ximgproc.hpp +++ b/modules/ximgproc/include/opencv2/ximgproc.hpp @@ -1,38 +1,6 @@ -/* - * By downloading, copying, installing or using the software you agree to this license. - * If you do not agree to this license, do not download, install, - * copy or use the software. - * - * - * License Agreement - * For Open Source Computer Vision Library - * (3 - clause BSD License) - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met : - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and / or other materials provided with the distribution. - * - * * Neither the names of the copyright holders nor the names of the contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * This software is provided by the copyright holders and contributors "as is" and - * any express or implied warranties, including, but not limited to, the implied - * warranties of merchantability and fitness for a particular purpose are disclaimed. - * In no event shall copyright holders or contributors be liable for any direct, - * indirect, incidental, special, exemplary, or consequential damages - * (including, but not limited to, procurement of substitute goods or services; - * loss of use, data, or profits; or business interruption) however caused - * and on any theory of liability, whether in contract, strict liability, - * or tort(including negligence or otherwise) arising in any way out of - * the use of this software, even if advised of the possibility of such damage. - */ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. #ifndef __OPENCV_XIMGPROC_HPP__ #define __OPENCV_XIMGPROC_HPP__ @@ -68,6 +36,8 @@ /** @defgroup ximgproc Extended Image Processing @{ + @defgroup ximgproc_binarization Binarization + @defgroup ximgproc_edge Structured forests for fast edge detection This module contains implementations of modern structured edge detection algorithms, @@ -124,7 +94,7 @@ namespace cv namespace ximgproc { -//! @addtogroup ximgproc +//! @addtogroup ximgproc_binarization //! @{ enum ThinningTypes{ @@ -179,15 +149,20 @@ CV_EXPORTS_W void niBlackThreshold( InputArray _src, OutputArray _dst, int blockSize, double k, int binarizationMethod = BINARIZATION_NIBLACK, double r = 128 ); -/** @brief Applies a binary blob thinning operation, to achieve a skeletization of the input image. +/** @brief Performs binary image thinning to obtain a skeletonized representation of the input image. -The function transforms a binary blob image into a skeletized form using the technique of Zhang-Suen. +This function applies a thinning algorithm, reducing the binary blobs in the input image to a skeletal form. +By default, it uses the Zhang-Suen technique, which iteratively removes pixels from the boundaries of the blobs +while preserving the overall structure and connectivity of the objects. + +@param src Source image: an 8-bit, single-channel binary image where the blobs are represented by pixels with a value of 255 (white), +and the background is 0 (black). +@param dst Destination image of the same size and type as src, where the result of the thinning operation will be stored. +This operation can be performed in-place, meaning `src` and `dst` can be the same. +@param thinningType The thinning algorithm to apply. By default, the Zhang-Suen algorithm is used. See cv::ximgproc::ThinningTypes for other options. +*/ +CV_EXPORTS_W void thinning(InputArray src, OutputArray dst, int thinningType = THINNING_ZHANGSUEN); -@param src Source 8-bit single-channel image, containing binary blobs, with blobs having 255 pixel values. -@param dst Destination image of the same size and the same type as src. The function can work in-place. -@param thinningType Value that defines which thinning algorithm should be used. See cv::ximgproc::ThinningTypes - */ -CV_EXPORTS_W void thinning( InputArray src, OutputArray dst, int thinningType = THINNING_ZHANGSUEN); /** @brief Performs anisotropic diffusion on an image. diff --git a/modules/ximgproc/src/thinning.cpp b/modules/ximgproc/src/thinning.cpp index abd71e76e2..752112903d 100644 --- a/modules/ximgproc/src/thinning.cpp +++ b/modules/ximgproc/src/thinning.cpp @@ -95,32 +95,32 @@ static uint8_t lut_guo_iter1[] = { static void thinningIteration(Mat &img, Mat &marker, const uint8_t* const lut) { int rows = img.rows; int cols = img.cols; - marker.col(0).setTo(1); - marker.col(cols - 1).setTo(1); - marker.row(0).setTo(1); - marker.row(rows - 1).setTo(1); - marker.forEach([=](uchar& value, const int postion[]) { - int i = postion[0]; - int j = postion[1]; - if (i == 0 || j == 0 || i == rows - 1 || j == cols - 1) { return; } + // Parallelized iteration over pixels excluding the boundary + parallel_for_(Range(1, rows - 1), [&](const Range& range) { + for (int i = range.start; i < range.end; i++) { + uchar* imgRow = img.ptr(i); + uchar* markerRow = marker.ptr(i); + for (int j = 1; j < cols - 1; j++) { + if (imgRow[j]) { + uchar p2 = imgRow[j - cols] != 0; + uchar p3 = imgRow[j - cols + 1] != 0; + uchar p4 = imgRow[j + 1] != 0; + uchar p5 = imgRow[j + cols + 1] != 0; + uchar p6 = imgRow[j + cols] != 0; + uchar p7 = imgRow[j + cols - 1] != 0; + uchar p8 = imgRow[j - 1] != 0; + uchar p9 = imgRow[j - cols - 1] != 0; - auto ptr = img.ptr(i, j); // p1 - uchar p2 = ptr[-cols]; - uchar p3 = ptr[-cols + 1]; - uchar p4 = ptr[1]; - uchar p5 = ptr[cols + 1]; - uchar p6 = ptr[cols]; - uchar p7 = ptr[cols - 1]; - uchar p8 = ptr[-1]; - uchar p9 = ptr[-cols - 1]; - - int neighbors = p9 | (p2 << 1) | (p3 << 2) | (p4 << 3) | (p5 << 4) | (p6 << 5) | (p7 << 6) | (p8 << 7); - value = lut[neighbors]; + int neighbors = p9 | (p2 << 1) | (p3 << 2) | (p4 << 3) | (p5 << 4) | (p6 << 5) | (p7 << 6) | (p8 << 7); + markerRow[j] = lut[neighbors]; + } + } + } }); + // Bitwise AND and reset marker for the next iteration img &= marker; - marker.setTo(0); } // Apply the thinning procedure to a given image @@ -130,7 +130,10 @@ void thinning(InputArray input, OutputArray output, int thinningType){ // Enforce the range of the input image to be in between 0 - 255 processed /= 255; Mat prev = processed.clone(); - Mat marker = Mat::zeros(processed.size(), CV_8UC1); + + Mat marker,marker_inner = processed(Rect(1, 1, processed.cols - 2, processed.rows - 2)); + copyMakeBorder(marker_inner, marker, 1, 1, 1, 1, BORDER_ISOLATED | BORDER_CONSTANT, Scalar(255)); + const auto lutIter0 = (thinningType == THINNING_GUOHALL) ? lut_guo_iter0 : lut_zhang_iter0; const auto lutIter1 = (thinningType == THINNING_GUOHALL) ? lut_guo_iter1 : lut_zhang_iter1; do { diff --git a/modules/ximgproc/test/test_thinning.cpp b/modules/ximgproc/test/test_thinning.cpp index 066b7d67e2..e3b523b538 100644 --- a/modules/ximgproc/test/test_thinning.cpp +++ b/modules/ximgproc/test/test_thinning.cpp @@ -17,7 +17,8 @@ TEST(ximgproc_Thinning, simple_ZHANGSUEN) check_img = imread(dir + "cv/ximgproc/results/Thinning_ZHANGSUEN.png", IMREAD_GRAYSCALE); EXPECT_EQ(0, cvtest::norm(check_img, dst, NORM_INF)); - thinning(~src, dst, THINNING_ZHANGSUEN); + dst = ~src; + thinning(dst, dst, THINNING_ZHANGSUEN); check_img = imread(dir + "cv/ximgproc/results/Thinning_inv_ZHANGSUEN.png", IMREAD_GRAYSCALE); EXPECT_EQ(0, cvtest::norm(check_img, dst, NORM_INF)); @@ -34,7 +35,8 @@ TEST(ximgproc_Thinning, simple_GUOHALL) check_img = imread(dir + "cv/ximgproc/results/Thinning_GUOHALL.png", IMREAD_GRAYSCALE); EXPECT_EQ(0, cvtest::norm(check_img, dst, NORM_INF)); - thinning(~src, dst, THINNING_GUOHALL); + dst = ~src; + thinning(dst, dst, THINNING_GUOHALL); check_img = imread(dir + "cv/ximgproc/results/Thinning_inv_GUOHALL.png", IMREAD_GRAYSCALE); EXPECT_EQ(0, cvtest::norm(check_img, dst, NORM_INF));