1 /*M///////////////////////////////////////////////////////////////////////////////////////
2  //
3  //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4  //
5  //  By downloading, copying, installing or using the software you agree to this license.
6  //  If you do not agree to this license, do not download, install,
7  //  copy or use the software.
8  //
9  //
10  //                           License Agreement
11  //                For Open Source Computer Vision Library
12  //
13  // Copyright (C) 2014, OpenCV Foundation, all rights reserved.
14  // Third party copyrights are property of their respective owners.
15  //
16  // Redistribution and use in source and binary forms, with or without modification,
17  // are permitted provided that the following conditions are met:
18  //
19  //   * Redistribution's of source code must retain the above copyright notice,
20  //     this list of conditions and the following disclaimer.
21  //
22  //   * Redistribution's in binary form must reproduce the above copyright notice,
23  //     this list of conditions and the following disclaimer in the documentation
24  //     and/or other materials provided with the distribution.
25  //
26  //   * The name of the copyright holders may not be used to endorse or promote products
27  //     derived from this software without specific prior written permission.
28  //
29  // This software is provided by the copyright holders and contributors "as is" and
30  // any express or implied warranties, including, but not limited to, the implied
31  // warranties of merchantability and fitness for a particular purpose are disclaimed.
32  // In no event shall the Intel Corporation or contributors be liable for any direct,
33  // indirect, incidental, special, exemplary, or consequential damages
34  // (including, but not limited to, procurement of substitute goods or services;
35  // loss of use, data, or profits; or business interruption) however caused
36  // and on any theory of liability, whether in contract, strict liability,
37  // or tort (including negligence or otherwise) arising in any way out of
38  // the use of this software, even if advised of the possibility of such damage.
39  //
40  //M*/
41 
42 #include "../precomp.hpp"
43 
44 #include "kyheader.hpp"
45 #include "CmTimer.hpp"
46 #include "CmFile.hpp"
47 
48 namespace cv
49 {
50 namespace saliency
51 {
52 
53 /**
54  * BING Objectness
55  */
56 
57 const char* ObjectnessBING::_clrName[3] =
58 { "MAXBGR", "HSV", "I" };
59 
ObjectnessBING()60 ObjectnessBING::ObjectnessBING()
61 {
62   _base = 2;  // base for window size quantization
63   _W = 8;  // feature window size (W, W)
64   _NSS = 2;  //non-maximal suppress size NSS
65   _logBase = log( _base );
66   _minT = cvCeil( log( 10. ) / _logBase );
67   _maxT = cvCeil( log( 500. ) / _logBase );
68   _numT = _maxT - _minT + 1;
69   _Clr = MAXBGR;
70 
71   setColorSpace( _Clr );
72 
73   className = "BING";
74 }
75 
~ObjectnessBING()76 ObjectnessBING::~ObjectnessBING()
77 {
78 
79 }
80 
setColorSpace(int clr)81 void ObjectnessBING::setColorSpace( int clr )
82 {
83   _Clr = clr;
84   _modelName = _trainingPath + "/" + std::string( format( "ObjNessB%gW%d%s", _base, _W, _clrName[_Clr] ).c_str() );
85   _bbResDir = _resultsDir + "/" + std::string( format( "BBoxesB%gW%d%s/", _base, _W, _clrName[_Clr] ).c_str() );
86 }
87 
setTrainingPath(const String & trainingPath)88 void ObjectnessBING::setTrainingPath( const String& trainingPath )
89 {
90   _trainingPath = trainingPath;
91 }
92 
setBBResDir(const String & resultsDir)93 void ObjectnessBING::setBBResDir(const String &resultsDir )
94 {
95   _resultsDir = resultsDir;
96 }
97 
loadTrainedModel()98 int ObjectnessBING::loadTrainedModel()  // Return -1, 0, or 1 if partial, none, or all loaded
99 {
100   CStr s1 = _modelName + ".wS1", s2 = _modelName + ".wS2", sI = _modelName + ".idx";
101   Mat filters1f, reW1f, idx1i, show3u;
102 
103   if( !matRead( s1, filters1f ) || !matRead( sI, idx1i ) )
104   {
105     printf( "Can't load model: %s or %s\r\n", s1.c_str(), sI.c_str() );
106     return 0;
107   }
108 
109 
110   normalize( filters1f, show3u, 1, 255, NORM_MINMAX, CV_8U );
111   _tigF.update( filters1f );
112 
113   _svmSzIdxs = idx1i;
114   CV_Assert( _svmSzIdxs.size() > 1 && filters1f.size() == Size(_W, _W) && filters1f.type() == CV_32F );
115   _svmFilter = filters1f;
116 
117   if( !matRead( s2, _svmReW1f ) || _svmReW1f.size() != Size( 2, (int) _svmSzIdxs.size() ) )
118   {
119     _svmReW1f = Mat();
120     return -1;
121   }
122   return 1;
123 }
124 
predictBBoxSI(Mat & img3u,ValStructVec<float,Vec4i> & valBoxes,std::vector<int> & sz,int NUM_WIN_PSZ,bool fast)125 void ObjectnessBING::predictBBoxSI( Mat &img3u, ValStructVec<float, Vec4i> &valBoxes, std::vector<int> &sz, int NUM_WIN_PSZ, bool fast )
126 {
127   const int numSz = (int) _svmSzIdxs.size();
128   const int imgW = img3u.cols, imgH = img3u.rows;
129   valBoxes.reserve( 10000 );
130   sz.clear();
131   sz.reserve( 10000 );
132   for ( int ir = numSz - 1; ir >= 0; ir-- )
133   {
134     int r = _svmSzIdxs[ir];
135     int height = cvRound( pow( _base, r / _numT + _minT ) ), width = cvRound( pow( _base, r % _numT + _minT ) );
136     if( height > imgH * _base || width > imgW * _base )
137       continue;
138 
139     height = min( height, imgH ), width = min( width, imgW );
140     Mat im3u, matchCost1f, mag1u;
141     resize( img3u, im3u, Size( cvRound( _W * imgW * 1.0 / width ), cvRound( _W * imgH * 1.0 / height ) ), 0, 0, INTER_LINEAR_EXACT );
142     gradientMag( im3u, mag1u );
143 
144     matchCost1f = _tigF.matchTemplate( mag1u );
145 
146     ValStructVec<float, Point> matchCost;
147     nonMaxSup( matchCost1f, matchCost, _NSS, NUM_WIN_PSZ, fast );
148 
149     // Find true locations and match values
150     double ratioX = width / _W, ratioY = height / _W;
151     int iMax = min( matchCost.size(), NUM_WIN_PSZ );
152     for ( int i = 0; i < iMax; i++ )
153     {
154       float mVal = matchCost( i );
155       Point pnt = matchCost[i];
156       Vec4i box( cvRound( pnt.x * ratioX ), cvRound( pnt.y * ratioY ) );
157       box[2] = cvRound( min( box[0] + width, imgW ) );
158       box[3] = cvRound( min( box[1] + height, imgH ) );
159       box[0]++;
160       box[1]++;
161       valBoxes.pushBack( mVal, box );
162       sz.push_back( ir );
163     }
164   }
165 
166 }
167 
predictBBoxSII(ValStructVec<float,Vec4i> & valBoxes,const std::vector<int> & sz)168 void ObjectnessBING::predictBBoxSII( ValStructVec<float, Vec4i> &valBoxes, const std::vector<int> &sz )
169 {
170   int numI = valBoxes.size();
171   for ( int i = 0; i < numI; i++ )
172   {
173     const float* svmIIw = _svmReW1f.ptr<float>( sz[i] );
174     valBoxes( i ) = valBoxes( i ) * svmIIw[0] + svmIIw[1];
175   }
176   //valBoxes.sort();
177   // Descending order. At the top there are the values with higher
178   // values, ie more likely to have objects in the their corresponding rectangles.
179   valBoxes.sort( true );
180 }
181 
182 // Get potential bounding boxes, each of which is represented by a Vec4i for (minX, minY, maxX, maxY).
183 // The trained model should be prepared before calling this function: loadTrainedModel() or trainStageI() + trainStageII().
184 // Use numDet to control the final number of proposed bounding boxes, and number of per size (scale and aspect ratio)
getObjBndBoxes(Mat & img3u,ValStructVec<float,Vec4i> & valBoxes,int numDetPerSize)185 void ObjectnessBING::getObjBndBoxes( Mat &img3u, ValStructVec<float, Vec4i> &valBoxes, int numDetPerSize )
186 {
187   //CV_Assert_(filtersLoaded() , ("SVM filters should be initialized before getting object proposals\n"));
188   vecI sz;
189   predictBBoxSI( img3u, valBoxes, sz, numDetPerSize, false );
190   predictBBoxSII( valBoxes, sz );
191   return;
192 }
193 
nonMaxSup(Mat & matchCost1f,ValStructVec<float,Point> & matchCost,int NSS,int maxPoint,bool fast)194 void ObjectnessBING::nonMaxSup( Mat &matchCost1f, ValStructVec<float, Point> &matchCost, int NSS, int maxPoint, bool fast )
195 {
196   const int _h = matchCost1f.rows, _w = matchCost1f.cols;
197   Mat isMax1u = Mat::ones( _h, _w, CV_8U ), costSmooth1f;
198   ValStructVec<float, Point> valPnt;
199   matchCost.reserve( _h * _w );
200   valPnt.reserve( _h * _w );
201   if( fast )
202   {
203     blur( matchCost1f, costSmooth1f, Size( 3, 3 ) );
204     for ( int r = 0; r < _h; r++ )
205     {
206       const float* d = matchCost1f.ptr<float>( r );
207       const float* ds = costSmooth1f.ptr<float>( r );
208       for ( int c = 0; c < _w; c++ )
209         if( d[c] >= ds[c] )
210           valPnt.pushBack( d[c], Point( c, r ) );
211     }
212   }
213   else
214   {
215     for ( int r = 0; r < _h; r++ )
216     {
217       const float* d = matchCost1f.ptr<float>( r );
218       for ( int c = 0; c < _w; c++ )
219         valPnt.pushBack( d[c], Point( c, r ) );
220     }
221   }
222 
223   valPnt.sort();
224   for ( int i = 0; i < valPnt.size(); i++ )
225   {
226     Point &pnt = valPnt[i];
227     if( isMax1u.at<BYTE>( pnt ) )
228     {
229       matchCost.pushBack( valPnt( i ), pnt );
230       for ( int dy = -NSS; dy <= NSS; dy++ )
231         for ( int dx = -NSS; dx <= NSS; dx++ )
232         {
233           Point neighbor = pnt + Point( dx, dy );
234           if( !CHK_IND( neighbor ) )
235             continue;
236           isMax1u.at<BYTE>( neighbor ) = false;
237         }
238     }
239     if( matchCost.size() >= maxPoint )
240       return;
241   }
242 }
243 
gradientMag(Mat & imgBGR3u,Mat & mag1u)244 void ObjectnessBING::gradientMag( Mat &imgBGR3u, Mat &mag1u )
245 {
246   switch ( _Clr )
247   {
248     case MAXBGR:
249       gradientRGB( imgBGR3u, mag1u );
250       break;
251     case G:
252       gradientGray( imgBGR3u, mag1u );
253       break;
254     case HSV:
255       gradientHSV( imgBGR3u, mag1u );
256       break;
257     default:
258       printf( "Error: not recognized color space\n" );
259   }
260 }
261 
gradientRGB(Mat & bgr3u,Mat & mag1u)262 void ObjectnessBING::gradientRGB( Mat &bgr3u, Mat &mag1u )
263 {
264   const int H = bgr3u.rows, W = bgr3u.cols;
265   Mat Ix( H, W, CV_32S ), Iy( H, W, CV_32S );
266 
267   // Left/right most column Ix
268   for ( int y = 0; y < H; y++ )
269   {
270     Ix.at<int>( y, 0 ) = bgrMaxDist( bgr3u.at<Vec3b>( y, 1 ), bgr3u.at<Vec3b>( y, 0 ) ) * 2;
271     Ix.at<int>( y, W - 1 ) = bgrMaxDist( bgr3u.at<Vec3b>( y, W - 1 ), bgr3u.at<Vec3b>( y, W - 2 ) ) * 2;
272   }
273 
274   // Top/bottom most column Iy
275   for ( int x = 0; x < W; x++ )
276   {
277     Iy.at<int>( 0, x ) = bgrMaxDist( bgr3u.at<Vec3b>( 1, x ), bgr3u.at<Vec3b>( 0, x ) ) * 2;
278     Iy.at<int>( H - 1, x ) = bgrMaxDist( bgr3u.at<Vec3b>( H - 1, x ), bgr3u.at<Vec3b>( H - 2, x ) ) * 2;
279   }
280 
281   // Find the gradient for inner regions
282   for ( int y = 0; y < H; y++ )
283   {
284     const Vec3b *dataP = bgr3u.ptr<Vec3b>( y );
285     for ( int x = 2; x < W; x++ )
286       Ix.at<int>( y, x - 1 ) = bgrMaxDist( dataP[x - 2], dataP[x] );  //  bgr3u.at<Vec3b>(y, x+1), bgr3u.at<Vec3b>(y, x-1));
287   }
288   for ( int y = 1; y < H - 1; y++ )
289   {
290     const Vec3b *tP = bgr3u.ptr<Vec3b>( y - 1 );
291     const Vec3b *bP = bgr3u.ptr<Vec3b>( y + 1 );
292     for ( int x = 0; x < W; x++ )
293       Iy.at<int>( y, x ) = bgrMaxDist( tP[x], bP[x] );
294   }
295   gradientXY( Ix, Iy, mag1u );
296 }
297 
gradientGray(Mat & bgr3u,Mat & mag1u)298 void ObjectnessBING::gradientGray( Mat &bgr3u, Mat &mag1u )
299 {
300   Mat g1u;
301   cvtColor( bgr3u, g1u, COLOR_BGR2GRAY );
302   const int H = g1u.rows, W = g1u.cols;
303   Mat Ix( H, W, CV_32S ), Iy( H, W, CV_32S );
304 
305   // Left/right most column Ix
306   for ( int y = 0; y < H; y++ )
307   {
308     Ix.at<int>( y, 0 ) = abs( g1u.at<BYTE>( y, 1 ) - g1u.at<BYTE>( y, 0 ) ) * 2;
309     Ix.at<int>( y, W - 1 ) = abs( g1u.at<BYTE>( y, W - 1 ) - g1u.at<BYTE>( y, W - 2 ) ) * 2;
310   }
311 
312   // Top/bottom most column Iy
313   for ( int x = 0; x < W; x++ )
314   {
315     Iy.at<int>( 0, x ) = abs( g1u.at<BYTE>( 1, x ) - g1u.at<BYTE>( 0, x ) ) * 2;
316     Iy.at<int>( H - 1, x ) = abs( g1u.at<BYTE>( H - 1, x ) - g1u.at<BYTE>( H - 2, x ) ) * 2;
317   }
318 
319   // Find the gradient for inner regions
320   for ( int y = 0; y < H; y++ )
321     for ( int x = 1; x < W - 1; x++ )
322       Ix.at<int>( y, x ) = abs( g1u.at<BYTE>( y, x + 1 ) - g1u.at<BYTE>( y, x - 1 ) );
323   for ( int y = 1; y < H - 1; y++ )
324     for ( int x = 0; x < W; x++ )
325       Iy.at<int>( y, x ) = abs( g1u.at<BYTE>( y + 1, x ) - g1u.at<BYTE>( y - 1, x ) );
326 
327   gradientXY( Ix, Iy, mag1u );
328 }
329 
gradientHSV(Mat & bgr3u,Mat & mag1u)330 void ObjectnessBING::gradientHSV( Mat &bgr3u, Mat &mag1u )
331 {
332   Mat hsv3u;
333   cvtColor( bgr3u, hsv3u, COLOR_BGR2HSV );
334   const int H = hsv3u.rows, W = hsv3u.cols;
335   Mat Ix( H, W, CV_32S ), Iy( H, W, CV_32S );
336 
337   // Left/right most column Ix
338   for ( int y = 0; y < H; y++ )
339   {
340     Ix.at<int>( y, 0 ) = vecDist3b( hsv3u.at<Vec3b>( y, 1 ), hsv3u.at<Vec3b>( y, 0 ) );
341     Ix.at<int>( y, W - 1 ) = vecDist3b( hsv3u.at<Vec3b>( y, W - 1 ), hsv3u.at<Vec3b>( y, W - 2 ) );
342   }
343 
344   // Top/bottom most column Iy
345   for ( int x = 0; x < W; x++ )
346   {
347     Iy.at<int>( 0, x ) = vecDist3b( hsv3u.at<Vec3b>( 1, x ), hsv3u.at<Vec3b>( 0, x ) );
348     Iy.at<int>( H - 1, x ) = vecDist3b( hsv3u.at<Vec3b>( H - 1, x ), hsv3u.at<Vec3b>( H - 2, x ) );
349   }
350 
351   // Find the gradient for inner regions
352   for ( int y = 0; y < H; y++ )
353     for ( int x = 1; x < W - 1; x++ )
354       Ix.at<int>( y, x ) = vecDist3b( hsv3u.at<Vec3b>( y, x + 1 ), hsv3u.at<Vec3b>( y, x - 1 ) ) / 2;
355   for ( int y = 1; y < H - 1; y++ )
356     for ( int x = 0; x < W; x++ )
357       Iy.at<int>( y, x ) = vecDist3b( hsv3u.at<Vec3b>( y + 1, x ), hsv3u.at<Vec3b>( y - 1, x ) ) / 2;
358 
359   gradientXY( Ix, Iy, mag1u );
360 }
361 
gradientXY(Mat & x1i,Mat & y1i,Mat & mag1u)362 void ObjectnessBING::gradientXY( Mat &x1i, Mat &y1i, Mat &mag1u )
363 {
364   const int H = x1i.rows, W = x1i.cols;
365   mag1u.create( H, W, CV_8U );
366   for ( int r = 0; r < H; r++ )
367   {
368     const int *x = x1i.ptr<int>( r ), *y = y1i.ptr<int>( r );
369     BYTE* m = mag1u.ptr<BYTE>( r );
370     for ( int c = 0; c < W; c++ )
371       m[c] = (BYTE) min( x[c] + y[c], 255 );   //((int)sqrt(sqr(x[c]) + sqr(y[c])), 255);
372   }
373 }
374 
getObjBndBoxesForSingleImage(Mat img,ValStructVec<float,Vec4i> & finalBoxes,int numDetPerSize)375 void ObjectnessBING::getObjBndBoxesForSingleImage( Mat img, ValStructVec<float, Vec4i> &finalBoxes, int numDetPerSize )
376 {
377   ValStructVec<float, Vec4i> boxes;
378   finalBoxes.reserve( 10000 );
379 
380   int scales[3] =
381   { 1, 3, 5 };
382   for ( int clr = MAXBGR; clr <= G; clr++ )
383   {
384     setColorSpace( clr );
385     if (!loadTrainedModel())
386       continue;
387 
388     CmTimer tm( "Predict" );
389     tm.Start();
390 
391     getObjBndBoxes( img, boxes, numDetPerSize );
392     finalBoxes.append( boxes, scales[clr] );
393 
394     tm.Stop();
395     printf( "Average time for predicting an image (%s) is %gs\n", _clrName[_Clr], tm.TimeInSeconds() );
396   }
397 
398   //Write on file the total number and the list of rectangles returned by objectess, one for each row.
399 
400   CmFile::MkDir( _bbResDir );
401   CStr fName = _bbResDir + "bb";
402   std::vector<Vec4i> sortedBB = finalBoxes.getSortedStructVal();
403   std::ofstream ofs;
404   ofs.open( ( fName + ".txt" ).c_str(), std::ofstream::out );
405   std::stringstream dim;
406   dim << sortedBB.size();
407   ofs << dim.str() << "\n";
408   for ( size_t k = 0; k < sortedBB.size(); k++ )
409   {
410     std::stringstream str;
411     str << sortedBB[k][0] << " " << sortedBB[k][1] << " " << sortedBB[k][2] << " " << sortedBB[k][3] << "\n";
412     ofs << str.str();
413   }
414   ofs.close();
415 }
416 
417 struct MatchPathSeparator
418 {
operator ()cv::saliency::MatchPathSeparator419   bool operator()( char ch ) const
420   {
421     return ch == '/';
422   }
423 };
424 
basename(std::string const & pathname)425 std::string inline basename( std::string const& pathname )
426 {
427   return std::string( std::find_if( pathname.rbegin(), pathname.rend(), MatchPathSeparator() ).base(), pathname.end() );
428 }
429 
removeExtension(std::string const & filename)430 std::string inline removeExtension( std::string const& filename )
431 {
432   std::string::const_reverse_iterator pivot = std::find( filename.rbegin(), filename.rend(), '.' );
433   return pivot == filename.rend() ? filename : std::string( filename.begin(), pivot.base() - 1 );
434 }
435 
436 // Read matrix from binary file
matRead(const std::string & filename,Mat & _M)437 bool ObjectnessBING::matRead( const std::string& filename, Mat& _M )
438 {
439   String filenamePlusExt( filename.c_str() );
440   filenamePlusExt += ".yml.gz";
441   FileStorage fs2( filenamePlusExt, FileStorage::READ );
442   if (! fs2.isOpened()) // wrong trainingPath
443     return false;
444 
445   Mat M;
446   fs2[String( removeExtension( basename( filename ) ).c_str() )] >> M;
447 
448   M.copyTo( _M );
449   return true;
450 }
getobjectnessValues()451 std::vector<float> ObjectnessBING::getobjectnessValues()
452 {
453   return objectnessValues;
454 }
455 
read()456 void ObjectnessBING::read()
457 {
458 
459 }
460 
write() const461 void ObjectnessBING::write() const
462 {
463 
464 }
465 
computeSaliencyImpl(InputArray image,OutputArray objectnessBoundingBox)466 bool ObjectnessBING::computeSaliencyImpl( InputArray image, OutputArray objectnessBoundingBox )
467 {
468   ValStructVec<float, Vec4i> finalBoxes;
469   getObjBndBoxesForSingleImage( image.getMat(), finalBoxes, 250 );
470 
471   // List of rectangles returned by objectess function in descending order.
472   // At the top there are the rectangles with higher values, ie more
473   // likely to have objects in them.
474   std::vector<Vec4i> sortedBB = finalBoxes.getSortedStructVal();
475   Mat( sortedBB ).copyTo( objectnessBoundingBox );
476 
477   // List of the rectangles' objectness value
478   unsigned long int valIdxesSize = (unsigned long int) finalBoxes.getvalIdxes().size();
479   objectnessValues.resize( valIdxesSize );
480   for ( uint i = 0; i < valIdxesSize; i++ )
481     objectnessValues[finalBoxes.getvalIdxes()[i].second] = finalBoxes.getvalIdxes()[i].first;
482 
483   return true;
484 }
485 
486 template<typename VT, typename ST>
append(const ValStructVec<VT,ST> & newVals,int startV)487 void ObjectnessBING::ValStructVec<VT, ST>::append( const ValStructVec<VT, ST> &newVals, int startV )
488 {
489   int newValsSize = newVals.size();
490   for ( int i = 0; i < newValsSize; i++ )
491     pushBack( (float) ( ( i + 300 ) * startV ), newVals[i] );
492 }
493 
494 template<typename VT, typename ST>
sort(bool descendOrder)495 void ObjectnessBING::ValStructVec<VT, ST>::sort( bool descendOrder /* = true */)
496 {
497   if( descendOrder )
498     std::sort( valIdxes.begin(), valIdxes.end(), std::greater<std::pair<VT, int> >() );
499   else
500     std::sort( valIdxes.begin(), valIdxes.end(), std::less<std::pair<VT, int> >() );
501 }
502 
503 template<typename VT, typename ST>
getSortedStructVal()504 const std::vector<ST>& ObjectnessBING::ValStructVec<VT, ST>::getSortedStructVal()
505 {
506   sortedStructVals.resize( sz );
507   for ( int i = 0; i < sz; i++ )
508     sortedStructVals[i] = structVals[valIdxes[i].second];
509   return sortedStructVals;
510 }
511 
512 template<typename VT, typename ST>
getvalIdxes()513 std::vector<std::pair<VT, int> > ObjectnessBING::ValStructVec<VT, ST>::getvalIdxes()
514 {
515   return valIdxes;
516 }
517 
518 template<typename VT, typename ST>
ValStructVec()519 ObjectnessBING::ValStructVec<VT, ST>::ValStructVec()
520 {
521   clear();
522 }
523 
524 template<typename VT, typename ST>
size() const525 int ObjectnessBING::ValStructVec<VT, ST>::size() const
526 {
527   return sz;
528 }
529 
530 template<typename VT, typename ST>
clear()531 void ObjectnessBING::ValStructVec<VT, ST>::clear()
532 {
533   sz = 0;
534   structVals.clear();
535   valIdxes.clear();
536 }
537 
538 template<typename VT, typename ST>
reserve(int resSz)539 void ObjectnessBING::ValStructVec<VT, ST>::reserve( int resSz )
540 {
541   clear();
542   structVals.reserve( resSz );
543   valIdxes.reserve( resSz );
544 }
545 
546 template<typename VT, typename ST>
pushBack(const VT & val,const ST & structVal)547 void ObjectnessBING::ValStructVec<VT, ST>::pushBack( const VT& val, const ST& structVal )
548 {
549   valIdxes.push_back( std::make_pair( val, sz ) );
550   structVals.push_back( structVal );
551   sz++;
552 }
553 
554 template<typename VT, typename ST>
operator ()(int i) const555 const VT& ObjectnessBING::ValStructVec<VT, ST>::operator ()( int i ) const
556 {
557   return valIdxes[i].first;
558 }  // Should be called after sort
559 
560 template<typename VT, typename ST>
operator [](int i) const561 const ST& ObjectnessBING::ValStructVec<VT, ST>::operator []( int i ) const
562 {
563   return structVals[valIdxes[i].second];
564 }  // Should be called after sort
565 
566 template<typename VT, typename ST>
567 VT& ObjectnessBING::ValStructVec<VT, ST>::operator ()( int i )
568 {
569   return valIdxes[i].first;
570 }  // Should be called after sort
571 
572 template<typename VT, typename ST>
operator [](int i)573 ST& ObjectnessBING::ValStructVec<VT, ST>::operator []( int i )
574 {
575   return structVals[valIdxes[i].second];
576 }
577 
578 } /* namespace saliency */
579 }/* namespace cv */
580