summaryrefslogtreecommitdiffstats
path: root/ml/dlib/dlib/image_transforms/morphological_operations.h
diff options
context:
space:
mode:
Diffstat (limited to 'ml/dlib/dlib/image_transforms/morphological_operations.h')
-rw-r--r--ml/dlib/dlib/image_transforms/morphological_operations.h846
1 files changed, 0 insertions, 846 deletions
diff --git a/ml/dlib/dlib/image_transforms/morphological_operations.h b/ml/dlib/dlib/image_transforms/morphological_operations.h
deleted file mode 100644
index a659e4bdc..000000000
--- a/ml/dlib/dlib/image_transforms/morphological_operations.h
+++ /dev/null
@@ -1,846 +0,0 @@
-// Copyright (C) 2006 Davis E. King (davis@dlib.net)
-// License: Boost Software License See LICENSE.txt for the full license.
-#ifndef DLIB_MORPHOLOGICAL_OPERATIONs_
-#define DLIB_MORPHOLOGICAL_OPERATIONs_
-
-#include "../pixel.h"
-#include "thresholding.h"
-#include "morphological_operations_abstract.h"
-#include "assign_image.h"
-
-namespace dlib
-{
-
-// ----------------------------------------------------------------------------------------
-
- namespace morphological_operations_helpers
- {
- template <typename image_type>
- bool is_binary_image (
- const image_type& img_
- )
- /*!
- ensures
- - returns true if img_ contains only on_pixel and off_pixel values.
- - returns false otherwise
- !*/
- {
- const_image_view<image_type> img(img_);
- for (long r = 0; r < img.nr(); ++r)
- {
- for (long c = 0; c < img.nc(); ++c)
- {
- if (img[r][c] != on_pixel && img[r][c] != off_pixel)
- {
- return false;
- }
- }
- }
- return true;
- }
-
- template <
- long M,
- long N
- >
- bool is_binary_image (
- const unsigned char (&structuring_element)[M][N]
- )
- /*!
- ensures
- - returns true if structuring_element contains only on_pixel and off_pixel values.
- - returns false otherwise
- !*/
- {
- for (long m = 0; m < M; ++m)
- {
- for (long n = 0; n < N; ++n)
- {
- if (structuring_element[m][n] != on_pixel &&
- structuring_element[m][n] != off_pixel)
- {
- return false;
- }
- }
- }
- return true;
- }
-
- }
-
-// ----------------------------------------------------------------------------------------
-
- template <
- typename in_image_type,
- typename out_image_type,
- long M,
- long N
- >
- void binary_dilation (
- const in_image_type& in_img_,
- out_image_type& out_img_,
- const unsigned char (&structuring_element)[M][N]
- )
- {
- typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
- typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
- COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );
- COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );
-
- using namespace morphological_operations_helpers;
- COMPILE_TIME_ASSERT(M%2 == 1);
- COMPILE_TIME_ASSERT(N%2 == 1);
- DLIB_ASSERT(is_same_object(in_img_,out_img_) == false,
- "\tvoid binary_dilation()"
- << "\n\tYou must give two different image objects"
- );
- COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type>::grayscale);
- DLIB_ASSERT(is_binary_image(in_img_) ,
- "\tvoid binary_dilation()"
- << "\n\tin_img must be a binary image"
- );
- DLIB_ASSERT(is_binary_image(structuring_element) ,
- "\tvoid binary_dilation()"
- << "\n\tthe structuring_element must be a binary image"
- );
-
-
- const_image_view<in_image_type> in_img(in_img_);
- image_view<out_image_type> out_img(out_img_);
-
- // if there isn't any input image then don't do anything
- if (in_img.size() == 0)
- {
- out_img.clear();
- return;
- }
-
- out_img.set_size(in_img.nr(),in_img.nc());
-
- // apply the filter to the image
- for (long r = 0; r < in_img.nr(); ++r)
- {
- for (long c = 0; c < in_img.nc(); ++c)
- {
- unsigned char out_pixel = off_pixel;
- for (long m = 0; m < M && out_pixel == off_pixel; ++m)
- {
- for (long n = 0; n < N && out_pixel == off_pixel; ++n)
- {
- if (structuring_element[m][n] == on_pixel)
- {
- // if this pixel is inside the image then get it from the image
- // but if it isn't just pretend it was an off_pixel value
- if (r+m >= M/2 && c+n >= N/2 &&
- r+m-M/2 < in_img.nr() && c+n-N/2 < in_img.nc())
- {
- out_pixel = in_img[r+m-M/2][c+n-N/2];
- }
- }
- }
- }
- assign_pixel(out_img[r][c], out_pixel);
- }
- }
- }
-
-// ----------------------------------------------------------------------------------------
-
- template <
- typename in_image_type,
- typename out_image_type,
- long M,
- long N
- >
- void binary_erosion (
- const in_image_type& in_img_,
- out_image_type& out_img_,
- const unsigned char (&structuring_element)[M][N]
- )
- {
- typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
- typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
- COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );
- COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );
-
- using namespace morphological_operations_helpers;
- COMPILE_TIME_ASSERT(M%2 == 1);
- COMPILE_TIME_ASSERT(N%2 == 1);
- DLIB_ASSERT(is_same_object(in_img_,out_img_) == false,
- "\tvoid binary_erosion()"
- << "\n\tYou must give two different image objects"
- );
- COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type>::grayscale);
- DLIB_ASSERT(is_binary_image(in_img_) ,
- "\tvoid binary_erosion()"
- << "\n\tin_img must be a binary image"
- );
- DLIB_ASSERT(is_binary_image(structuring_element) ,
- "\tvoid binary_erosion()"
- << "\n\tthe structuring_element must be a binary image"
- );
-
- const_image_view<in_image_type> in_img(in_img_);
- image_view<out_image_type> out_img(out_img_);
-
-
- // if there isn't any input image then don't do anything
- if (in_img.size() == 0)
- {
- out_img.clear();
- return;
- }
-
- out_img.set_size(in_img.nr(),in_img.nc());
-
- // apply the filter to the image
- for (long r = 0; r < in_img.nr(); ++r)
- {
- for (long c = 0; c < in_img.nc(); ++c)
- {
- unsigned char out_pixel = on_pixel;
- for (long m = 0; m < M && out_pixel == on_pixel; ++m)
- {
- for (long n = 0; n < N && out_pixel == on_pixel; ++n)
- {
- if (structuring_element[m][n] == on_pixel)
- {
- // if this pixel is inside the image then get it from the image
- // but if it isn't just pretend it was an off_pixel value
- if (r+m >= M/2 && c+n >= N/2 &&
- r+m-M/2 < in_img.nr() && c+n-N/2 < in_img.nc())
- {
- out_pixel = in_img[r+m-M/2][c+n-N/2];
- }
- else
- {
- out_pixel = off_pixel;
- }
- }
- }
- }
- assign_pixel(out_img[r][c], out_pixel);
- }
- }
- }
-
-// ----------------------------------------------------------------------------------------
-
- template <
- typename in_image_type,
- typename out_image_type,
- long M,
- long N
- >
- void binary_open (
- const in_image_type& in_img,
- out_image_type& out_img,
- const unsigned char (&structuring_element)[M][N],
- const unsigned long iter = 1
- )
- {
- typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
- typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
- COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );
- COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );
-
- using namespace morphological_operations_helpers;
- COMPILE_TIME_ASSERT(M%2 == 1);
- COMPILE_TIME_ASSERT(N%2 == 1);
- DLIB_ASSERT(is_same_object(in_img,out_img) == false,
- "\tvoid binary_open()"
- << "\n\tYou must give two different image objects"
- );
- COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type>::grayscale);
- DLIB_ASSERT(is_binary_image(in_img) ,
- "\tvoid binary_open()"
- << "\n\tin_img must be a binary image"
- );
- DLIB_ASSERT(is_binary_image(structuring_element) ,
- "\tvoid binary_open()"
- << "\n\tthe structuring_element must be a binary image"
- );
-
-
- // if there isn't any input image then don't do anything
- if (num_rows(in_img)*num_columns(in_img) == 0)
- {
- set_image_size(out_img, 0,0);
- return;
- }
-
- set_image_size(out_img, num_rows(in_img), num_columns(in_img));
-
- if (iter == 0)
- {
- // just copy the image over
- assign_image(out_img, in_img);
- }
- else if (iter == 1)
- {
- in_image_type temp;
- binary_erosion(in_img,temp,structuring_element);
- binary_dilation(temp,out_img,structuring_element);
- }
- else
- {
- in_image_type temp1, temp2;
- binary_erosion(in_img,temp1,structuring_element);
-
- // do the extra erosions
- for (unsigned long i = 1; i < iter; ++i)
- {
- swap(temp1, temp2);
- binary_erosion(temp2,temp1,structuring_element);
- }
-
- // do the extra dilations
- for (unsigned long i = 1; i < iter; ++i)
- {
- swap(temp1, temp2);
- binary_dilation(temp2,temp1,structuring_element);
- }
-
- binary_dilation(temp1,out_img,structuring_element);
- }
- }
-
-// ----------------------------------------------------------------------------------------
-
- template <
- typename in_image_type,
- typename out_image_type,
- long M,
- long N
- >
- void binary_close (
- const in_image_type& in_img,
- out_image_type& out_img,
- const unsigned char (&structuring_element)[M][N],
- const unsigned long iter = 1
- )
- {
- typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
- typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
- COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );
- COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );
-
-
- using namespace morphological_operations_helpers;
- COMPILE_TIME_ASSERT(M%2 == 1);
- COMPILE_TIME_ASSERT(N%2 == 1);
- DLIB_ASSERT(is_same_object(in_img,out_img) == false,
- "\tvoid binary_close()"
- << "\n\tYou must give two different image objects"
- );
- COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type>::grayscale);
- DLIB_ASSERT(is_binary_image(in_img) ,
- "\tvoid binary_close()"
- << "\n\tin_img must be a binary image"
- );
- DLIB_ASSERT(is_binary_image(structuring_element) ,
- "\tvoid binary_close()"
- << "\n\tthe structuring_element must be a binary image"
- );
-
-
- // if there isn't any input image then don't do anything
- if (num_rows(in_img)*num_columns(in_img) == 0)
- {
- set_image_size(out_img, 0,0);
- return;
- }
-
- set_image_size(out_img, num_rows(in_img), num_columns(in_img));
-
- if (iter == 0)
- {
- // just copy the image over
- assign_image(out_img, in_img);
- }
- else if (iter == 1)
- {
- in_image_type temp;
- binary_dilation(in_img,temp,structuring_element);
- binary_erosion(temp,out_img,structuring_element);
- }
- else
- {
- in_image_type temp1, temp2;
- binary_dilation(in_img,temp1,structuring_element);
-
- // do the extra dilations
- for (unsigned long i = 1; i < iter; ++i)
- {
- swap(temp1, temp2);
- binary_dilation(temp2,temp1,structuring_element);
- }
-
- // do the extra erosions
- for (unsigned long i = 1; i < iter; ++i)
- {
- swap(temp1, temp2);
- binary_erosion(temp2,temp1,structuring_element);
- }
-
- binary_erosion(temp1,out_img,structuring_element);
- }
- }
-
-// ----------------------------------------------------------------------------------------
-
- template <
- typename in_image_type1,
- typename in_image_type2,
- typename out_image_type
- >
- void binary_intersection (
- const in_image_type1& in_img1_,
- const in_image_type2& in_img2_,
- out_image_type& out_img_
- )
- {
- typedef typename image_traits<in_image_type1>::pixel_type in_pixel_type1;
- typedef typename image_traits<in_image_type2>::pixel_type in_pixel_type2;
- typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
- COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type1>::has_alpha == false );
- COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type2>::has_alpha == false );
- COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );
-
- using namespace morphological_operations_helpers;
- COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type1>::grayscale);
- COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type2>::grayscale);
- DLIB_ASSERT(is_binary_image(in_img1_) ,
- "\tvoid binary_intersection()"
- << "\n\tin_img1 must be a binary image"
- );
- DLIB_ASSERT(is_binary_image(in_img2_) ,
- "\tvoid binary_intersection()"
- << "\n\tin_img2 must be a binary image"
- );
-
- const_image_view<in_image_type1> in_img1(in_img1_);
- const_image_view<in_image_type2> in_img2(in_img2_);
- image_view<out_image_type> out_img(out_img_);
-
- DLIB_ASSERT(in_img1.nc() == in_img2.nc(),
- "\tvoid binary_intersection()"
- << "\n\tin_img1 and in_img2 must have the same ncs."
- << "\n\tin_img1.nc(): " << in_img1.nc()
- << "\n\tin_img2.nc(): " << in_img2.nc()
- );
- DLIB_ASSERT(in_img1.nr() == in_img2.nr(),
- "\tvoid binary_intersection()"
- << "\n\tin_img1 and in_img2 must have the same nrs."
- << "\n\tin_img1.nr(): " << in_img1.nr()
- << "\n\tin_img2.nr(): " << in_img2.nr()
- );
-
-
-
- // if there isn't any input image then don't do anything
- if (in_img1.size() == 0)
- {
- out_img.clear();
- return;
- }
-
- out_img.set_size(in_img1.nr(),in_img1.nc());
-
- for (long r = 0; r < in_img1.nr(); ++r)
- {
- for (long c = 0; c < in_img1.nc(); ++c)
- {
- if (in_img1[r][c] == on_pixel && in_img2[r][c] == on_pixel)
- assign_pixel(out_img[r][c], on_pixel);
- else
- assign_pixel(out_img[r][c], off_pixel);
- }
- }
- }
-
-// ----------------------------------------------------------------------------------------
-
- template <
- typename in_image_type1,
- typename in_image_type2,
- typename out_image_type
- >
- void binary_union (
- const in_image_type1& in_img1_,
- const in_image_type2& in_img2_,
- out_image_type& out_img_
- )
- {
- typedef typename image_traits<in_image_type1>::pixel_type in_pixel_type1;
- typedef typename image_traits<in_image_type2>::pixel_type in_pixel_type2;
- typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
- COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type1>::has_alpha == false );
- COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type2>::has_alpha == false );
- COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );
-
-
- using namespace morphological_operations_helpers;
- COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type1>::grayscale);
- COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type2>::grayscale);
- DLIB_ASSERT(is_binary_image(in_img1_) ,
- "\tvoid binary_intersection()"
- << "\n\tin_img1 must be a binary image"
- );
- DLIB_ASSERT(is_binary_image(in_img2_) ,
- "\tvoid binary_intersection()"
- << "\n\tin_img2 must be a binary image"
- );
-
- const_image_view<in_image_type1> in_img1(in_img1_);
- const_image_view<in_image_type2> in_img2(in_img2_);
- image_view<out_image_type> out_img(out_img_);
-
- DLIB_ASSERT(in_img1.nc() == in_img2.nc(),
- "\tvoid binary_intersection()"
- << "\n\tin_img1 and in_img2 must have the same ncs."
- << "\n\tin_img1.nc(): " << in_img1.nc()
- << "\n\tin_img2.nc(): " << in_img2.nc()
- );
- DLIB_ASSERT(in_img1.nr() == in_img2.nr(),
- "\tvoid binary_intersection()"
- << "\n\tin_img1 and in_img2 must have the same nrs."
- << "\n\tin_img1.nr(): " << in_img1.nr()
- << "\n\tin_img2.nr(): " << in_img2.nr()
- );
-
-
-
- // if there isn't any input image then don't do anything
- if (in_img1.size() == 0)
- {
- out_img.clear();
- return;
- }
-
- out_img.set_size(in_img1.nr(),in_img1.nc());
-
- for (long r = 0; r < in_img1.nr(); ++r)
- {
- for (long c = 0; c < in_img1.nc(); ++c)
- {
- if (in_img1[r][c] == on_pixel || in_img2[r][c] == on_pixel)
- assign_pixel(out_img[r][c], on_pixel);
- else
- assign_pixel(out_img[r][c], off_pixel);
- }
- }
- }
-
-// ----------------------------------------------------------------------------------------
-
- template <
- typename in_image_type1,
- typename in_image_type2,
- typename out_image_type
- >
- void binary_difference (
- const in_image_type1& in_img1_,
- const in_image_type2& in_img2_,
- out_image_type& out_img_
- )
- {
- typedef typename image_traits<in_image_type1>::pixel_type in_pixel_type1;
- typedef typename image_traits<in_image_type2>::pixel_type in_pixel_type2;
- typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
- COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type1>::has_alpha == false );
- COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type2>::has_alpha == false );
- COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );
-
- using namespace morphological_operations_helpers;
- COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type1>::grayscale);
- COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type2>::grayscale);
- DLIB_ASSERT(is_binary_image(in_img1_) ,
- "\tvoid binary_difference()"
- << "\n\tin_img1 must be a binary image"
- );
- DLIB_ASSERT(is_binary_image(in_img2_) ,
- "\tvoid binary_difference()"
- << "\n\tin_img2 must be a binary image"
- );
-
- const_image_view<in_image_type1> in_img1(in_img1_);
- const_image_view<in_image_type2> in_img2(in_img2_);
- image_view<out_image_type> out_img(out_img_);
-
- DLIB_ASSERT(in_img1.nc() == in_img2.nc(),
- "\tvoid binary_difference()"
- << "\n\tin_img1 and in_img2 must have the same ncs."
- << "\n\tin_img1.nc(): " << in_img1.nc()
- << "\n\tin_img2.nc(): " << in_img2.nc()
- );
- DLIB_ASSERT(in_img1.nr() == in_img2.nr(),
- "\tvoid binary_difference()"
- << "\n\tin_img1 and in_img2 must have the same nrs."
- << "\n\tin_img1.nr(): " << in_img1.nr()
- << "\n\tin_img2.nr(): " << in_img2.nr()
- );
-
-
-
- // if there isn't any input image then don't do anything
- if (in_img1.size() == 0)
- {
- out_img.clear();
- return;
- }
-
- out_img.set_size(in_img1.nr(),in_img1.nc());
-
- for (long r = 0; r < in_img1.nr(); ++r)
- {
- for (long c = 0; c < in_img1.nc(); ++c)
- {
- if (in_img1[r][c] == on_pixel && in_img2[r][c] == off_pixel)
- assign_pixel(out_img[r][c], on_pixel);
- else
- assign_pixel(out_img[r][c], off_pixel);
- }
- }
- }
-
-// ----------------------------------------------------------------------------------------
-
- template <
- typename in_image_type,
- typename out_image_type
- >
- void binary_complement (
- const in_image_type& in_img_,
- out_image_type& out_img_
- )
- {
- typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
- typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
- COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );
- COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );
-
-
- using namespace morphological_operations_helpers;
- COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type>::grayscale);
- DLIB_ASSERT(is_binary_image(in_img_) ,
- "\tvoid binary_complement()"
- << "\n\tin_img must be a binary image"
- );
-
- const_image_view<in_image_type> in_img(in_img_);
- image_view<out_image_type> out_img(out_img_);
-
- // if there isn't any input image then don't do anything
- if (in_img.size() == 0)
- {
- out_img.clear();
- return;
- }
-
- out_img.set_size(in_img.nr(),in_img.nc());
-
- for (long r = 0; r < in_img.nr(); ++r)
- {
- for (long c = 0; c < in_img.nc(); ++c)
- {
- if (in_img[r][c] == on_pixel)
- assign_pixel(out_img[r][c], off_pixel);
- else
- assign_pixel(out_img[r][c], on_pixel);
- }
- }
- }
-
- template <
- typename image_type
- >
- void binary_complement (
- image_type& img
- )
- {
- binary_complement(img,img);
- }
-
-// ----------------------------------------------------------------------------------------
-// ----------------------------------------------------------------------------------------
-
- namespace impl
- {
- template <typename image_type>
- inline bool should_remove_pixel (
- const image_type& img,
- long r,
- long c,
- int iter
- )
- {
- unsigned int p2 = img[r-1][c];
- unsigned int p3 = img[r-1][c+1];
- unsigned int p4 = img[r][c+1];
- unsigned int p5 = img[r+1][c+1];
- unsigned int p6 = img[r+1][c];
- unsigned int p7 = img[r+1][c-1];
- unsigned int p8 = img[r][c-1];
- unsigned int p9 = img[r-1][c-1];
-
- int A = (p2 == 0 && p3 == 255) + (p3 == 0 && p4 == 255) +
- (p4 == 0 && p5 == 255) + (p5 == 0 && p6 == 255) +
- (p6 == 0 && p7 == 255) + (p7 == 0 && p8 == 255) +
- (p8 == 0 && p9 == 255) + (p9 == 0 && p2 == 255);
- 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);
- // Decide if we should remove the pixel img[r][c].
- return (A == 1 && (B >= 2*255 && B <= 6*255) && m1 == 0 && m2 == 0);
- }
-
- template <typename image_type>
- inline void add_to_remove (
- std::vector<point>& to_remove,
- array2d<unsigned char>& marker,
- const image_type& img,
- long r,
- long c,
- int iter
- )
- {
- if (marker[r][c]&&should_remove_pixel(img,r,c,iter))
- {
- to_remove.push_back(point(c,r));
- marker[r][c] = 0;
- }
- }
-
- template <typename image_type>
- inline bool is_bw_border_pixel(
- const image_type& img,
- long r,
- long c
- )
- {
- unsigned int p2 = img[r-1][c];
- unsigned int p3 = img[r-1][c+1];
- unsigned int p4 = img[r][c+1];
- unsigned int p5 = img[r+1][c+1];
- unsigned int p6 = img[r+1][c];
- unsigned int p7 = img[r+1][c-1];
- unsigned int p8 = img[r][c-1];
- unsigned int p9 = img[r-1][c-1];
-
- int B = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
- // If you are on but at least one of your neighbors isn't.
- return B<8*255 && img[r][c];
-
- }
-
- inline void add_if(
- std::vector<point>& to_check2,
- const array2d<unsigned char>& marker,
- long c,
- long r
- )
- {
- if (marker[r][c])
- to_check2.push_back(point(c,r));
- }
-
- } // end namespace impl
-
-// ----------------------------------------------------------------------------------------
-
- template <
- typename image_type
- >
- void skeleton(
- image_type& img_
- )
- {
- /*
- The implementation of this function is based on the paper
- "A fast parallel algorithm for thinning digital patterns” by T.Y. Zhang and C.Y. Suen.
- and also the excellent discussion of it at:
- http://opencv-code.com/quick-tips/implementation-of-thinning-algorithm-in-opencv/
- */
-
- typedef typename image_traits<image_type>::pixel_type pixel_type;
-
- // This function only works on grayscale images
- COMPILE_TIME_ASSERT(pixel_traits<pixel_type>::grayscale);
-
- using namespace impl;
- // Note that it's important to zero the border for 2 reasons. First, it allows
- // thinning to being at the border of the image. But more importantly, it causes
- // the mask to have a border of 0 pixels as well which we use later to avoid
- // indexing outside the image inside add_to_remove().
- zero_border_pixels(img_,1,1);
- image_view<image_type> img(img_);
-
- // We use the marker to keep track of pixels we have committed to removing but
- // haven't yet removed from img.
- array2d<unsigned char> marker(img.nr(), img.nc());
- assign_image(marker, img);
-
-
- // Begin by making a list of the pixels on the borders of binary blobs.
- std::vector<point> to_remove, to_check, to_check2;
- for (int r = 1; r < img.nr()-1; r++)
- {
- for (int c = 1; c < img.nc()-1; c++)
- {
- if (is_bw_border_pixel(img, r, c))
- {
- to_check.push_back(point(c,r));
- }
- }
- }
-
- // Now start iteratively looking at the border pixels and removing them.
- while(to_check.size() != 0)
- {
- for (int iter = 0; iter <= 1; ++iter)
- {
- // Check which pixels we should remove
- to_remove.clear();
- for (unsigned long i = 0; i < to_check.size(); ++i)
- {
- long r = to_check[i].y();
- long c = to_check[i].x();
- add_to_remove(to_remove, marker, img, r, c, iter);
- }
- for (unsigned long i = 0; i < to_check2.size(); ++i)
- {
- long r = to_check2[i].y();
- long c = to_check2[i].x();
- add_to_remove(to_remove, marker, img, r, c, iter);
- }
- // Now remove those pixels. Also add their neighbors into the "to check"
- // pixel list for the next iteration.
- for (unsigned long i = 0; i < to_remove.size(); ++i)
- {
- long r = to_remove[i].y();
- long c = to_remove[i].x();
- // remove the pixel
- img[r][c] = 0;
- add_if(to_check2, marker, c-1, r-1);
- add_if(to_check2, marker, c, r-1);
- add_if(to_check2, marker, c+1, r-1);
- add_if(to_check2, marker, c-1, r);
- add_if(to_check2, marker, c+1, r);
- add_if(to_check2, marker, c-1, r+1);
- add_if(to_check2, marker, c, r+1);
- add_if(to_check2, marker, c+1, r+1);
- }
- }
- to_check.clear();
- to_check.swap(to_check2);
- }
- }
-
-// ----------------------------------------------------------------------------------------
-// ----------------------------------------------------------------------------------------
-
-}
-
-#endif // DLIB_MORPHOLOGICAL_OPERATIONs_
-