// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_LABEL_CONNeCTED_BLOBS_H_
#define DLIB_LABEL_CONNeCTED_BLOBS_H_
#include "label_connected_blobs_abstract.h"
#include "../geometry.h"
#include <stack>
#include <vector>
namespace dlib
{
// ----------------------------------------------------------------------------------------
struct neighbors_8
{
void operator() (
const point& p,
std::vector<point>& neighbors
) const
{
neighbors.push_back(point(p.x()+1,p.y()+1));
neighbors.push_back(point(p.x()+1,p.y() ));
neighbors.push_back(point(p.x()+1,p.y()-1));
neighbors.push_back(point(p.x(),p.y()+1));
neighbors.push_back(point(p.x(),p.y()-1));
neighbors.push_back(point(p.x()-1,p.y()+1));
neighbors.push_back(point(p.x()-1,p.y() ));
neighbors.push_back(point(p.x()-1,p.y()-1));
}
};
struct neighbors_4
{
void operator() (
const point& p,
std::vector<point>& neighbors
) const
{
neighbors.push_back(point(p.x()+1,p.y()));
neighbors.push_back(point(p.x()-1,p.y()));
neighbors.push_back(point(p.x(),p.y()+1));
neighbors.push_back(point(p.x(),p.y()-1));
}
};
// ----------------------------------------------------------------------------------------
struct connected_if_both_not_zero
{
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
{
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
{
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
{
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_
)
{
// make sure requires clause is not broken
DLIB_ASSERT(is_same_object(img_, label_img_) == false,
"\t unsigned long label_connected_blobs()"
<< "\n\t The input image and output label image can't be the same object."
);
const_image_view<image_type> img(img_);
image_view<label_image_type> label_img(label_img_);
std::stack<point> neighbors;
label_img.set_size(img.nr(), img.nc());
assign_all_pixels(label_img, 0);
unsigned long next = 1;
if (img.size() == 0)
return 0;
const rectangle area = get_rect(img);
std::vector<point> window;
for (long r = 0; r < img.nr(); ++r)
{
for (long c = 0; c < img.nc(); ++c)
{
// skip already labeled pixels or background pixels
if (label_img[r][c] != 0 || is_background(img,point(c,r)))
continue;
label_img[r][c] = next;
// label all the neighbors of this point
neighbors.push(point(c,r));
while (neighbors.size() > 0)
{
const point p = neighbors.top();
neighbors.pop();
window.clear();
get_neighbors(p, window);
for (unsigned long i = 0; i < window.size(); ++i)
{
if (area.contains(window[i]) && // point in image.
!is_background(img,window[i]) && // isn't background.
label_img[window[i].y()][window[i].x()] == 0 && // haven't already labeled it.
is_connected(img, p, window[i])) // it's connected.
{
label_img[window[i].y()][window[i].x()] = next;
neighbors.push(window[i]);
}
}
}
++next;
}
}
return next;
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_LABEL_CONNeCTED_BLOBS_H_