diff --git a/modules/ximgproc/include/opencv2/ximgproc.hpp b/modules/ximgproc/include/opencv2/ximgproc.hpp index b803ce3ef..256d8c905 100644 --- a/modules/ximgproc/include/opencv2/ximgproc.hpp +++ b/modules/ximgproc/include/opencv2/ximgproc.hpp @@ -104,6 +104,16 @@ CV_EXPORTS_W void niBlackThreshold( InputArray _src, OutputArray _dst, double maxValue, int type, int blockSize, double delta ); +/** @brief Applies a binary blob thinning operation, to achieve a skeletization of the input image. + +The function transforms a binary blob image into a skeletized form using the technique of Zhang-Suen. + +@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. + */ +CV_EXPORTS_W void thinning( InputArray src, OutputArray dst); + + //! @} } diff --git a/modules/ximgproc/src/thinning.cpp b/modules/ximgproc/src/thinning.cpp new file mode 100644 index 000000000..787071637 --- /dev/null +++ b/modules/ximgproc/src/thinning.cpp @@ -0,0 +1,63 @@ +#include "precomp.hpp" + +using namespace std; + +namespace cv { +namespace ximgproc { + +// Applies a thinning iteration to a binary image +static void thinningIteration(Mat img, int iter){ + Mat marker = Mat::zeros(img.size(), CV_8UC1); + for (int i = 1; i < img.rows-1; i++) + { + for (int j = 1; j < img.cols-1; j++) + { + uchar p2 = img.at(i-1, j); + uchar p3 = img.at(i-1, j+1); + uchar p4 = img.at(i, j+1); + uchar p5 = img.at(i+1, j+1); + uchar p6 = img.at(i+1, j); + uchar p7 = img.at(i+1, j-1); + uchar p8 = img.at(i, j-1); + uchar p9 = img.at(i-1, j-1); + + int A = (p2 == 0 && p3 == 1) + (p3 == 0 && p4 == 1) + + (p4 == 0 && p5 == 1) + (p5 == 0 && p6 == 1) + + (p6 == 0 && p7 == 1) + (p7 == 0 && p8 == 1) + + (p8 == 0 && p9 == 1) + (p9 == 0 && p2 == 1); + int B = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9; + int m1 = iter == 0 ? (p2 * p4 * p6) : (p2 * p4 * p8); + int m2 = iter == 0 ? (p4 * p6 * p8) : (p2 * p6 * p8); + + if (A == 1 && (B >= 2 && B <= 6) && m1 == 0 && m2 == 0) + marker.at(i,j) = 1; + } + } + + img &= ~marker; +} + +// Apply the thinning procedure to a given image +void thinning(InputArray input, OutputArray output){ + Mat processed = input.getMat().clone(); + // Enforce the range of the input image to be in between 0 - 255 + processed /= 255; + + Mat prev = Mat::zeros(processed.size(), CV_8UC1); + Mat diff; + + do { + thinningIteration(processed, 0); + thinningIteration(processed, 1); + absdiff(processed, prev, diff); + processed.copyTo(prev); + } + while (countNonZero(diff) > 0); + + processed *= 255; + + output.assign(processed); +} + +} //namespace ximgproc +} //namespace cv