    // Copyright (C) 2011  Davis E. King (davis@dlib.net)
    // License: Boost Software License   See LICENSE.txt for the full license.
    #undef DLIB_LABEL_CONNeCTED_BLOBS_ABSTRACT_H_
    #ifdef DLIB_LABEL_CONNeCTED_BLOBS_ABSTRACT_H_

    #include "../geometry.h"
    #include <vector>

    namespace dlib
    {

    // ----------------------------------------------------------------------------------------

        struct neighbors_8
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This object is a pixel neighborhood generating functor for
                    use with the label_connected_blobs() routine defined below.
            !*/

            void operator() (
                const point& p,
                std::vector<point>& neighbors
            ) const;
            /*!
                ensures
                    - adds the 8 neighboring pixels surrounding p into neighbors
            !*/
        };

        struct neighbors_4
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This object is a pixel neighborhood generating functor for
                    use with the label_connected_blobs() routine defined below.
            !*/

            void operator() (
                const point& p,
                std::vector<point>& neighbors
            ) const;
            /*!
                ensures
                    - adds the 4 neighboring pixels of p into neighbors.  These
                      are the ones immediately to the left, top, right, and bottom.
            !*/
        };

    // ----------------------------------------------------------------------------------------

        struct connected_if_both_not_zero
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This object is a pixel connection testing functor for use
                    with the label_connected_blobs() routine defined below.
            !*/

            template <typename image_type>
            bool operator() (
                const image_type& img,
                const point& a,
                const point& b
            ) const
            {
                return (img[a.y()][a.x()] != 0 && img[b.y()][b.x()] != 0);
            }
        };

        struct connected_if_equal
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This object is a pixel connection testing functor for use
                    with the label_connected_blobs() routine defined below.
            !*/

            template <typename image_type>
            bool operator() (
                const image_type& img,
                const point& a,
                const point& b
            ) const
            {
                return (img[a.y()][a.x()] == img[b.y()][b.x()]);
            }
        };

    // ----------------------------------------------------------------------------------------

        struct zero_pixels_are_background
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This object is a background testing functor for use
                    with the label_connected_blobs() routine defined below.
            !*/

            template <typename image_type>
            bool operator() (
                const image_type& img,
                const point& p
            ) const
            {
                return img[p.y()][p.x()] == 0;
            }

        };

        struct nothing_is_background
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This object is a background testing functor for use
                    with the label_connected_blobs() routine defined below.
            !*/

            template <typename image_type>
            bool operator() (
                const image_type&,
                const point&
            ) const
            {
                return false;
            }

        };

    // ----------------------------------------------------------------------------------------

        template <
            typename image_type,
            typename label_image_type,
            typename background_functor_type,
            typename neighbors_functor_type,
            typename connected_functor_type
            >
        unsigned long label_connected_blobs (
            const image_type& img,
            const background_functor_type& is_background,
            const neighbors_functor_type&  get_neighbors,
            const connected_functor_type&  is_connected,
            label_image_type& label_img
        );
        /*!
            requires
                - image_type       == is an implementation of array2d/array2d_kernel_abstract.h
                - label_image_type == is an implementation of array2d/array2d_kernel_abstract.h
                  and it must contain integers.
                - is_background(img, point(c,r)) is a legal expression that evaluates to a bool.
                - is_connected(img, point(c,r), point(c2,r2)) is a legal expression that
                  evaluates to a bool.
                - get_neighbors(point(c,r), neighbors) is a legal expression where neighbors
                  is of type std::vector<point>.
                - is_same_object(img, label_img) == false
            ensures
                - This function labels each of the connected blobs in img with a unique integer
                  label.
                - An image can be thought of as a graph where pixels A and B are connected if
                  and only if the following two statements are satisfied:
                    - is_connected(img,A,B) == true
                    - get_neighbors(A, neighbors) results in neighbors containing B or
                      get_neighbors(B, neighbors) results in neighbors containing A.
                  Then this function can be understood as labeling all the connected components
                  of this pixel graph such that all pixels in a component get the same label while
                  pixels in different components get different labels.  Note that there is a
                  special "background" component determined by is_background().  Any pixels which
                  are "background" always get a blob id of 0 regardless of any other considerations.
                - #label_img.nr() == img.nr()
                - #label_img.nc() == img.nc()
                - for all valid r and c:
                    - #label_img[r][c] == the blob label number for pixel img[r][c].
                    - #label_img[r][c] >= 0
                    - if (is_background(img, point(c,r))) then
                        - #label_img[r][c] == 0
                    - else
                        - #label_img[r][c] != 0
                - if (img.size() != 0) then
                    - returns max(mat(#label_img))+1
                      (i.e. returns a number one greater than the maximum blob id number,
                      this is the number of blobs found.)
                - else
                    - returns 0
                - blob labels are contiguous, therefore, the number returned by this function is
                  the number of blobs in the image (including the background blob).
                - It is guaranteed that is_connected() and is_background() will never be
                  called with points outside the image.
        !*/

    // ----------------------------------------------------------------------------------------

    }

    #endif // DLIB_LABEL_CONNeCTED_BLOBS_ABSTRACT_H_