ORB原理與源碼解析


轉載: http://blog.csdn.net/luoshixian099/article/details/48523267

CSDN-勿在浮沙築高台

 沒有時間重新復制代碼,只能一股腦的復制,所以代碼效果不好。。。。。。

   為了滿足實時性的要求,前面文章中介紹過快速提取特征點算法Fast,以及特征描述子Brief。本篇文章介紹的ORB算法結合了Fast和Brief的速度優勢,並做了改進,且ORB是免費。

   Ethan Rublee等人2011年在《ORB:An Efficient Alternative to SIFT or SURF》文章中提出了ORB算法。結合Fast與Brief算法,並給Fast特征點增加了方向性,使得特征點具有旋轉不變性,並提出了構造金字塔方法,解決尺度不變性,但文章中沒有具體詳述。實驗證明,ORB遠優於之前的SIFT與SURF算法。

-------------------------------------------------------------------------------------------------------------------------------

論文核心內容概述:

1.構造金字塔,在每層金字塔上采用Fast算法提取特征點,采用Harris角點響應函數,按角點響應值排序,選取前N個特征點。

2. oFast:計算每個特征點的主方向,灰度質心法,計算特征點半徑為r的圓形鄰域范圍內的灰度質心位置。從中心位置到質心位置的向量,定義為該特 征點的主方向。

  定義矩的計算公式,x,y∈[-r,r]:

                                 

             質心位置:

                               

               主方向:

                                  

3.rBrief:為了解決旋轉不變性,把特征點的Patch旋轉到主方向上(steered Brief)。通過實驗得到,描述子在各個維度上的均值比較離散(偏離0.5),同時維度間相關性很強,說明特征點描述子區分性不好,影響匹配的效果。論文中提出采取學習的方法,采用300K個訓練樣本點。每一個特征點,選取Patch大小為wp=31,Patch內每對點都采用wt=5大小的子窗口灰度均值做比較,子窗口的個數即為N=(wp-wt)*(wp-wt),從N個窗口中隨機選兩個做比較即構成描述子的一個bit,論文中采用M=205590種可能的情況:   

       ---------------------------------------------------------------------------------

        1.對所有樣本點,做M種測試,構成M維的描述子,每個維度上非1即0;

        2.按均值對M個維度排序(以0.5為中心),組成向量T;

        3.貪婪搜索:把向量T中第一個元素移動到R中,然后繼續取T的第二個元素,與R中的所有元素做相關性比較,如果相關性大於指定的閾值Threshold,           拋棄T的這個元素,否則加入到R中;

        4.重復第3個步驟,直到R中有256個元素,若檢測完畢,少於256個元素,則降低閾值,重復上述步驟;

       ----------------------------------------------------------------------------------

    rBrief:通過上面的步驟取到的256對點,構成的描述子各維度間相關性很低,區分性好;

                                        

                                              訓練前                                            訓練后

---------------------------------------------------------------------------------------------------------------------------------

ORB算法步驟,參考opencv源碼:

1.首先構造尺度金字塔;

   金字塔共n層,與SIFT不同,每層僅有一副圖像;

   第s層的尺度為,Fator初始尺度(默認為1.2),原圖在第0層;

   第s層圖像大小:

                              

2.在不同尺度上采用Fast檢測特征點;在每一層上按公式計算需要提取的特征點數n,在本層上按Fast角點響應值排序,提取前2n個特征點,然后根據Harris   角點響應值排序, 取前n個特征點,作為本層的特征點;

3.計算每個特征點的主方向(質心法);

4.旋轉每個特征點的Patch到主方向,采用上述步驟3的選取的最優的256對特征點做τ測試,構成256維描述子,占32個字節;

                   ,,n=256


4.采用漢明距離做特征點匹配;


----------OpenCV源碼解析-------------------------------------------------------

ORB類定義:位置..\features2d.hpp

nfeatures:需要的特征點總數;

scaleFactor:尺度因子;

nlevels:金字塔層數;

edgeThreshold:邊界閾值;

firstLevel:起始層;

 WTA_K:描述子形成方法,WTA_K=2表示,采用兩兩比較;

 scoreType:角點響應函數,可以選擇Harris或者Fast的方法;

 patchSize:特征點鄰域大小;

 

[cpp] 
 

/*! 

  •   
  •  CV_EXPORTS_W ORB :  Feature2D  
  • {  
  • :  
  •       
  •      { kBytes = 32, HARRIS_SCORE=0, FAST_SCORE=1 };  
  •   
  •     CV_WRAP  ORB( nfeatures = 500,  scaleFactor = 1.2f,  nlevels = 8,  edgeThreshold = 31,  
  •          firstLevel = 0,  WTA_K=2,  scoreType=ORB::HARRIS_SCORE,  patchSize=31 );  
  •   
  •       
  •      descriptorSize() ;     
  •       
  •      descriptorType() ;  
  •   
  •       
  •      operator()(InputArray image, InputArray mask, vector<KeyPoint>& keypoints) ;  
  •   
  •       
  •      operator()( InputArray image, InputArray mask, vector<KeyPoint>& keypoints,      
  •                      OutputArray descriptors,  useProvidedKeypoints= ) ;  
  •   
  •     AlgorithmInfo* info() ;  
  •   
  • :  
  •   
  •      computeImpl(  Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors ) ;  
  •      detectImpl(  Mat& image, vector<KeyPoint>& keypoints,  Mat& mask=Mat() ) ;  
  •   
  •     CV_PROP_RW  nfeatures;  
  •     CV_PROP_RW  scaleFactor;  
  •     CV_PROP_RW  nlevels;  
  •     CV_PROP_RW  edgeThreshold;  
  •     CV_PROP_RW  firstLevel;  
  •     CV_PROP_RW  WTA_K;  
  •     CV_PROP_RW  scoreType;  
  •     CV_PROP_RW  patchSize;  
  • };  

 

特征提取及形成描述子:通過這個函數對圖像提取Fast特征點或者計算特征描述子

_image:輸入圖像;

_mask:掩碼圖像;

_keypoints:輸入角點;

_descriptors:如果為空,只尋找特征點,不計算特征描述子;

_useProvidedKeypoints:如果為true,函數只計算特征描述子;

 /** Compute the ORB features and descriptors on an image 

  •  * @param keypoints the resulting keypoints 
  •  * @param do_keypoints if true, the keypoints are computed, otherwise used as an input 
  •  */ ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _keypoints,  
  •                       OutputArray _descriptors,  useProvidedKeypoints)   
  • {  
  •     CV_Assert(patchSize >= 2);  
  •   
  •      do_keypoints = !useProvidedKeypoints;  
  •      do_descriptors = _descriptors.needed();  
  •   
  •     ( (!do_keypoints && !do_descriptors) || _image.empty() )  
  •         ;  
  •   
  •       
  •       HARRIS_BLOCK_SIZE = 9;  
  •      halfPatchSize = patchSize / 2;.  
  •      border = std::max(edgeThreshold, std::max(halfPatchSize, HARRIS_BLOCK_SIZE/2))+1;  
  •   
  •     Mat image = _image.getMat(), mask = _mask.getMat();  
  •     ( image.type() != CV_8UC1 )  
  •         cvtColor(_image, image, CV_BGR2GRAY);  
  •   
  •      levelsNum = ->nlevels;  
  •   
  •     ( !do_keypoints )     
  •     {  
  •           
  •           
  •           
  •           
  •           
  •           
  •           
  •           
  •           
  •         levelsNum = 0;  
  •          i = 0; i < _keypoints.size(); i++ )  
  •             levelsNum = std::max(levelsNum, std::max(_keypoints[i].octave, 0));  
  •         levelsNum++;  
  •     }  
  •   
  •       
  •     vector<Mat> imagePyramid(levelsNum), maskPyramid(levelsNum);  
  •      ( level = 0; level < levelsNum; ++level)  
  •     {  
  •          scale = 1/getScale(level, firstLevel, scaleFactor);    
  •                  static inline float getScale(int level, int firstLevel, double scaleFactor) 
  •                    return (float)std::pow(scaleFactor, (double)(level - firstLevel)); 
  •         */        Size sz(cvRound(image.cols*scale), cvRound(image.rows*scale));  
  •         Size wholeSize(sz.width + border*2, sz.height + border*2);  
  •         Mat temp(wholeSize, image.type()), masktemp;  
  •         imagePyramid[level] = temp(Rect(border, border, sz.width, sz.height));  
  •         ( !mask.empty() )  
  •         {  
  •             masktemp = Mat(wholeSize, mask.type());  
  •             maskPyramid[level] = masktemp(Rect(border, border, sz.width, sz.height));  
  •         }  
  •   
  •           
  •         ( level != firstLevel )      
  •         {  
  •             ( level < firstLevel )  
  •             {  
  •                 resize(image, imagePyramid[level], sz, 0, 0, INTER_LINEAR);  
  •                  (!mask.empty())  
  •                     resize(mask, maskPyramid[level], sz, 0, 0, INTER_LINEAR);  
  •             }  
  •               
  •             {  
  •                 resize(imagePyramid[level-1], imagePyramid[level], sz, 0, 0, INTER_LINEAR);  
  •                  (!mask.empty())  
  •                 {  
  •                     resize(maskPyramid[level-1], maskPyramid[level], sz, 0, 0, INTER_LINEAR);  
  •                     threshold(maskPyramid[level], maskPyramid[level], 254, 0, THRESH_TOZERO);  
  •                 }  
  •             }  
  •   
  •             copyMakeBorder(imagePyramid[level], temp, border, border, border, border,  
  •                            BORDER_REFLECT_101+BORDER_ISOLATED);  
  •              (!mask.empty())  
  •                 copyMakeBorder(maskPyramid[level], masktemp, border, border, border, border,  
  •                                BORDER_CONSTANT+BORDER_ISOLATED);  
  •         }  
  •           
  •         {  
  •             copyMakeBorder(image, temp, border, border, border, border,  
  •                            BORDER_REFLECT_101);  
  •             ( !mask.empty() )  
  •                 copyMakeBorder(mask, masktemp, border, border, border, border,  
  •                                BORDER_CONSTANT+BORDER_ISOLATED);  
  •         }  
  •     }  
  •   
  •       
  •     vector < vector<KeyPoint> > allKeypoints;  
  •     ( do_keypoints )  
  •     {  
  •           
  •         computeKeyPoints(imagePyramid, maskPyramid, allKeypoints,    
  •                          nfeatures, firstLevel, scaleFactor,  
  •                          edgeThreshold, patchSize, scoreType);  
  •   
  •           
  •                  for (int level = 0; level < n_levels; ++level) 
  •             vector<KeyPoint>& keypoints = all_keypoints[level]; 
  •             keypoints.clear(); 
  •  
  •  
  •              keypoint_end = temp.end(); keypoint != keypoint_end; ++keypoint) 
  •   
  •     }  
  •         
  •     {  
  •           
  •         KeyPointsFilter::runByImageBorder(_keypoints, image.size(), edgeThreshold);  
  •   
  •           
  •         allKeypoints.resize(levelsNum);  
  •          (vector<KeyPoint>::iterator keypoint = _keypoints.begin(),  
  •              keypointEnd = _keypoints.end(); keypoint != keypointEnd; ++keypoint)  
  •             allKeypoints[keypoint->octave].push_back(*keypoint);      
  •   
  •           
  •          ( level = 0; level < levelsNum; ++level)     
  •         {  
  •              (level == firstLevel)  
  •                 ;  
  •   
  •             vector<KeyPoint> & keypoints = allKeypoints[level];  
  •              scale = 1/getScale(level, firstLevel, scaleFactor);  
  •              (vector<KeyPoint>::iterator keypoint = keypoints.begin(),  
  •                  keypointEnd = keypoints.end(); keypoint != keypointEnd; ++keypoint)  
  •                 keypoint->pt *= scale;     
  •         }  
  •     }  
  •   
  •     Mat descriptors;          
  •     vector<Point> pattern;  
  •   
  •     ( do_descriptors )   
  •     {  
  •          nkeypoints = 0;  
  •          ( level = 0; level < levelsNum; ++level)  
  •             nkeypoints += ()allKeypoints[level].size();  
  •         ( nkeypoints == 0 )  
  •             _descriptors.release();  
  •           
  •         {  
  •             _descriptors.create(nkeypoints, descriptorSize(), CV_8U);  
  •             descriptors = _descriptors.getMat();  
  •         }  
  •   
  •           npoints = 512;  
  •         Point patternbuf[npoints];  
  •          Point* pattern0 = ( Point*)bit_pattern_31_;  
  •   
  •         ( patchSize != 31 )  
  •         {  
  •             pattern0 = patternbuf;  
  •             makeRandomPattern(patchSize, patternbuf, npoints);  
  •         }  
  •   
  •         CV_Assert( WTA_K == 2 || WTA_K == 3 || WTA_K == 4 );  
  •   
  •         ( WTA_K == 2 )    
  •             std::copy(pattern0, pattern0 + npoints, std::back_inserter(pattern));  
  •           
  •         {  
  •              ntuples = descriptorSize()*4;  
  •             initializeOrbPattern(pattern0, pattern, ntuples, WTA_K, npoints);  
  •         }  
  •     }  
  •   
  •     _keypoints.clear();  
  •      offset = 0;  
  •      ( level = 0; level < levelsNum; ++level)  
  •     {  
  •           
  •         vector<KeyPoint>& keypoints = allKeypoints[level];  
  •          nkeypoints = ()keypoints.size();  
  •   
  •           
  •          (do_descriptors)  
  •         {  
  •             Mat desc;  
  •              (!descriptors.empty())  
  •             {  
  •                 desc = descriptors.rowRange(offset, offset + nkeypoints);  
  •             }  
  •   
  •             offset += nkeypoints;    
  •               
  •             Mat& workingMat = imagePyramid[level];  
  •               
  •             GaussianBlur(workingMat, workingMat, Size(7, 7), 2, 2, BORDER_REFLECT_101);  
  •             computeDescriptors(workingMat, keypoints, desc, pattern, descriptorSize(), WTA_K);  
  •         }  
  •   
  •           
  •          (level != firstLevel)    
  •         {  
  •              scale = getScale(level, firstLevel, scaleFactor);  
  •              (vector<KeyPoint>::iterator keypoint = keypoints.begin(),  
  •                  keypointEnd = keypoints.end(); keypoint != keypointEnd; ++keypoint)  
  •                 keypoint->pt *= scale;   
  •         }  
  •           
  •         _keypoints.insert(_keypoints.end(), keypoints.begin(), keypoints.end());  
  •     }  
  • }  

(1)提取角點:computeKeyPoints

imagePyramid:即構造好的金字塔

 /** Compute the ORB keypoints on an image 

  •  * @param keypoints the resulting keypoints, clustered per level 
  •   
  •   computeKeyPoints( vector<Mat>& imagePyramid,  
  •                               vector<Mat>& maskPyramid,  
  •                              vector<vector<KeyPoint> >& allKeypoints,  
  •                               nfeatures,  firstLevel,  scaleFactor,  
  •                               edgeThreshold,  patchSize,  scoreType )  
  • {  
  •      nlevels = ()imagePyramid.size();    
  •     vector<> nfeaturesPerLevel(nlevels);  
  •   
  •       
  •      factor = ()(1.0 / scaleFactor);  
  •      ndesiredFeaturesPerScale = nfeatures*(1 - factor)/(1 - ()pow(()factor, ()nlevels));  
  •   
  •      sumFeatures = 0;  
  •      level = 0; level < nlevels-1; level++ )     
  •     {  
  •         nfeaturesPerLevel[level] = cvRound(ndesiredFeaturesPerScale);  
  •         sumFeatures += nfeaturesPerLevel[level];  
  •         ndesiredFeaturesPerScale *= factor;  
  •     }  
  •     nfeaturesPerLevel[nlevels-1] = std::max(nfeatures - sumFeatures, 0);  
  •   
  •       
  •       
  •   
  •       
  •      halfPatchSize = patchSize / 2;             
  •     vector<> umax(halfPatchSize + 2);  
  •      v, v0, vmax = cvFloor(halfPatchSize * sqrt(2.f) / 2 + 1);  
  •      vmin = cvCeil(halfPatchSize * sqrt(2.f) / 2);  
  •      (v = 0; v <= vmax; ++v)             
  •         umax[v] = cvRound(sqrt(()halfPatchSize * halfPatchSize - v * v));  
  •       
  •      (v = halfPatchSize, v0 = 0; v >= vmin; --v)  
  •     {  
  •          (umax[v0] == umax[v0 + 1])  
  •             ++v0;  
  •         umax[v] = v0;  
  •            ++v0;  
  •     }  
  •   
  •     allKeypoints.resize(nlevels);  
  •   
  •      ( level = 0; level < nlevels; ++level)  
  •     {  
  •          featuresNum = nfeaturesPerLevel[level];  
  •         allKeypoints[level].reserve(featuresNum*2);  
  •   
  •         vector<KeyPoint> & keypoints = allKeypoints[level];  
  •   
  •           
  •         FastFeatureDetector fd(20, );        
  •         fd.detect(imagePyramid[level], keypoints, maskPyramid[level]);  
  •   
  •           
  •         KeyPointsFilter::runByImageBorder(keypoints, imagePyramid[level].size(), edgeThreshold);  
  •   
  •         ( scoreType == ORB::HARRIS_SCORE )  
  •         {  
  •               
  •             KeyPointsFilter::retainBest(keypoints, 2 * featuresNum);  
  •   
  •               
  •             HarrisResponses(imagePyramid[level], keypoints, 7, HARRIS_K);   
  •         }  
  •   
  •           
  •         KeyPointsFilter::retainBest(keypoints, featuresNum);  
  •   
  •          sf = getScale(level, firstLevel, scaleFactor);  
  •   
  •           
  •          (vector<KeyPoint>::iterator keypoint = keypoints.begin(),  
  •              keypointEnd = keypoints.end(); keypoint != keypointEnd; ++keypoint)  
  •         {  
  •             keypoint->octave = level;    
  •             keypoint->size = patchSize*sf;   
  •         }  
  •   
  •         computeOrientation(imagePyramid[level], keypoints, halfPatchSize, umax);    
  •     }  
  • }  

(2)為每個角點計算主方向,質心法;

 static computeOrientation( Mat& image, vector<KeyPoint>& keypoints,  

  •                                 halfPatchSize,  vector<>& umax)  
  • {  
  •       
  •      (vector<KeyPoint>::iterator keypoint = keypoints.begin(),    
  •          keypointEnd = keypoints.end(); keypoint != keypointEnd; ++keypoint)  
  •     {  
  •         keypoint->angle = IC_Angle(image, halfPatchSize, keypoint->pt, umax);  
  •     }  
  • }  

 static IC_Angle( Mat& image,   half_k, Point2f pt,  

  •                        vector<> & u_max)  
  • {  
  •      m_01 = 0, m_10 = 0;  
  •   
  •      uchar* center = &image.at<uchar> (cvRound(pt.y), cvRound(pt.x));  
  •   
  •       
  •      ( u = -half_k; u <= half_k; ++u)  
  •         m_10 += u * center[u];  
  •   
  •       
  •      step = ()image.step1();  
  •      ( v = 1; v <= half_k; ++v)      
  •     {  
  •           
  •          v_sum = 0;  
  •          d = u_max[v];  
  •          ( u = -d; u <= d; ++u)  
  •         {  
  •              val_plus = center[u + v*step], val_minus = center[u - v*step];  
  •             v_sum += (val_plus - val_minus);   
  •             m_10 += u * (val_plus + val_minus);  
  •         }  
  •         m_01 += v * v_sum;  
  •     }  
  •   
  •      fastAtan2(()m_01, ()m_10);  
  • }  

(3)計算特征點描述子

 static computeDescriptors( Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors,  

  •                                 vector<Point>& pattern,  dsize,  WTA_K)  
  • {  
  •       
  •     CV_Assert(image.type() == CV_8UC1);  
  •       
  •     descriptors = Mat::zeros(()keypoints.size(), dsize, CV_8UC1);  
  •   
  •      ( i = 0; i < keypoints.size(); i++)  
  •         computeOrbDescriptor(keypoints[i], image, &pattern[0], descriptors.ptr(()i), dsize, WTA_K);  
  • }  

 static computeOrbDescriptor( KeyPoint& kpt,  

  •                                   Mat& img,  Point* pattern,  
  •                                  uchar* desc,  dsize,  WTA_K)  
  • {  
  •      angle = kpt.angle;   
  •       
  •     angle *= ()(CV_PI/180.f);  
  •      a = ()cos(angle), b = ()sin(angle);  
  •   
  •      uchar* center = &img.at<uchar>(cvRound(kpt.pt.y), cvRound(kpt.pt.x));  
  •      step = ()img.step;  
  •   
  •   
  •   
  •         center[cvRound(pattern[idx].x*b + pattern[idx].y*a)*step + \  
  •                cvRound(pattern[idx].x*a - pattern[idx].y*b)]  
  •   
  •      x, y;  
  •      ix, iy;  
  •   
  •         (x = pattern[idx].x*a - pattern[idx].y*b, \  
  •         y = pattern[idx].x*b + pattern[idx].y*a, \  
  •         ix = cvFloor(x), iy = cvFloor(y), \  
  •         x -= ix, y -= iy, \  
  •         cvRound(center[iy*step + ix]*(1-x)*(1-y) + center[(iy+1)*step + ix]*(1-x)*y + \  
  •                 center[iy*step + ix+1]*x*(1-y) + center[(iy+1)*step + ix+1]*x*y))  
  •   
  •   
  •     ( WTA_K == 2 )  
  •     {  
  •          ( i = 0; i < dsize; ++i, pattern += 16)  
  •         {  
  •              t0, t1, val;  
  •             t0 = GET_VALUE(0); t1 = GET_VALUE(1);  
  •             val = t0 < t1;  
  •             t0 = GET_VALUE(2); t1 = GET_VALUE(3);  
  •             val |= (t0 < t1) << 1;  
  •             t0 = GET_VALUE(4); t1 = GET_VALUE(5);  
  •             val |= (t0 < t1) << 2;  
  •             t0 = GET_VALUE(6); t1 = GET_VALUE(7);  
  •             val |= (t0 < t1) << 3;  
  •             t0 = GET_VALUE(8); t1 = GET_VALUE(9);  
  •             val |= (t0 < t1) << 4;  
  •             t0 = GET_VALUE(10); t1 = GET_VALUE(11);  
  •             val |= (t0 < t1) << 5;  
  •             t0 = GET_VALUE(12); t1 = GET_VALUE(13);  
  •             val |= (t0 < t1) << 6;  
  •             t0 = GET_VALUE(14); t1 = GET_VALUE(15);  
  •             val |= (t0 < t1) << 7;  
  •   
  •             desc[i] = (uchar)val;  
  •         }  
  •     }  
  •      ( WTA_K == 3 )  
  •     {  
  •          ( i = 0; i < dsize; ++i, pattern += 12)  
  •         {  
  •              t0, t1, t2, val;  
  •             t0 = GET_VALUE(0); t1 = GET_VALUE(1); t2 = GET_VALUE(2);  
  •             val = t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0);  
  •   
  •             t0 = GET_VALUE(3); t1 = GET_VALUE(4); t2 = GET_VALUE(5);  
  •             val |= (t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0)) << 2;  
  •   
  •             t0 = GET_VALUE(6); t1 = GET_VALUE(7); t2 = GET_VALUE(8);  
  •             val |= (t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0)) << 4;  
  •   
  •             t0 = GET_VALUE(9); t1 = GET_VALUE(10); t2 = GET_VALUE(11);  
  •             val |= (t2 > t1 ? (t2 > t0 ? 2 : 0) : (t1 > t0)) << 6;  
  •   
  •             desc[i] = (uchar)val;  
  •         }  
  •     }  
  •      ( WTA_K == 4 )  
  •     {  
  •          ( i = 0; i < dsize; ++i, pattern += 16)  
  •         {  
  •              t0, t1, t2, t3, u, v, k, val;  
  •             t0 = GET_VALUE(0); t1 = GET_VALUE(1);  
  •             t2 = GET_VALUE(2); t3 = GET_VALUE(3);  
  •             u = 0, v = 2;  
  •             ( t1 > t0 ) t0 = t1, u = 1;  
  •             ( t3 > t2 ) t2 = t3, v = 3;  
  •             k = t0 > t2 ? u : v;  
  •             val = k;  
  •   
  •             t0 = GET_VALUE(4); t1 = GET_VALUE(5);  
  •             t2 = GET_VALUE(6); t3 = GET_VALUE(7);  
  •             u = 0, v = 2;  
  •             ( t1 > t0 ) t0 = t1, u = 1;  
  •             ( t3 > t2 ) t2 = t3, v = 3;  
  •             k = t0 > t2 ? u : v;  
  •             val |= k << 2;  
  •   
  •             t0 = GET_VALUE(8); t1 = GET_VALUE(9);  
  •             t2 = GET_VALUE(10); t3 = GET_VALUE(11);  
  •             u = 0, v = 2;  
  •             ( t1 > t0 ) t0 = t1, u = 1;  
  •             ( t3 > t2 ) t2 = t3, v = 3;  
  •             k = t0 > t2 ? u : v;  
  •             val |= k << 4;  
  •   
  •             t0 = GET_VALUE(12); t1 = GET_VALUE(13);  
  •             t2 = GET_VALUE(14); t3 = GET_VALUE(15);  
  •             u = 0, v = 2;  
  •             ( t1 > t0 ) t0 = t1, u = 1;  
  •             ( t3 > t2 ) t2 = t3, v = 3;  
  •             k = t0 > t2 ? u : v;  
  •             val |= k << 6;  
  •   
  •             desc[i] = (uchar)val;  
  •         }  
  •     }  
  •       
  •         CV_Error( CV_StsBadSize,    

  •  

 

 

 

 

參考:

Ethan Rublee et. ORB:An Efficient Alternative to SIFT or SURF

http://www.cnblogs.com/ronny/p/4083537.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM