Added to objdetect module: meanshift grouping (groupRectangles_meanshift(...) for...
authorAlexey Kazakov <no@email>
Tue, 19 Apr 2011 09:05:15 +0000 (09:05 +0000)
committerAlexey Kazakov <no@email>
Tue, 19 Apr 2011 09:05:15 +0000 (09:05 +0000)
Some changes in the HOGDescriptor class interface(objdetect.hpp) (added useMeanShiftGrouping parameter to the detectMultiScale(...) function)

modules/objdetect/include/opencv2/objdetect/objdetect.hpp
modules/objdetect/src/cascadedetect.cpp
modules/objdetect/src/hog.cpp
modules/objdetect/src/ms_grouping.cpp [new file with mode: 0644]

index 8eaf538..a2b6cd0 100644 (file)
@@ -275,6 +275,41 @@ namespace cv
 
 CV_EXPORTS_W void groupRectangles(vector<Rect>& rectList, int groupThreshold, double eps=0.2);
 CV_EXPORTS_W void groupRectangles(vector<Rect>& rectList, CV_OUT vector<int>& weights, int groupThreshold, double eps=0.2);
+CV_EXPORTS void groupRectangles(vector<Rect>& rectList, vector<double>& resultWeights, int groupThreshold = 2, double eps=0.2);
+CV_EXPORTS void groupRectangles_meanshift(vector<Rect>& rectList, vector<double>& foundWeights, vector<double>& foundScales, 
+                                                                                 double detectThreshold = 0.0, Size winDetSize = Size(64, 128));
+
+class MeanshiftGrouping
+{
+public:
+       MeanshiftGrouping(const Point3d& densKer, const vector<Point3d>& posV, 
+               const vector<double>& wV, double modeEps = 1e-4,
+               int maxIt = 20);
+       
+       void getModes(vector<Point3d>& modesV, vector<double>& resWeightsV, const double eps); 
+
+protected:
+       vector<Point3d> positionsV;
+       vector<double> weightsV;
+
+       Point3d densityKernel;
+       int positionsCount;
+
+       vector<Point3d> meanshiftV;
+       vector<Point3d> distanceV;
+       int iterMax;
+       double modeEps;
+
+       Point3d getNewValue(const Point3d& inPt) const;
+
+       double getResultWeight(const Point3d& inPt) const; 
+
+       Point3d moveToMode(Point3d aPt) const; 
+
+       double getDistance(Point3d p1, Point3d p2) const; 
+};
+
+
         
 class CV_EXPORTS FeatureEvaluator
 {
@@ -312,7 +347,10 @@ public:
                                    double scaleFactor=1.1,
                                    int minNeighbors=3, int flags=0,
                                    Size minSize=Size(),
-                                   Size maxSize=Size() );
+                                   Size maxSize=Size(),
+                                   bool outputRejectLevels = false, 
+                                   vector<int>& rejectLevels = vector<int>(0));
+
 
     bool isOldFormatCascade() const;
     virtual Size getOriginalWindowSize() const;
@@ -321,7 +359,8 @@ public:
 
 protected:
     virtual bool detectSingleScale( const Mat& image, int stripCount, Size processingRectSize,
-                                    int stripSize, int yStep, double factor, vector<Rect>& candidates );
+                                    int stripSize, int yStep, double factor, vector<Rect>& candidates,
+                                    bool outputRejectLevels = false, vector<int>& rejectLevels = vector<int>(0) );
 
 protected:
     enum { BOOST = 0 };
@@ -387,6 +426,35 @@ protected:
     Data data;
     Ptr<FeatureEvaluator> featureEvaluator;
     Ptr<CvHaarClassifierCascade> oldCascade;
+
+//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+public:
+    int getNumStages()
+    {
+        int numStages;
+        if( !isOldFormatCascade() )
+        {
+            numStages = data.stages.size();
+        }
+        else
+        {
+            numStages = this->oldCascade->count;
+        }
+        return numStages;
+    }
+    void setNumStages(int stageCount)
+    {
+        if( !isOldFormatCascade() )
+        {
+            if( stageCount )
+                data.stages.resize(stageCount);
+        }
+        else
+            if( stageCount )
+                this->oldCascade->count = stageCount;
+    }
+//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
 };
 
 //////////////// HOG (Histogram-of-Oriented-Gradients) Descriptor and Object Detector //////////////
@@ -438,23 +506,38 @@ public:
     CV_WRAP virtual bool load(const String& filename, const String& objname=String());
     CV_WRAP virtual void save(const String& filename, const String& objname=String()) const;
     virtual void copyTo(HOGDescriptor& c) const;
-    
+
     CV_WRAP virtual void compute(const Mat& img,
                          CV_OUT vector<float>& descriptors,
                          Size winStride=Size(), Size padding=Size(),
                          const vector<Point>& locations=vector<Point>()) const;
+       //with found weights output
+    CV_WRAP virtual void detect(const Mat& img, CV_OUT vector<Point>& foundLocations, 
+                                               vector<double>& weights,
+                        double hitThreshold=0, Size winStride=Size(), 
+                                               Size padding=Size(),
+                        const vector<Point>& searchLocations=vector<Point>()) const;
+       //without found weights output
     CV_WRAP virtual void detect(const Mat& img, CV_OUT vector<Point>& foundLocations,
                         double hitThreshold=0, Size winStride=Size(),
                         Size padding=Size(),
                         const vector<Point>& searchLocations=vector<Point>()) const;
-    CV_WRAP virtual void detectMultiScale(const Mat& img, CV_OUT vector<Rect>& foundLocations,
-                                  double hitThreshold=0, Size winStride=Size(),
-                                  Size padding=Size(), double scale=1.05,
-                                  int groupThreshold=2) const;
+       //with result weights output
+    CV_WRAP virtual void detectMultiScale(const Mat& img, CV_OUT vector<Rect>& foundLocations, 
+                                                                 vector<double>& foundWeights, double hitThreshold=0, 
+                                                                 Size winStride=Size(), Size padding=Size(), double scale=1.05, 
+                                                                 double finalThreshold=2.0,bool useMeanshiftGrouping = false) const;
+       //without found weights output
+       CV_WRAP virtual void detectMultiScale(const Mat& img, CV_OUT vector<Rect>& foundLocations, 
+                                                                 double hitThreshold=0, Size winStride=Size(),
+                                  Size padding=Size(), double scale=1.05, 
+                                                                 double finalThreshold=2.0, bool useMeanshiftGrouping = false) const;
+
     CV_WRAP virtual void computeGradient(const Mat& img, CV_OUT Mat& grad, CV_OUT Mat& angleOfs,
                                  Size paddingTL=Size(), Size paddingBR=Size()) const;
     
     static vector<float> getDefaultPeopleDetector();
+       static vector<float> getDaimlerPeopleDetector();
     
     CV_PROP Size winSize;
     CV_PROP Size blockSize;
index 4e18c2d..04fed1a 100644 (file)
@@ -63,7 +63,7 @@ public:
 };    
     
 
-static void groupRectangles(vector<Rect>& rectList, int groupThreshold, double eps, vector<int>* weights)
+static void groupRectangles(vector<Rect>& rectList, int groupThreshold, double eps, vector<int>* weights, vector<double>* foundWeights)
 {
     if( groupThreshold <= 0 || rectList.empty() )
     {
@@ -82,6 +82,7 @@ static void groupRectangles(vector<Rect>& rectList, int groupThreshold, double e
     
     vector<Rect> rrects(nclasses);
     vector<int> rweights(nclasses, 0);
+       vector<double> outWeights(nclasses, 0.0);
     int i, j, nlabels = (int)labels.size();
     for( i = 0; i < nlabels; i++ )
     {
@@ -92,6 +93,14 @@ static void groupRectangles(vector<Rect>& rectList, int groupThreshold, double e
         rrects[cls].height += rectList[i].height;
         rweights[cls]++;
     }
+       if ( foundWeights && !foundWeights->empty() )
+       {
+               for( i = 0; i < nlabels; i++ )
+               {
+                       int cls = labels[i];
+                       outWeights[cls] = outWeights[cls] + (*foundWeights)[i];
+               }
+       }
     
     for( i = 0; i < nclasses; i++ )
     {
@@ -106,11 +115,14 @@ static void groupRectangles(vector<Rect>& rectList, int groupThreshold, double e
     rectList.clear();
     if( weights )
         weights->clear();
+       if( foundWeights )
+               foundWeights->clear();
     
     for( i = 0; i < nclasses; i++ )
     {
         Rect r1 = rrects[i];
         int n1 = rweights[i];
+               double w1 = outWeights[i];
         if( n1 <= groupThreshold )
             continue;
         // filter out small face rectangles inside large rectangles
@@ -139,19 +151,76 @@ static void groupRectangles(vector<Rect>& rectList, int groupThreshold, double e
             rectList.push_back(r1);
             if( weights )
                 weights->push_back(n1);
+                       if( foundWeights )
+                               foundWeights->push_back(w1);
         }
     }
 }
 
+//new grouping function with using meanshift
+static void groupRectangles_meanshift(vector<Rect>& rectList, double detectThreshold, vector<double>* foundWeights, 
+                                                                         vector<double>& scales, Size winDetSize)
+{
+    int detectionCount = rectList.size();
+    vector<Point3d> hits(detectionCount), resultHits;
+    vector<double> hitWeights(detectionCount), resultWeights;
+    Point2d hitCenter;
+
+    for (int i=0; i < detectionCount; i++) 
+    {
+        hitWeights[i] = (*foundWeights)[i];
+        hitCenter = (rectList[i].tl() + rectList[i].br())*(0.5); //center of rectangles
+        hits[i] = Point3d(hitCenter.x, hitCenter.y, std::log(scales[i]));
+    }
+
+    rectList.clear();
+    if (foundWeights)
+        foundWeights->clear();
+
+    double logZ = std::log(1.3);
+    Point3d smothing(8, 16, logZ);
+
+    MeanshiftGrouping msGrouping(smothing, hits, hitWeights, 1e-5, 100);
+
+    msGrouping.getModes(resultHits, resultWeights, 1);
+
+    for (unsigned i=0; i < resultHits.size(); ++i) 
+    {
+
+        double scale = exp(resultHits[i].z);
+        hitCenter.x = resultHits[i].x;
+        hitCenter.y = resultHits[i].y;
+        Size s( int(winDetSize.width * scale), int(winDetSize.height * scale) );
+        Rect resultRect( int(hitCenter.x-s.width/2), int(hitCenter.y-s.height/2), 
+            int(s.width), int(s.height) ); 
+
+        if (resultWeights[i] > detectThreshold) 
+        {
+            rectList.push_back(resultRect);
+            foundWeights->push_back(resultWeights[i]);
+        }
+    }
+}
 
 void groupRectangles(vector<Rect>& rectList, int groupThreshold, double eps)
 {
-    groupRectangles(rectList, groupThreshold, eps, 0);
+    groupRectangles(rectList, groupThreshold, eps, 0, 0);
 }
-    
+
 void groupRectangles(vector<Rect>& rectList, vector<int>& weights, int groupThreshold, double eps)
 {
-    groupRectangles(rectList, groupThreshold, eps, &weights);
+    groupRectangles(rectList, groupThreshold, eps, &weights, 0);
+}
+
+void groupRectangles(vector<Rect>& rectList, vector<double>& foundWeights, int groupThreshold, double eps)
+{
+    groupRectangles(rectList, groupThreshold, eps, 0, &foundWeights);
+}
+
+void groupRectangles_meanshift(vector<Rect>& rectList, vector<double>& foundWeights, 
+                                                          vector<double>& foundScales, double detectThreshold, Size winDetSize)
+{
+       groupRectangles_meanshift(rectList, detectThreshold, &foundWeights, foundScales, winDetSize);
 }
 
     
@@ -802,7 +871,8 @@ bool CascadeClassifier::setImage( Ptr<FeatureEvaluator>& featureEvaluator, const
 
 struct CascadeClassifierInvoker
 {
-    CascadeClassifierInvoker( CascadeClassifier& _cc, Size _sz1, int _stripSize, int _yStep, double _factor, ConcurrentRectVector& _vec )
+    CascadeClassifierInvoker( CascadeClassifier& _cc, Size _sz1, int _stripSize, int _yStep, double _factor, 
+        ConcurrentRectVector& _vec, vector<int>& _levels, bool outputLevels = false  )
     {
         classifier = &_cc;
         processingRectSize = _sz1;
@@ -810,6 +880,7 @@ struct CascadeClassifierInvoker
         yStep = _yStep;
         scalingFactor = _factor;
         rectangles = &_vec;
+        rejectLevels  = outputLevels ? &_levels : 0;
     }
     
     void operator()(const BlockedRange& range) const
@@ -824,7 +895,17 @@ struct CascadeClassifierInvoker
             for( int x = 0; x < processingRectSize.width; x += yStep )
             {
                 int result = classifier->runAt(evaluator, Point(x, y));
-                if( result > 0 )
+                if( rejectLevels )
+                {
+                    if( result == 1 )
+                        result =  -1*classifier->data.stages.size();
+                    if( classifier->data.stages.size() + result < 6 )
+                    {
+                        rectangles->push_back(Rect(cvRound(x*scalingFactor), cvRound(y*scalingFactor), winSize.width, winSize.height)); 
+                        rejectLevels->push_back(-result);
+                    }
+                }                    
+                else if( result > 0 )
                     rectangles->push_back(Rect(cvRound(x*scalingFactor), cvRound(y*scalingFactor),
                                                winSize.width, winSize.height));
                 if( result == 0 )
@@ -838,18 +919,31 @@ struct CascadeClassifierInvoker
     Size processingRectSize;
     int stripSize, yStep;
     double scalingFactor;
+    vector<int> *rejectLevels;
 };
     
 struct getRect { Rect operator ()(const CvAvgComp& e) const { return e.rect; } };
 
 bool CascadeClassifier::detectSingleScale( const Mat& image, int stripCount, Size processingRectSize,
-                                           int stripSize, int yStep, double factor, vector<Rect>& candidates )
+                                           int stripSize, int yStep, double factor, vector<Rect>& candidates,
+                                           bool outputRejectLevels, vector<int>& levels )
 {
     if( !featureEvaluator->setImage( image, data.origWinSize ) )
         return false;
 
     ConcurrentRectVector concurrentCandidates;
-    parallel_for(BlockedRange(0, stripCount), CascadeClassifierInvoker( *this, processingRectSize, stripSize, yStep, factor, concurrentCandidates));
+    vector<int> rejectLevels;
+    if( outputRejectLevels )
+    {
+        parallel_for(BlockedRange(0, stripCount), CascadeClassifierInvoker( *this, processingRectSize, stripSize, yStep, factor,
+            concurrentCandidates, rejectLevels, true));
+        levels.insert( levels.end(), rejectLevels.begin(), rejectLevels.end() );
+    }
+    else
+    {
+         parallel_for(BlockedRange(0, stripCount), CascadeClassifierInvoker( *this, processingRectSize, stripSize, yStep, factor,
+            concurrentCandidates, rejectLevels, false));
+    }
     candidates.insert( candidates.end(), concurrentCandidates.begin(), concurrentCandidates.end() );
 
     return true;
@@ -877,7 +971,8 @@ bool CascadeClassifier::setImage(const Mat& image)
 
 void CascadeClassifier::detectMultiScale( const Mat& image, vector<Rect>& objects,
                                           double scaleFactor, int minNeighbors,
-                                          int flags, Size minObjectSize, Size maxObjectSize )
+                                          int flags, Size minObjectSize, Size maxObjectSize, 
+                                          bool outputRejectLevels, vector<int>& rejectLevels )
 {
     const double GROUP_EPS = 0.2;
     
@@ -946,14 +1041,16 @@ void CascadeClassifier::detectMultiScale( const Mat& image, vector<Rect>& object
         stripSize = processingRectSize.height;
     #endif
 
-        if( !detectSingleScale( scaledImage, stripCount, processingRectSize, stripSize, yStep, factor, candidates ) )
+        if( !detectSingleScale( scaledImage, stripCount, processingRectSize, stripSize, yStep, factor, candidates, 
+            outputRejectLevels, rejectLevels ) )
             break;
     }
 
     objects.resize(candidates.size());
     std::copy(candidates.begin(), candidates.end(), objects.begin());
 
-    groupRectangles( objects, minNeighbors, GROUP_EPS );
+
+    groupRectangles( objects, rejectLevels, minNeighbors, GROUP_EPS );
 }    
 
 bool CascadeClassifier::Data::read(const FileNode &root)
index 09ab7a8..b79c92a 100644 (file)
@@ -852,7 +852,7 @@ void HOGDescriptor::compute(const Mat& img, vector<float>& descriptors,
 
 
 void HOGDescriptor::detect(const Mat& img,
-    vector<Point>& hits, double hitThreshold,
+    vector<Point>& hits, vector<double>& weights, double hitThreshold, 
     Size winStride, Size padding, const vector<Point>& locations) const
 {
     hits.clear();
@@ -923,16 +923,26 @@ void HOGDescriptor::detect(const Mat& img,
 #endif
         }
         if( s >= hitThreshold )
+        {
             hits.push_back(pt0);
+            weights.push_back(s);
+        }
     }
 }
 
+void HOGDescriptor::detect(const Mat& img, vector<Point>& hits, double hitThreshold, 
+                           Size winStride, Size padding, const vector<Point>& locations) const
+{
+    vector<double> weightsV;
+    detect(img, hits, weightsV, hitThreshold, winStride, padding, locations);
+}
 
 struct HOGInvoker
 {
     HOGInvoker( const HOGDescriptor* _hog, const Mat& _img,
                 double _hitThreshold, Size _winStride, Size _padding,
-                const double* _levelScale, ConcurrentRectVector* _vec ) 
+                const double* _levelScale, ConcurrentRectVector* _vec, 
+                vector<double>* _weights=0, vector<double>* _scales=0 ) 
     {
         hog = _hog;
         img = _img;
@@ -941,6 +951,8 @@ struct HOGInvoker
         padding = _padding;
         levelScale = _levelScale;
         vec = _vec;
+        weights = _weights;
+        scales = _scales;
     }
 
     void operator()( const BlockedRange& range ) const
@@ -950,6 +962,7 @@ struct HOGInvoker
         Size maxSz(cvCeil(img.cols/minScale), cvCeil(img.rows/minScale));
         Mat smallerImgBuf(maxSz, img.type());
         vector<Point> locations;
+        vector<double> hitsWeights;
 
         for( i = i1; i < i2; i++ )
         {
@@ -960,12 +973,25 @@ struct HOGInvoker
                 smallerImg = Mat(sz, img.type(), img.data, img.step);
             else
                 resize(img, smallerImg, sz);
-            hog->detect(smallerImg, locations, hitThreshold, winStride, padding);
+            hog->detect(smallerImg, locations, hitsWeights, hitThreshold, winStride, padding);
             Size scaledWinSize = Size(cvRound(hog->winSize.width*scale), cvRound(hog->winSize.height*scale));
             for( size_t j = 0; j < locations.size(); j++ )
+            {
                 vec->push_back(Rect(cvRound(locations[j].x*scale),
                                     cvRound(locations[j].y*scale),
                                     scaledWinSize.width, scaledWinSize.height));
+                if (scales) {
+                    scales->push_back(scale);
+                }
+            }
+            
+            if (weights && (!hitsWeights.empty()))
+            {
+                for (size_t j = 0; j < locations.size(); j++)
+                {
+                    weights->push_back(hitsWeights[j]);
+                }
+            }        
         }
     }
 
@@ -976,13 +1002,15 @@ struct HOGInvoker
     Size padding;
     const double* levelScale;
     ConcurrentRectVector* vec;
+    vector<double>* weights;
+    vector<double>* scales;
 };
 
 
 void HOGDescriptor::detectMultiScale(
-    const Mat& img, vector<Rect>& foundLocations,
+    const Mat& img, vector<Rect>& foundLocations, vector<double>& foundWeights,
     double hitThreshold, Size winStride, Size padding,
-    double scale0, int groupThreshold) const
+    double scale0, double finalThreshold, bool useMeanshiftGrouping) const  
 {
     double scale = 1.;
     int levels = 0;
@@ -1002,15 +1030,32 @@ void HOGDescriptor::detectMultiScale(
 
     ConcurrentRectVector allCandidates;
 
+    vector<double> foundScales;
+    
     parallel_for(BlockedRange(0, (int)levelScale.size()),
-                 HOGInvoker(this, img, hitThreshold, winStride, padding, &levelScale[0], &allCandidates));
+                 HOGInvoker(this, img, hitThreshold, winStride, padding, &levelScale[0], &allCandidates, &foundWeights, &foundScales));
 
     foundLocations.resize(allCandidates.size());
     std::copy(allCandidates.begin(), allCandidates.end(), foundLocations.begin());
 
-    groupRectangles(foundLocations, groupThreshold, 0.2);
+    if ( useMeanshiftGrouping )
+    {
+        groupRectangles_meanshift(foundLocations, foundWeights, foundScales, finalThreshold, winSize);
+    }
+    else
+    {
+        groupRectangles(foundLocations, (int)finalThreshold, 0.2);
+    }
 }
 
+void HOGDescriptor::detectMultiScale(const Mat& img, vector<Rect>& foundLocations, 
+                                     double hitThreshold, Size winStride, Size padding,
+                                     double scale0, double finalThreshold, bool useMeanshiftGrouping) const  
+{
+    vector<double> foundWeights;
+    detectMultiScale(img, foundLocations, foundWeights, hitThreshold, winStride, 
+                     padding, scale0, finalThreshold, useMeanshiftGrouping);
+}
 
 typedef RTTIImpl<HOGDescriptor> HOGRTTI;
 
@@ -1827,5 +1872,508 @@ vector<float> HOGDescriptor::getDefaultPeopleDetector()
        -0.02411991f, -0.04229729f, 0.10666174f, -6.66579151f };
     return vector<float>(detector, detector + sizeof(detector)/sizeof(detector[0]));
 }
+//This function renurn 1981 SVM coeffs obtained from daimler's base. 
+//To use these coeffs the detection window size should be (48,96)  
+vector<float> HOGDescriptor::getDaimlerPeopleDetector()
+{
+    static const float detector[] = {
+        0.294350f, -0.098796f, -0.129522f, 0.078753f,
+        0.387527f, 0.261529f, 0.145939f, 0.061520f,
+        0.328699f, 0.227148f, -0.066467f, -0.086723f,
+        0.047559f, 0.106714f, 0.037897f, 0.111461f,
+        -0.024406f, 0.304769f, 0.254676f, -0.069235f,
+        0.082566f, 0.147260f, 0.326969f, 0.148888f,
+        0.055270f, -0.087985f, 0.261720f, 0.143442f,
+        0.026812f, 0.238212f, 0.194020f, 0.056341f,
+        -0.025854f, -0.034444f, -0.156631f, 0.205174f,
+        0.089008f, -0.139811f, -0.100147f, -0.037830f,
+        -0.029230f, -0.055641f, 0.033248f, -0.016512f,
+        0.155244f, 0.247315f, -0.124694f, -0.048414f,
+        -0.062219f, 0.193683f, 0.004574f, 0.055089f,
+        0.093565f, 0.167712f, 0.167581f, 0.018895f,
+        0.215258f, 0.122609f, 0.090520f, -0.067219f,
+        -0.049029f, -0.099615f, 0.241804f, -0.094893f,
+        -0.176248f, 0.001727f, -0.134473f, 0.104442f,
+        0.050942f, 0.081165f, 0.072156f, 0.121646f,
+        0.002656f, -0.297974f, -0.133587f, -0.060121f,
+        -0.092515f, -0.048974f, -0.084754f, -0.180111f,
+        -0.038590f, 0.086283f, -0.134636f, -0.107249f,
+        0.132890f, 0.141556f, 0.249425f, 0.130273f,
+        -0.030031f, 0.073212f, -0.008155f, 0.019931f,
+        0.071688f, 0.000300f, -0.019525f, -0.021725f,
+        -0.040993f, -0.086841f, 0.070124f, 0.240033f,
+        0.265350f, 0.043208f, 0.166754f, 0.091453f,
+        0.060916f, -0.036972f, -0.091043f, 0.079873f,
+        0.219781f, 0.158102f, -0.140618f, -0.043016f,
+        0.124802f, 0.093668f, 0.103208f, 0.094872f,
+        0.080541f, 0.137711f, 0.160566f, -0.169231f,
+        0.013983f, 0.309508f, -0.004217f, -0.057200f,
+        -0.064489f, 0.014066f, 0.361009f, 0.251328f,
+        -0.080983f, -0.044183f, 0.061436f, -0.037381f,
+        -0.078786f, 0.030993f, 0.066314f, 0.037683f,
+        0.152325f, -0.091683f, 0.070203f, 0.217856f,
+        0.036435f, -0.076462f, 0.006254f, -0.094431f,
+        0.154829f, -0.023038f, -0.196961f, -0.024594f,
+        0.178465f, -0.050139f, -0.045932f, -0.000965f,
+        0.109112f, 0.046165f, -0.159373f, -0.008713f,
+        0.041307f, 0.097129f, -0.057211f, -0.064599f,
+        0.077165f, 0.176167f, 0.138322f, 0.065753f,
+        -0.104950f, 0.017933f, 0.136255f, -0.011598f,
+        0.047007f, 0.080550f, 0.068619f, 0.084661f,
+        -0.035493f, -0.091314f, -0.041411f, 0.060971f,
+        -0.101912f, -0.079870f, -0.085977f, -0.022686f,
+        0.079788f, -0.098064f, -0.054603f, 0.040383f,
+        0.300794f, 0.128603f, 0.094844f, 0.047407f,
+        0.101825f, 0.061832f, -0.162160f, -0.204553f,
+        -0.035165f, 0.101450f, -0.016641f, -0.027140f,
+        -0.134392f, -0.008743f, 0.102331f, 0.114853f,
+        0.009644f, 0.062823f, 0.237339f, 0.167843f,
+        0.053066f, -0.012592f, 0.043158f, 0.002305f,
+        0.065001f, -0.038929f, -0.020356f, 0.152343f,
+        0.043469f, -0.029967f, -0.042948f, 0.032481f,
+        0.068488f, -0.110840f, -0.111083f, 0.111980f,
+        -0.002072f, -0.005562f, 0.082926f, 0.006635f,
+        -0.108153f, 0.024242f, -0.086464f, -0.189884f,
+        -0.017492f, 0.191456f, -0.007683f, -0.128769f,
+        -0.038017f, -0.132380f, 0.091926f, 0.079696f,
+        -0.106728f, -0.007656f, 0.172744f, 0.011576f,
+        0.009883f, 0.083258f, -0.026516f, 0.145534f,
+        0.153924f, -0.130290f, -0.108945f, 0.124490f,
+        -0.003186f, -0.100485f, 0.015024f, -0.060512f,
+        0.026288f, -0.086713f, -0.169012f, 0.076517f,
+        0.215778f, 0.043701f, -0.131642f, -0.012585f,
+        -0.045181f, -0.118183f, -0.241544f, -0.167293f,
+        -0.020107f, -0.019917f, -0.101827f, -0.107096f,
+        -0.010503f, 0.044938f, 0.189680f, 0.217119f,
+        -0.046086f, 0.044508f, 0.199716f, -0.036004f,
+        -0.148927f, 0.013355f, -0.078279f, 0.030451f,
+        0.056301f, -0.024609f, 0.083224f, 0.099533f,
+        -0.039432f, -0.138880f, 0.005482f, -0.024120f,
+        -0.140468f, -0.066381f, -0.017057f, 0.009260f,
+        -0.058004f, -0.028486f, -0.061610f, 0.007483f,
+        -0.158309f, -0.150687f, -0.044595f, -0.105121f,
+        -0.045763f, -0.006618f, -0.024419f, -0.117713f,
+        -0.119366f, -0.175941f, -0.071542f, 0.119027f,
+        0.111362f, 0.043080f, 0.034889f, 0.093003f,
+        0.007842f, 0.057368f, -0.108834f, -0.079968f,
+        0.230959f, 0.020205f, 0.011470f, 0.098877f,
+        0.101310f, -0.030215f, -0.018018f, -0.059552f,
+        -0.106157f, 0.021866f, -0.036471f, 0.080051f,
+        0.041165f, -0.082101f, 0.117726f, 0.030961f,
+        -0.054763f, -0.084102f, -0.185778f, -0.061305f,
+        -0.038089f, -0.110728f, -0.264010f, 0.076675f,
+        -0.077111f, -0.137644f, 0.036232f, 0.277995f,
+        0.019116f, 0.107738f, 0.144003f, 0.080304f,
+        0.215036f, 0.228897f, 0.072713f, 0.077773f,
+        0.120168f, 0.075324f, 0.062730f, 0.122478f,
+        -0.049008f, 0.164912f, 0.162450f, 0.041246f,
+        0.009891f, -0.097827f, -0.038700f, -0.023027f,
+        -0.120020f, 0.203364f, 0.248474f, 0.149810f,
+        -0.036276f, -0.082814f, -0.090343f, -0.027143f,
+        -0.075689f, -0.320310f, -0.000500f, -0.143334f,
+        -0.065077f, -0.186936f, 0.129372f, 0.116431f,
+        0.181699f, 0.170436f, 0.418854f, 0.460045f,
+        0.333719f, 0.230515f, 0.047822f, -0.044954f,
+        -0.068086f, 0.140179f, -0.044821f, 0.085550f,
+        0.092483f, -0.107296f, -0.130670f, -0.206629f,
+        0.114601f, -0.317869f, -0.076663f, 0.038680f,
+        0.212753f, -0.016059f, -0.126526f, -0.163602f,
+        0.210154f, 0.099887f, -0.126366f, 0.118453f,
+        0.019309f, -0.021611f, -0.096499f, -0.111809f,
+        -0.200489f, 0.142854f, 0.228840f, -0.353346f,
+        -0.179151f, 0.116834f, 0.252389f, -0.031728f,
+        -0.188135f, -0.158998f, 0.386523f, 0.122315f,
+        0.209944f, 0.394023f, 0.359030f, 0.260717f,
+        0.170335f, 0.013683f, -0.142596f, -0.026138f,
+        -0.011878f, -0.150519f, 0.047159f, -0.107062f,
+        -0.147347f, -0.187689f, -0.186027f, -0.208048f,
+        0.058468f, -0.073026f, -0.236556f, -0.079788f,
+        -0.146216f, -0.058563f, -0.101361f, -0.071294f,
+        -0.071093f, 0.116919f, 0.234304f, 0.306781f,
+        0.321866f, 0.240000f, 0.073261f, -0.012173f,
+        0.026479f, 0.050173f, 0.166127f, 0.228955f,
+        0.061905f, 0.156460f, 0.205990f, 0.120672f,
+        0.037350f, 0.167884f, 0.290099f, 0.420900f,
+        -0.012601f, 0.189839f, 0.306378f, 0.118383f,
+        -0.095598f, -0.072360f, -0.132496f, -0.224259f,
+        -0.126021f, 0.022714f, 0.284039f, 0.051369f,
+        -0.000927f, -0.058735f, -0.083354f, -0.141254f,
+        -0.187578f, -0.202669f, 0.048902f, 0.246597f,
+        0.441863f, 0.342519f, 0.066979f, 0.215286f,
+        0.188191f, -0.072240f, -0.208142f, -0.030196f,
+        0.178141f, 0.136985f, -0.043374f, -0.181098f,
+        0.091815f, 0.116177f, -0.126690f, -0.386625f,
+        0.368165f, 0.269149f, -0.088042f, -0.028823f,
+        0.092961f, 0.024099f, 0.046112f, 0.176756f,
+        0.135849f, 0.124955f, 0.195467f, -0.037218f,
+        0.167217f, 0.188938f, 0.053528f, -0.066561f,
+        0.133721f, -0.070565f, 0.115898f, 0.152435f,
+        -0.116993f, -0.110592f, -0.179005f, 0.026668f,
+        0.080530f, 0.075084f, -0.070401f, 0.012497f,
+        0.021849f, -0.139764f, -0.022020f, -0.096301f,
+        -0.064954f, -0.127446f, -0.013806f, -0.108315f,
+        0.156285f, 0.149867f, -0.011382f, 0.064532f,
+        0.029168f, 0.027393f, 0.069716f, 0.153735f,
+        0.038459f, 0.230714f, 0.253840f, 0.059522f,
+        -0.045053f, 0.014083f, 0.071103f, 0.068747f,
+        0.095887f, 0.005832f, 0.144887f, 0.026357f,
+        -0.067359f, -0.044151f, -0.123283f, -0.019911f,
+        0.005318f, 0.109208f, -0.003201f, -0.021734f,
+        0.142025f, -0.066907f, -0.120070f, -0.188639f,
+        0.012472f, -0.048704f, -0.012366f, -0.184828f,
+        0.168591f, 0.267166f, 0.058208f, -0.044101f,
+        0.033500f, 0.178558f, 0.104550f, 0.122418f,
+        0.080177f, 0.173246f, 0.298537f, 0.064173f,
+        0.053397f, 0.174341f, 0.230984f, 0.117025f,
+        0.166242f, 0.227781f, 0.120623f, 0.176952f,
+        -0.011393f, -0.086483f, -0.008270f, 0.051700f,
+        -0.153369f, -0.058837f, -0.057639f, -0.060115f,
+        0.026349f, -0.160745f, -0.037894f, -0.048575f,
+        0.041052f, -0.022112f, 0.060365f, 0.051906f,
+        0.162657f, 0.138519f, -0.050185f, -0.005938f,
+        0.071301f, 0.127686f, 0.062342f, 0.144400f,
+        0.072600f, 0.198436f, 0.246219f, -0.078185f,
+        -0.036169f, 0.075934f, 0.047328f, -0.013601f,
+        0.087205f, 0.019900f, 0.022606f, -0.015365f,
+        -0.092506f, 0.075275f, -0.116375f, 0.050500f,
+        0.045118f, 0.166567f, 0.072073f, 0.060371f,
+        0.131747f, -0.169863f, -0.039352f, -0.047486f,
+        -0.039797f, -0.204312f, 0.021710f, 0.129443f,
+        -0.021173f, 0.173416f, -0.070794f, -0.063986f,
+        0.069689f, -0.064099f, -0.123201f, -0.017372f,
+        -0.206870f, 0.065863f, 0.113226f, 0.024707f,
+        -0.071341f, -0.066964f, -0.098278f, -0.062927f,
+        0.075840f, 0.014716f, 0.019378f, 0.132699f,
+        -0.074191f, -0.089557f, -0.078446f, -0.197488f,
+        -0.173665f, 0.052583f, 0.044361f, 0.113549f,
+        0.098492f, 0.077379f, -0.011146f, -0.192593f,
+        -0.164435f, 0.045568f, 0.205699f, 0.049187f,
+        -0.082281f, 0.134874f, 0.185499f, 0.034968f,
+        -0.119561f, -0.112372f, -0.115091f, -0.054042f,
+        -0.183816f, -0.078100f, 0.190695f, 0.091617f,
+        0.004257f, -0.041135f, -0.061453f, -0.141592f,
+        -0.194809f, -0.120638f, 0.020168f, 0.109672f,
+        0.067398f, -0.015238f, -0.239145f, -0.264671f,
+        -0.185176f, 0.050472f, 0.020793f, 0.035678f,
+        0.022839f, -0.052055f, -0.127968f, -0.113049f,
+        -0.228416f, -0.258281f, -0.053437f, 0.076424f,
+        0.061450f, 0.237478f, 0.003618f, -0.055865f,
+        -0.108087f, -0.028937f, 0.045585f, 0.052829f,
+        -0.001471f, 0.022826f, 0.059565f, -0.104430f,
+        -0.077266f, -0.211882f, -0.212078f, 0.028074f,
+        0.075846f, 0.016265f, 0.161879f, 0.134477f,
+        0.008935f, -0.048041f, 0.074692f, 0.004928f,
+        -0.025156f, 0.192874f, 0.074410f, 0.308732f,
+        0.267400f, 0.094208f, -0.005251f, 0.042041f,
+        -0.032148f, 0.015588f, 0.252869f, 0.175302f,
+        0.022892f, 0.081673f, 0.063208f, 0.162626f,
+        0.194426f, 0.233890f, 0.262292f, 0.186930f,
+        0.084079f, -0.286388f, -0.213034f, -0.048867f,
+        -0.207669f, -0.170050f, 0.011673f, -0.092958f,
+        -0.192786f, -0.273536f, 0.230904f, 0.266732f,
+        0.320519f, 0.297155f, 0.548169f, 0.304922f,
+        0.132687f, 0.247333f, 0.212488f, -0.271472f,
+        -0.142105f, -0.002627f, -0.119215f, 0.128383f,
+        0.100079f, -0.057490f, -0.121902f, -0.228892f,
+        0.202292f, -0.399795f, -0.371326f, -0.095836f,
+        -0.063626f, -0.161375f, -0.311180f, -0.294797f,
+        0.242122f, 0.011788f, 0.095573f, 0.322523f,
+        0.511840f, 0.322880f, 0.313259f, 0.173331f,
+        0.002542f, -0.029802f, 0.324766f, -0.326170f,
+        -0.340547f, -0.138288f, -0.002963f, -0.114060f,
+        -0.377312f, -0.442570f, 0.212446f, -0.007759f,
+        -0.011576f, 0.169711f, 0.308689f, 0.317348f,
+        0.539390f, 0.332845f, 0.057331f, -0.068180f,
+        0.101994f, 0.266995f, 0.209570f, 0.355730f,
+        0.091635f, 0.170238f, 0.125215f, 0.274154f,
+        0.070223f, 0.025515f, 0.049946f, -0.000550f,
+        0.043715f, -0.141843f, 0.020844f, 0.129871f,
+        0.256588f, 0.105015f, 0.148339f, 0.170682f,
+        0.028792f, 0.074037f, 0.160042f, 0.405137f,
+        0.246187f, 0.352160f, 0.168951f, 0.222263f,
+        0.264439f, 0.065945f, 0.021963f, -0.075084f,
+        0.093105f, 0.027318f, 0.098864f, 0.057566f,
+        -0.080282f, 0.185032f, 0.314419f, 0.333727f,
+        0.125798f, 0.294919f, 0.386002f, 0.217619f,
+        -0.183517f, -0.278622f, -0.002342f, -0.027821f,
+        -0.134266f, -0.331843f, -0.008296f, 0.124564f,
+        0.053712f, -0.369016f, -0.095036f, 0.209381f,
+        0.423760f, 0.371760f, 0.106397f, 0.369408f,
+        0.485608f, 0.231201f, -0.138685f, -0.349208f,
+        -0.070083f, 0.028991f, -0.081630f, -0.395992f,
+        -0.146791f, -0.027354f, 0.063396f, -0.272484f,
+        0.058299f, 0.338207f, 0.110767f, -0.052642f,
+        -0.233848f, -0.027448f, 0.030328f, 0.155572f,
+        -0.093826f, 0.019331f, 0.120638f, 0.006292f,
+        -0.106083f, -0.236290f, -0.140933f, -0.088067f,
+        -0.025138f, -0.208395f, -0.025502f, 0.144192f,
+        -0.048353f, -0.106144f, -0.305121f, -0.114147f,
+        0.090963f, 0.327727f, 0.035606f, -0.093779f,
+        0.002651f, -0.171081f, -0.188131f, -0.216571f,
+        -0.209101f, -0.054402f, 0.157147f, -0.057127f,
+        0.066584f, 0.008988f, 0.041191f, 0.034456f,
+        -0.078255f, 0.052099f, -0.022239f, 0.066981f,
+        -0.117520f, -0.072637f, 0.062512f, 0.037570f,
+        -0.057544f, -0.312359f, 0.034357f, -0.031549f,
+        0.002566f, -0.207375f, -0.070654f, -0.018786f,
+        -0.044815f, -0.012814f, -0.076320f, 0.078183f,
+        0.023877f, 0.117078f, 0.022292f, -0.205424f,
+        -0.060430f, -0.017296f, -0.004827f, -0.321036f,
+        -0.092155f, 0.038837f, 0.073190f, -0.067513f,
+        0.026521f, 0.171945f, 0.087318f, 0.034495f,
+        -0.034089f, 0.154410f, -0.061431f, 0.007435f,
+        -0.111094f, -0.095976f, 0.014741f, -0.132324f,
+        -0.029517f, -0.192160f, 0.098667f, 0.020762f,
+        0.177050f, -0.064510f, -0.054437f, -0.058678f,
+        -0.001858f, 0.167602f, 0.015735f, 0.054338f,
+        0.016477f, 0.186381f, -0.010667f, 0.054692f,
+        0.126742f, 0.013140f, 0.090353f, -0.133608f,
+        -0.018017f, -0.152619f, 0.027600f, -0.138700f,
+        -0.050274f, 0.045141f, -0.118731f, 0.094797f,
+        -0.167605f, 0.097461f, -0.009131f, 0.199920f,
+        -0.052976f, 0.158194f, 0.178568f, -0.107600f,
+        0.009671f, -0.084072f, -0.040258f, -0.205673f,
+        0.102891f, 0.223511f, 0.042699f, 0.118548f,
+        -0.021274f, 0.110997f, -0.155121f, 0.027696f,
+        -0.149968f, 0.051552f, -0.129219f, 0.173524f,
+        0.073972f, -0.189045f, -0.034523f, -0.106655f,
+        -0.011843f, -0.197381f, 0.219413f, 0.183197f,
+        -0.054920f, 0.144955f, 0.036517f, -0.085412f,
+        -0.229070f, -0.143710f, -0.049486f, 0.156634f,
+        -0.008673f, -0.064778f, 0.082344f, 0.145673f,
+        0.002912f, -0.210121f, -0.116564f, 0.078425f,
+        0.220908f, -0.067594f, 0.048610f, 0.084912f,
+        -0.066202f, -0.112515f, -0.217767f, -0.082640f,
+        -0.017414f, 0.230265f, -0.070735f, 0.066073f,
+        0.215256f, 0.071157f, -0.087220f, -0.202235f,
+        -0.011918f, 0.099562f, 0.174716f, -0.063845f,
+        -0.121055f, 0.014367f, 0.132709f, -0.005060f,
+        -0.244606f, -0.179693f, -0.134690f, 0.023239f,
+        -0.193116f, -0.076975f, -0.021164f, -0.001938f,
+        -0.163799f, -0.111437f, -0.210362f, -0.166376f,
+        0.034754f, 0.010036f, -0.021917f, 0.068014f,
+        -0.086893f, -0.251746f, -0.267171f, 0.037383f,
+        0.003966f, 0.033571f, -0.151506f, 0.025437f,
+        -0.020626f, -0.308454f, -0.343143f, -0.092263f,
+        -0.026261f, -0.028345f, 0.036036f, 0.035169f,
+        0.129470f, 0.122205f, 0.015661f, -0.070612f,
+        -0.094333f, -0.066055f, -0.041083f, 0.159146f,
+        0.073184f, 0.110044f, 0.174471f, 0.078069f,
+        -0.014881f, 0.008116f, 0.013209f, 0.075857f,
+        0.195605f, 0.062714f, 0.067955f, 0.056544f,
+        -0.153908f, -0.141749f, -0.072550f, 0.033523f,
+        -0.024665f, 0.134487f, 0.079076f, 0.133562f,
+        0.227130f, 0.018054f, 0.004928f, 0.169162f,
+        0.065152f, 0.072160f, 0.131631f, 0.096303f,
+        0.054288f, 0.106256f, 0.114632f, 0.119038f,
+        0.515200f, 0.247429f, 0.199134f, 0.211957f,
+        0.127558f, -0.294684f, -0.194890f, -0.049988f,
+        -0.112247f, -0.008122f, -0.006176f, 0.037035f,
+        -0.110881f, -0.249989f, 0.152434f, 0.234621f,
+        0.153340f, 0.349283f, 0.683049f, 0.157174f,
+        0.124844f, 0.099136f, 0.064407f, -0.248400f,
+        -0.155323f, -0.026498f, -0.023450f, 0.049051f,
+        -0.114187f, 0.007195f, -0.176825f, -0.376926f,
+        0.366159f, -0.179938f, -0.148508f, 0.006043f,
+        0.170048f, 0.097866f, -0.102658f, -0.260430f,
+        0.248868f, 0.037019f, -0.118111f, 0.078176f,
+        0.194171f, 0.211328f, 0.368612f, 0.361213f,
+        0.130013f, 0.094650f, 0.227396f, -0.178058f,
+        -0.114782f, -0.008093f, 0.231080f, -0.011843f,
+        -0.097917f, -0.325788f, 0.141879f, 0.119738f,
+        -0.230427f, -0.117419f, -0.114153f, 0.037903f,
+        0.116383f, 0.218773f, -0.101884f, 0.059466f,
+        0.119255f, 0.010874f, -0.031449f, 0.045996f,
+        0.119931f, 0.273760f, 0.311700f, 0.261794f,
+        0.194809f, 0.339829f, 0.239449f, 0.064140f,
+        0.077597f, 0.098996f, 0.143534f, 0.184602f,
+        0.037507f, 0.225494f, 0.096142f, -0.147370f,
+        -0.207833f, -0.174742f, -0.086391f, -0.038942f,
+        0.159577f, -0.088492f, -0.000989f, 0.108154f,
+        -0.025890f, -0.072713f, 0.025997f, -0.006803f,
+        -0.086879f, -0.011290f, -0.269200f, -0.103450f,
+        -0.124910f, -0.116340f, 0.141459f, 0.208800f,
+        0.042268f, 0.265034f, 0.516474f, 0.217591f,
+        -0.018843f, -0.313328f, -0.168363f, 0.047129f,
+        0.090480f, -0.109852f, -0.018761f, 0.210669f,
+        0.281269f, -0.043591f, -0.034147f, -0.237772f,
+        -0.134843f, -0.072481f, -0.103831f, 0.038355f,
+        0.308619f, 0.148023f, -0.045867f, -0.123950f,
+        -0.210860f, -0.064973f, -0.036308f, -0.046731f,
+        -0.022099f, 0.095776f, 0.409423f, 0.060635f,
+        -0.065196f, 0.051828f, 0.027981f, -0.009609f,
+        -0.137681f, -0.095011f, -0.019045f, 0.177278f,
+        0.009759f, -0.092119f, -0.016958f, -0.133860f,
+        -0.118421f, -0.032039f, -0.006214f, -0.084541f,
+        0.063971f, -0.073642f, 0.165676f, 0.110443f,
+        0.044131f, 0.046568f, 0.053292f, -0.055466f,
+        0.015512f, 0.371947f, 0.232102f, -0.016923f,
+        0.103979f, -0.091758f, 0.005907f, 0.209100f,
+        0.157433f, 0.030518f, 0.250366f, 0.062322f,
+        0.036720f, 0.094676f, 0.017306f, -0.010328f,
+        -0.079012f, 0.016781f, -0.112435f, 0.061795f,
+        0.042543f, -0.126799f, -0.009975f, -0.056760f,
+        0.046424f, -0.194712f, -0.139399f, -0.037731f,
+        0.157989f, -0.016261f, 0.123345f, 0.230563f,
+        0.083300f, -0.016392f, 0.059567f, -0.016035f,
+        -0.064767f, 0.231945f, 0.156629f, 0.034602f,
+        0.145628f, 0.041315f, 0.034535f, 0.019967f,
+        -0.089188f, -0.012091f, 0.307857f, 0.211405f,
+        -0.025091f, -0.148249f, -0.129384f, 0.063536f,
+        -0.068603f, -0.067941f, -0.035104f, 0.210832f,
+        0.063810f, 0.062764f, -0.089889f, -0.030554f,
+        0.014791f, -0.053362f, -0.037818f, -0.196640f,
+        0.008388f, -0.082654f, 0.143056f, 0.064221f,
+        0.069795f, 0.191040f, 0.097321f, -0.028679f,
+        0.075794f, 0.313154f, 0.086240f, 0.207643f,
+        0.017809f, 0.122867f, 0.224586f, 0.167403f,
+        -0.023884f, 0.047434f, 0.344091f, 0.187745f,
+        0.136177f, 0.141738f, 0.063799f, 0.045233f,
+        -0.077342f, -0.003525f, -0.165041f, -0.025616f,
+        -0.073745f, 0.164439f, 0.011200f, -0.145896f,
+        -0.027954f, -0.061987f, -0.039874f, -0.142775f,
+        0.151042f, -0.038238f, 0.053152f, 0.078615f,
+        0.086061f, 0.100593f, 0.128046f, -0.071006f,
+        -0.116558f, 0.208445f, 0.051086f, 0.076843f,
+        0.023191f, -0.084781f, -0.011790f, 0.147807f,
+        -0.048554f, -0.113932f, 0.283322f, 0.190934f,
+        0.092789f, 0.033018f, -0.142428f, -0.142480f,
+        -0.099023f, -0.041020f, -0.042760f, 0.203295f,
+        -0.053475f, 0.042424f, 0.222839f, -0.019167f,
+        -0.133176f, -0.276216f, -0.031998f, 0.117290f,
+        0.177827f, -0.059973f, -0.064744f, -0.117040f,
+        -0.155482f, -0.099531f, 0.164121f, -0.026682f,
+        -0.093810f, 0.238993f, -0.006506f, 0.007830f,
+        0.065819f, -0.203643f, -0.100925f, -0.053652f,
+        -0.130770f, 0.026277f, 0.131796f, 0.032742f,
+        0.127186f, 0.116694f, -0.161122f, -0.279773f,
+        -0.252515f, -0.002638f, 0.042812f, 0.096776f,
+        -0.123280f, 0.064858f, -0.010455f, -0.219760f,
+        -0.239331f, -0.104363f, -0.058022f, -0.053584f,
+        0.025611f, 0.005129f, -0.100418f, -0.045712f,
+        -0.194418f, -0.126366f, -0.030530f, 0.051168f,
+        0.215959f, 0.172402f, -0.054700f, -0.185995f,
+        -0.278360f, -0.193693f, -0.040309f, 0.003735f,
+        -0.007770f, 0.123556f, 0.190179f, -0.077315f,
+        0.117403f, 0.212942f, 0.012160f, 0.000113f,
+        0.027331f, 0.040202f, 0.033293f, 0.219438f,
+        0.184174f, 0.259349f, 0.311206f, 0.082547f,
+        -0.047875f, -0.078417f, 0.010746f, 0.082620f,
+        0.311931f, 0.307605f, 0.003863f, 0.021405f,
+        -0.026388f, -0.019572f, 0.020582f, -0.059353f,
+        0.025199f, 0.261319f, 0.086316f, 0.143614f,
+        0.107780f, 0.003900f, -0.188397f, -0.038563f,
+        -0.106045f, -0.125154f, -0.010509f, 0.054021f,
+        0.242130f, 0.279152f, 0.215546f, 0.346995f,
+        0.440856f, 0.237452f, 0.234154f, 0.301646f,
+        0.168929f, -0.208358f, -0.126848f, 0.010260f,
+        0.121018f, -0.062975f, -0.052848f, 0.050341f,
+        -0.061103f, -0.266482f, 0.107186f, 0.140221f,
+        0.280065f, 0.287889f, 0.373198f, 0.151596f,
+        0.013593f, 0.115616f, 0.014616f, -0.281710f,
+        -0.237597f, -0.117305f, -0.000034f, -0.136739f,
+        -0.196275f, -0.095225f, -0.125310f, -0.250514f,
+        0.236804f, -0.071805f, -0.037421f, 0.048230f,
+        0.321596f, 0.063632f, 0.024039f, -0.029133f,
+        0.230983f, 0.160593f, -0.154355f, -0.013086f,
+        -0.079929f, 0.094692f, 0.160391f, 0.180239f,
+        0.053895f, 0.100759f, 0.288631f, 0.038191f,
+        0.181692f, 0.229682f, 0.440166f, 0.063401f,
+        0.006273f, 0.020865f, 0.338695f, 0.256244f,
+        -0.043927f, 0.115617f, 0.003296f, 0.173965f,
+        0.021318f, -0.040936f, -0.118932f, 0.182380f,
+        0.235922f, -0.053233f, -0.015053f, -0.101057f,
+        0.095341f, 0.051111f, 0.161831f, 0.032614f,
+        0.159496f, 0.072375f, 0.025089f, 0.023748f,
+        0.029151f, 0.161284f, -0.117717f, -0.036191f,
+        -0.176822f, -0.162006f, 0.226542f, -0.078329f,
+        0.043079f, -0.119172f, 0.054614f, -0.101365f,
+        -0.064541f, -0.115304f, 0.135170f, 0.298872f,
+        0.098060f, 0.089428f, -0.007497f, 0.110391f,
+        -0.028824f, 0.020835f, -0.036804f, 0.125411f,
+        0.192105f, -0.048931f, 0.003086f, -0.010681f,
+        0.074698f, -0.016263f, 0.096063f, 0.060267f,
+        -0.007277f, 0.139139f, -0.080635f, 0.036628f,
+        0.086058f, 0.131979f, 0.085707f, 0.025301f,
+        0.226094f, 0.194759f, 0.042193f, -0.157846f,
+        -0.068402f, -0.141450f, -0.112659f, -0.076305f,
+        -0.069085f, -0.114332f, -0.102005f, 0.132193f,
+        -0.067042f, 0.106643f, 0.198964f, 0.171616f,
+        0.167237f, -0.033730f, -0.026755f, 0.083621f,
+        0.149459f, -0.002799f, -0.000318f, 0.011753f,
+        0.065889f, -0.089375f, -0.049610f, 0.224579f,
+        0.216548f, -0.034908f, -0.017851f, -0.088144f,
+        0.007530f, 0.240268f, 0.073270f, 0.013263f,
+        0.175323f, 0.012082f, 0.093993f, 0.015282f,
+        0.105854f, 0.107990f, 0.077798f, -0.096166f,
+        -0.079607f, 0.177820f, 0.142392f, 0.033337f,
+        -0.078100f, -0.081616f, -0.046993f, 0.139459f,
+        0.020272f, -0.123161f, 0.175269f, 0.105217f,
+        0.057328f, 0.080909f, -0.012612f, -0.097081f,
+        0.082060f, -0.096716f, -0.063921f, 0.201884f,
+        0.128166f, -0.035051f, -0.032227f, -0.068139f,
+        -0.115915f, 0.095080f, -0.086007f, -0.067543f,
+        0.030776f, 0.032712f, 0.088937f, 0.054336f,
+        -0.039329f, -0.114022f, 0.171672f, -0.112321f,
+        -0.217646f, 0.065186f, 0.060223f, 0.192174f,
+        0.055580f, -0.131107f, -0.144338f, 0.056730f,
+        -0.034707f, -0.081616f, -0.135298f, -0.000614f,
+        0.087189f, 0.014614f, 0.067709f, 0.107689f,
+        0.225780f, 0.084361f, -0.008544f, 0.051649f,
+        -0.048369f, -0.037739f, -0.060710f, 0.002654f,
+        0.016935f, 0.085563f, -0.015961f, -0.019265f,
+        0.111788f, 0.062376f, 0.202019f, 0.047713f,
+        0.042261f, 0.069716f, 0.242913f, 0.021052f,
+        -0.072812f, -0.155920f, -0.026436f, 0.035621f,
+        -0.079300f, -0.028787f, -0.048329f, 0.084718f,
+        -0.060565f, -0.083750f, -0.164075f, -0.040742f,
+        -0.086219f, 0.015271f, -0.005204f, -0.016038f,
+        0.045816f, -0.050433f, -0.077652f, 0.117109f,
+        0.009611f, -0.009045f, -0.008634f, -0.055373f,
+        -0.085968f, 0.028527f, -0.054736f, -0.168089f,
+        0.175839f, 0.071205f, -0.023603f, 0.037907f,
+        -0.004561f, -0.022634f, 0.123831f, 0.094469f,
+        -0.072920f, -0.133642f, -0.014032f, -0.142754f,
+        -0.026999f, -0.199409f, 0.013268f, 0.226989f,
+        0.048650f, -0.170988f, -0.050141f, 0.007880f,
+        0.061880f, 0.019078f, -0.043578f, -0.038139f,
+        0.134814f, 0.054097f, -0.081670f, 0.176838f,
+        0.047920f, -0.038176f, 0.050406f, -0.107181f,
+        -0.036279f, 0.027060f, 0.081594f, -0.002820f,
+        0.090507f, -0.033338f, -0.059571f, 0.013404f,
+        -0.099860f, 0.073371f, 0.342805f, 0.098305f,
+        -0.150910f, -0.020822f, -0.056960f, 0.046262f,
+        -0.043413f, -0.149405f, -0.129105f, -0.010899f,
+        -0.014229f, -0.179949f, -0.113044f, -0.049468f,
+        -0.065513f, 0.090269f, -0.011919f, 0.087846f,
+        0.095796f, 0.146127f, 0.101599f, 0.078066f,
+        -0.084348f, -0.100002f, -0.020134f, -0.050169f,
+        0.062122f, 0.014640f, 0.019143f, 0.036543f,
+        0.180924f, -0.013976f, -0.066768f, -0.001090f,
+        -0.070419f, -0.004839f, -0.001504f, 0.034483f,
+        -0.044954f, -0.050336f, -0.088638f, -0.174782f,
+        -0.116082f, -0.205507f, 0.015587f, -0.042839f,
+        -0.096879f, -0.144097f, -0.050268f, -0.196796f,
+        0.109639f, 0.271411f, 0.173732f, 0.108070f,
+        0.156437f, 0.124255f, 0.097242f, 0.238693f,
+        0.083941f, 0.109105f, 0.223940f, 0.267188f,
+        0.027385f, 0.025819f, 0.125070f, 0.093738f,
+        0.040353f, 0.038645f, -0.012730f, 0.144063f,
+        0.052931f, -0.009138f, 0.084193f, 0.160272f,
+        -0.041366f, 0.011951f, -0.121446f, -0.106713f,
+        -0.047566f, 0.047984f, -0.255224f, -0.076116f,
+        0.098685f, -0.150845f, -0.171513f, -0.156590f,
+        0.058331f, 0.187493f, 0.413018f, 0.554265f,
+        0.372242f, 0.237943f, 0.124571f, 0.110829f,
+        0.010322f, -0.174477f, -0.067627f, -0.001979f,
+        0.142913f, 0.040597f, 0.019907f, 0.025963f,
+        -0.043585f, -0.120732f, 0.099937f, 0.091059f,
+        0.247307f, 0.204226f, -0.042753f, -0.068580f,
+        -0.119002f, 0.026722f, 0.034853f, -0.060934f,
+        -0.025054f, -0.093026f, -0.035372f, -0.233209f,
+        -0.049869f, -0.039151f, -0.022279f, -0.065380f,
+        -9.063785f};
+        return vector<float>(detector, detector + sizeof(detector)/sizeof(detector[0]));
+}
 
 }
diff --git a/modules/objdetect/src/ms_grouping.cpp b/modules/objdetect/src/ms_grouping.cpp
new file mode 100644 (file)
index 0000000..0a5000b
--- /dev/null
@@ -0,0 +1,171 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////\r
+//\r
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.\r
+//\r
+//  By downloading, copying, installing or using the software you agree to this license.\r
+//  If you do not agree to this license, do not download, install,\r
+//  copy or use the software.\r
+//\r
+//\r
+//                          License Agreement\r
+//                For Open Source Computer Vision Library\r
+//\r
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.\r
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.\r
+// Third party copyrights are property of their respective owners.\r
+//\r
+// Redistribution and use in source and binary forms, with or without modification,\r
+// are permitted provided that the following conditions are met:\r
+//\r
+//   * Redistribution's of source code must retain the above copyright notice,\r
+//     this list of conditions and the following disclaimer.\r
+//\r
+//   * Redistribution's in binary form must reproduce the above copyright notice,\r
+//     this list of conditions and the following disclaimer in the documentation\r
+//     and/or other materials provided with the distribution.\r
+//\r
+//   * The name of the copyright holders may not be used to endorse or promote products\r
+//     derived from this software without specific prior written permission.\r
+//\r
+// This software is provided by the copyright holders and contributors "as is" and\r
+// any express or implied warranties, including, but not limited to, the implied\r
+// warranties of merchantability and fitness for a particular purpose are disclaimed.\r
+// In no event shall the Intel Corporation or contributors be liable for any direct,\r
+// indirect, incidental, special, exemplary, or consequential damages\r
+// (including, but not limited to, procurement of substitute goods or services;\r
+// loss of use, data, or profits; or business interruption) however caused\r
+// and on any theory of liability, whether in contract, strict liability,\r
+// or tort (including negligence or otherwise) arising in any way out of\r
+// the use of this software, even if advised of the possibility of such damage.\r
+//\r
+//M*/\r
+\r
+#include "precomp.hpp"\r
+using namespace cv;\r
+\r
+MeanshiftGrouping::MeanshiftGrouping(const Point3d& densKer, const vector<Point3d>& posV, \r
+                                        const vector<double>& wV, double modeEps, int maxIter):\r
+       densityKernel(densKer), weightsV(wV), positionsV(posV), positionsCount(posV.size()),\r
+       meanshiftV(positionsCount), distanceV(positionsCount), modeEps(modeEps),\r
+       iterMax (maxIter)\r
+{\r
+       for (unsigned i=0; i<positionsV.size(); i++)\r
+       {\r
+               meanshiftV[i] = getNewValue(positionsV[i]);\r
+\r
+               distanceV[i] = moveToMode(meanshiftV[i]);\r
+\r
+               meanshiftV[i] -= positionsV[i];\r
+       }\r
+}\r
+\r
+void MeanshiftGrouping::getModes(vector<Point3d>& modesV, vector<double>& resWeightsV, double eps)\r
+{\r
+       for (size_t i=0; i <distanceV.size(); i++)\r
+       {\r
+               bool is_found = false;\r
+               for(size_t j=0; j<modesV.size(); j++)\r
+               {\r
+                       if ( getDistance(distanceV[i], modesV[j]) < eps)\r
+                       {\r
+                               is_found=true;\r
+                               break;\r
+                       }\r
+               }\r
+               if (!is_found)\r
+               {\r
+                       modesV.push_back(distanceV[i]);\r
+               }\r
+       }\r
+       \r
+       resWeightsV.resize(modesV.size());\r
+\r
+       for (size_t i=0; i<modesV.size(); i++)\r
+       {\r
+               resWeightsV[i] = getResultWeight(modesV[i]);\r
+       }\r
+}\r
+\r
+Point3d MeanshiftGrouping::moveToMode(Point3d aPt) const\r
+{\r
+       Point3d bPt;\r
+       for (int i = 0; i<iterMax; i++)\r
+       {\r
+               bPt = aPt;\r
+               aPt = getNewValue(bPt);\r
+               if ( getDistance(aPt, bPt) <= modeEps )\r
+               {\r
+                       break;\r
+               }\r
+       }\r
+       return aPt;\r
+}\r
+\r
+Point3d MeanshiftGrouping::getNewValue(const Point3d& inPt) const\r
+{\r
+       Point3d resPoint(.0);\r
+       Point3d ratPoint(.0);\r
+       for (size_t i=0; i<positionsV.size(); i++)\r
+       {\r
+               Point3d aPt= positionsV[i];\r
+               Point3d bPt = inPt;\r
+               Point3d sPt = densityKernel;\r
+               \r
+               sPt.x *= exp(aPt.z);\r
+               sPt.y *= exp(aPt.z);\r
+               \r
+               aPt.x /= sPt.x;\r
+               aPt.y /= sPt.y;\r
+               aPt.z /= sPt.z;\r
+\r
+               bPt.x /= sPt.x;\r
+               bPt.y /= sPt.y;\r
+               bPt.z /= sPt.z;\r
+               \r
+               double w = (weightsV[i])*std::exp(-((aPt-bPt).dot(aPt-bPt))/2)/std::sqrt(sPt.dot(Point3d(1,1,1)));\r
+               \r
+               resPoint += w*aPt;\r
+\r
+               ratPoint.x += w/sPt.x;\r
+               ratPoint.y += w/sPt.y;\r
+               ratPoint.z += w/sPt.z;\r
+       }\r
+       resPoint.x /= ratPoint.x;\r
+       resPoint.y /= ratPoint.y;\r
+       resPoint.z /= ratPoint.z;\r
+       return resPoint;\r
+} \r
+\r
+double MeanshiftGrouping::getResultWeight(const Point3d& inPt) const\r
+{\r
+       double sumW=0;\r
+       for (size_t i=0; i<positionsV.size(); i++)\r
+       {\r
+               Point3d aPt = positionsV[i];\r
+               Point3d sPt = densityKernel;\r
+\r
+               sPt.x *= exp(aPt.z);\r
+               sPt.y *= exp(aPt.z);\r
+\r
+               aPt -= inPt;\r
+               \r
+               aPt.x /= sPt.x;\r
+               aPt.y /= sPt.y;\r
+               aPt.z /= sPt.z;\r
+               \r
+               sumW+=(weightsV[i])*std::exp(-(aPt.dot(aPt))/2)/std::sqrt(sPt.dot(Point3d(1,1,1)));\r
+       }\r
+       return sumW;\r
+}\r
+\r
+double MeanshiftGrouping::getDistance(Point3d p1, Point3d p2) const \r
+{\r
+       Point3d ns = densityKernel;\r
+       ns.x *= exp(p2.z);\r
+       ns.y *= exp(p2.z);\r
+       p2 -= p1;\r
+       p2.x /= ns.x;\r
+       p2.y /= ns.y;\r
+       p2.z /= ns.z;\r
+       return p2.dot(p2);\r
+}\r