// 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_