// Copyright (C) 2011 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_MAX_SUM_SUBMaTRIX_Hh_ #define DLIB_MAX_SUM_SUBMaTRIX_Hh_ #include "max_sum_submatrix_abstract.h" #include "../matrix.h" #include <vector> #include <queue> #include "../geometry.h" namespace dlib { namespace impl { // ------------------------------------------------------------------------------------ template <typename T> struct range_set { int top_min; int top_max; int bottom_min; int bottom_max; T weight; bool operator<(const range_set& item) const { return weight < item.weight; } }; // ------------------------------------------------------------------------------------ template <typename T> bool is_terminal_set ( const range_set<T>& item ) { return (item.top_min >= item.top_max && item.bottom_min >= item.bottom_max); } // ------------------------------------------------------------------------------------ template <typename T> void split ( const range_set<T>& rset, range_set<T>& a, range_set<T>& b ) { if (rset.top_max - rset.top_min > rset.bottom_max - rset.bottom_min) { // split top const int middle = (rset.top_max + rset.top_min)/2; a.top_min = rset.top_min; a.top_max = middle; b.top_min = middle+1; b.top_max = rset.top_max; a.bottom_min = rset.bottom_min; a.bottom_max = rset.bottom_max; b.bottom_min = rset.bottom_min; b.bottom_max = rset.bottom_max; } else { // split bottom const int middle = (rset.bottom_max + rset.bottom_min)/2; a.bottom_min = rset.bottom_min; a.bottom_max = middle; b.bottom_min = middle+1; b.bottom_max = rset.bottom_max; a.top_min = rset.top_min; a.top_max = rset.top_max; b.top_min = rset.top_min; b.top_max = rset.top_max; } } // ------------------------------------------------------------------------------------ template <typename EXP, typename T> void find_best_column_range ( const matrix_exp<EXP>& sum_pos, const matrix_exp<EXP>& sum_neg, const range_set<T>& row_range, T& weight, int& left, int& right ) { left = 0; right = -1; weight = 0; T cur_sum = 0; int cur_pos = 0; for (long c = 0; c < sum_pos.nc(); ++c) { // compute the value for the current column T temp = sum_pos(row_range.bottom_max+1,c) - sum_pos(row_range.top_min,c); if (row_range.top_max <= row_range.bottom_min) temp += sum_neg(row_range.bottom_min+1,c) - sum_neg(row_range.top_max,c); cur_sum += temp; if (cur_sum > weight) { left = cur_pos; right = c; weight = cur_sum; } if (cur_sum <= 0) { cur_sum = 0; cur_pos = c+1; } } } } // ---------------------------------------------------------------------------------------- template <typename EXP> std::vector<rectangle> max_sum_submatrix( const matrix_exp<EXP>& mat, unsigned long max_rects, double thresh_ = 0 ) { // make sure requires clause is not broken DLIB_ASSERT(thresh_ >= 0 && mat.size() > 0, "\t std::vector<rectangle> max_sum_submatrix()" << "\n\t Invalid arguments were given to this function." << "\n\t mat.size(): " << mat.size() << "\n\t thresh_: " << thresh_ ); /* This function is basically an implementation of the efficient subwindow search (I-ESS) algorithm presented in the following paper: Efficient Algorithms for Subwindow Search in Object Detection and Localization by Senjian An, Patrick Peursum, Wanquan Liu and Svetha Venkatesh In CVPR 2009 */ if (max_rects == 0) return std::vector<rectangle>(); using namespace dlib::impl; typedef typename EXP::type element_type; typedef typename promote<element_type>::type scalar_type; const scalar_type thresh = static_cast<scalar_type>(thresh_); matrix<scalar_type> sum_pos; matrix<scalar_type> sum_neg; sum_pos.set_size(mat.nr()+1, mat.nc()); sum_neg.set_size(mat.nr()+1, mat.nc()); // integrate over the rows. for (long c = 0; c < mat.nc(); ++c) { sum_pos(0,c) = 0; sum_neg(0,c) = 0; } for (long r = 0; r < mat.nr(); ++r) { for (long c = 0; c < mat.nc(); ++c) { if (mat(r,c) > 0) { sum_pos(r+1,c) = mat(r,c) + sum_pos(r,c); sum_neg(r+1,c) = sum_neg(r,c); } else { sum_pos(r+1,c) = sum_pos(r,c); sum_neg(r+1,c) = mat(r,c) + sum_neg(r,c); } } } std::priority_queue<range_set<scalar_type> > q; // the range_sets will represent ranges of columns range_set<scalar_type> universe_set; universe_set.bottom_min = 0; universe_set.top_min = 0; universe_set.bottom_max = mat.nr()-1; universe_set.top_max = mat.nr()-1; universe_set.weight = sum(rowm(dlib::mat(sum_pos),mat.nr())); q.push(universe_set); std::vector<rectangle> results; std::vector<scalar_type> temp_pos(mat.nc()); std::vector<scalar_type> temp_neg(mat.nc()); while (q.size() > 0) { if (is_terminal_set(q.top())) { int left, right; scalar_type weight; find_best_column_range(sum_pos, sum_neg, q.top(), weight, left, right); rectangle rect(left, q.top().top_min, right, q.top().bottom_min); if (weight <= thresh) break; results.push_back(rect); if (results.size() >= max_rects) break; q = std::priority_queue<range_set<scalar_type> >(); // We are going to blank out the weights we just used. So adjust the sum images appropriately. for (long c = rect.left(); c <= rect.right(); ++c) { temp_pos[c] = sum_pos(rect.bottom()+1,c) - sum_pos(rect.top(),c); temp_neg[c] = sum_neg(rect.bottom()+1,c) - sum_neg(rect.top(),c); } // blank out the area inside the rectangle for (long r = rect.top(); r <= rect.bottom(); ++r) { for (long c = rect.left(); c <= rect.right(); ++c) { sum_pos(r+1,c) = sum_pos(r,c); sum_neg(r+1,c) = sum_neg(r,c); } } // account for the area below the rectangle for (long r = rect.bottom()+2; r < sum_pos.nr(); ++r) { for (long c = rect.left(); c <= rect.right(); ++c) { sum_pos(r,c) -= temp_pos[c]; sum_neg(r,c) -= temp_neg[c]; } } universe_set.weight = sum(rowm(dlib::mat(sum_pos),mat.nr())); if (universe_set.weight <= thresh) break; q.push(universe_set); continue; } range_set<scalar_type> a, b; split(q.top(), a,b); q.pop(); // these variables are not used at this point in the algorithm. int a_left, a_right; int b_left, b_right; find_best_column_range(sum_pos, sum_neg, a, a.weight, a_left, a_right); find_best_column_range(sum_pos, sum_neg, b, b.weight, b_left, b_right); if (a.weight > thresh) q.push(a); if (b.weight > thresh) q.push(b); } return results; } // ---------------------------------------------------------------------------------------- } #endif // DLIB_MAX_SUM_SUBMaTRIX_Hh_