// Copyright (C) 2011 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #undef DLIB_OBJECT_DeTECTOR_ABSTRACT_H__ #ifdef DLIB_OBJECT_DeTECTOR_ABSTRACT_H__ #include "../geometry.h" #include <vector> #include "box_overlap_testing_abstract.h" #include "full_object_detection_abstract.h" namespace dlib { // ---------------------------------------------------------------------------------------- template < typename image_scanner_type > class object_detector { /*! REQUIREMENTS ON image_scanner_type image_scanner_type must be an implementation of dlib/image_processing/scan_image_pyramid_abstract.h or dlib/image_processing/scan_image_boxes_abstract.h WHAT THIS OBJECT REPRESENTS This object is a tool for detecting the positions of objects in an image. In particular, it is a simple container to aggregate an instance of the scan_image_pyramid or scan_image_boxes classes, the weight vector needed by one of these image scanners, and finally an instance of test_box_overlap. The test_box_overlap object is used to perform non-max suppression on the output of the image scanner object. !*/ public: typedef typename image_scanner_type::feature_vector_type feature_vector_type; object_detector ( ); /*! ensures - This detector won't generate any detections when presented with an image. !*/ object_detector ( const object_detector& item ); /*! ensures - #*this is a copy of item - #get_scanner() == item.get_scanner() (note that only the "configuration" of item.get_scanner() is copied. I.e. the copy is done using copy_configuration()) !*/ object_detector ( const image_scanner_type& scanner, const test_box_overlap& overlap_tester, const feature_vector_type& w ); /*! requires - w.size() == scanner.get_num_dimensions() + 1 - scanner.get_num_detection_templates() > 0 ensures - When the operator() member function is called it will invoke scanner.detect(w,dets,w(w.size()-1)), suppress overlapping detections, and then report the results. - when #*this is used to detect objects, the set of output detections will never contain any overlaps with respect to overlap_tester. That is, for all pairs of returned detections A and B, we will always have: overlap_tester(A,B) == false - #get_w() == w - #get_overlap_tester() == overlap_tester - #get_scanner() == scanner (note that only the "configuration" of scanner is copied. I.e. the copy is done using copy_configuration()) !*/ const feature_vector_type& get_w ( ) const; /*! ensures - returns the weight vector used by this object !*/ const test_box_overlap& get_overlap_tester ( ) const; /*! ensures - returns the overlap tester used by this object !*/ const image_scanner_type& get_scanner ( ) const; /*! ensures - returns the image scanner used by this object. !*/ object_detector& operator= ( const object_detector& item ); /*! ensures - #*this is a copy of item - #get_scanner() == item.get_scanner() (note that only the "configuration" of item.get_scanner() is copied. I.e. the copy is done using copy_configuration()) - returns #*this !*/ template < typename image_type > std::vector<rectangle> operator() ( const image_type& img, const adjust_threshold = 0 ); /*! requires - img == an object which can be accepted by image_scanner_type::load() ensures - performs object detection on the given image and returns a vector which indicates the locations of all detected objects. - The returned vector will be sorted in the sense that the highest confidence detections come first. E.g. element 0 is the best detection, element 1 the next best, and so on. - #get_scanner() will have been loaded with img. Therefore, you can call #get_scanner().get_feature_vector() to obtain the feature vectors or #get_scanner().get_full_object_detection() to get the full_object_detections for the resulting object detection boxes. - The detection threshold is adjusted by having adjust_threshold added to it. Therefore, an adjust_threshold value > 0 makes detecting objects harder while a negative value makes it easier. This means that, for example, you can obtain the maximum possible number of detections by setting adjust_threshold equal to negative infinity. !*/ template < typename image_type > void operator() ( const image_type& img, std::vector<std::pair<double, rectangle> >& dets, double adjust_threshold = 0 ); /*! requires - img == an object which can be accepted by image_scanner_type::load() ensures - performs object detection on the given image and stores the detected objects into #dets. In particular, we will have that: - #dets is sorted such that the highest confidence detections come first. E.g. element 0 is the best detection, element 1 the next best, and so on. - #dets.size() == the number of detected objects. - #dets[i].first gives the "detection confidence", of the i-th detection. This is the detection value output by the scanner minus the threshold value stored at the end of the weight vector in get_w(). - #dets[i].second == the bounding box for the i-th detection. - #get_scanner() will have been loaded with img. Therefore, you can call #get_scanner().get_feature_vector() to obtain the feature vectors or #get_scanner().get_full_object_detection() to get the full_object_detections for the resulting object detection boxes. - The detection threshold is adjusted by having adjust_threshold added to it. Therefore, an adjust_threshold value > 0 makes detecting objects harder while a negative value makes it easier. Moreover, the following will be true for all valid i: - #dets[i].first >= adjust_threshold This means that, for example, you can obtain the maximum possible number of detections by setting adjust_threshold equal to negative infinity. !*/ template < typename image_type > void operator() ( const image_type& img, std::vector<std::pair<double, full_object_detection> >& final_dets, double adjust_threshold = 0 ); /*! requires - img == an object which can be accepted by image_scanner_type::load() ensures - This function is identical to the above operator() routine, except that it outputs full_object_detections instead of rectangles. This means that the output includes part locations. In particular, calling this function is the same as calling the above operator() routine and then using get_scanner().get_full_object_detection() to resolve all the rectangles into full_object_detections. Therefore, this version of operator() is simply a convenience function for performing this set of operations. !*/ template < typename image_type > void operator() ( const image_type& img, std::vector<full_object_detection>& final_dets, double adjust_threshold = 0 ); /*! requires - img == an object which can be accepted by image_scanner_type::load() ensures - This function is identical to the above operator() routine, except that it doesn't include a double valued score. That is, it just outputs the full_object_detections. !*/ }; // ---------------------------------------------------------------------------------------- template <typename T> void serialize ( const object_detector<T>& item, std::ostream& out ); /*! provides serialization support. Note that this function only saves the configuration part of item.get_scanner(). That is, we use the scanner's copy_configuration() function to get a copy of the scanner that doesn't contain any loaded image data and we then save just the configuration part of the scanner. This means that any serialized object_detectors won't remember any images they have processed but will otherwise contain all their state and be able to detect objects in new images. !*/ // ---------------------------------------------------------------------------------------- template <typename T> void deserialize ( object_detector<T>& item, std::istream& in ); /*! provides deserialization support !*/ // ---------------------------------------------------------------------------------------- } #endif // DLIB_OBJECT_DeTECTOR_ABSTRACT_H__