转载: 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

ORB原理与源码解析的更多相关文章

  1. 机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理、源码解析及测试

    机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理.源码解析及测试 关键字:决策树.python.源码解析.测试作者:米仓山下时间:2018-10-2 ...

  2. Spring-Session实现Session共享实现原理以及源码解析

    知其然,还要知其所以然 ! 本篇介绍Spring-Session的整个实现的原理.以及对核心的源码进行简单的介绍! 实现原理介绍 实现原理这里简单说明描述: 就是当Web服务器接收到http请求后,当 ...

  3. Spring MVC工作原理及源码解析(三) HandlerMapping和HandlerAdapter实现原理及源码解析

    1.HandlerMapping实现原理及源码解析 在前面讲解Spring MVC工作流程的时候我们说过,前端控制器收到请求后会调⽤处理器映射器(HandlerMapping),处理器映射器根据请求U ...

  4. Redux异步解决方案之Redux-Thunk原理及源码解析

    前段时间,我们写了一篇Redux源码分析的文章,也分析了跟React连接的库React-Redux的源码实现.但是在Redux的生态中还有一个很重要的部分没有涉及到,那就是Redux的异步解决方案.本 ...

  5. LinkedList原理及源码解析

    简介 LinkedList是一个双向线性链表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer).由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度, ...

  6. Spring核心框架 - AOP的原理及源码解析

    一.AOP的体系结构 如下图所示:(引自AOP联盟) 层次3语言和开发环境:基础是指待增加对象或者目标对象:切面通常包括对于基础的增加应用:配置是指AOP体系中提供的配置环境或者编织配置,通过该配置A ...

  7. 【Spring】Spring IOC原理及源码解析之scope=request、session

    一.容器 1. 容器 抛出一个议点:BeanFactory是IOC容器,而ApplicationContex则是Spring容器. 什么是容器?Collection和Container这两个单词都有存 ...

  8. RocketMQ原理及源码解析

    RocketMQ原理深入: 一.定义: RocketMQ是一款分布式.队列模型的消息中间件,有以下部分组成: 1.NameServer: 一个几乎无状态的节点,可集群部署,节点之间无任何信息同步 2. ...

  9. Go中定时器实现原理及源码解析

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com 本文使用的go的源码15.7,需要注意的是由于timer是1.14版本进行改版,但是1. ...

随机推荐

  1. mysql 伪列

    select  @rownum:=@rownum+1 AS rownum,b.* from (SELECT @rownum:=0) r ,goods_description_new  b

  2. openssl在多平台和多语言之间进行RSA加解密注意事项

    首先说一下平台和语言: 系统平台为CentOS6.3,RSA加解密时使用NOPADDING进行填充 1)使用C/C++调用系统自带的openssl 2)Android4.2模拟器,第三方openssl ...

  3. chattr和lsattr命令详解

    基础命令学习目录首页 原文链接:http://www.ha97.com/5172.html PS:有时候你发现用root权限都不能修改某个文件,大部分原因是曾经用chattr命令锁定该文件了.chat ...

  4. 随手记录-linux-常用命令

    转自:https://www.cnblogs.com/yjd_hycf_space/p/7730690.html linux目录结构:http://www.cnblogs.com/fat39/p/72 ...

  5. Django_rest_framework_组件(authentication、permission、throttle)

    认证组件 说明 from rest_framework.authentication import BaseAuthentication class TestAuthentication(BaseAu ...

  6. Scrum Meeting 报告

    Scrum Meeting 报告 ----团队项目所需时间估计以及任务分配 由于能力有限,我们还不能构架好一个大框架.但是初步可以完成任务的流程和分配.任务所需要的具体实现可以参看<学霸系统的N ...

  7. python处理xml实例

    """ Author = zyh FileName = read_xml_1.py Time = 18-9-26 下午5:19 """ fr ...

  8. 关于注册github

  9. WCF 和 ASP.NET Web API

    地址:https://docs.microsoft.com/zh-cn/dotnet/framework/wcf/wcf-and-aspnet-web-api WCF 是 Microsoft 为生成面 ...

  10. 树莓派与Arduino Leonardo使用NRF24L01无线模块通信之基于RF24库 (一) 配置与测试

    引脚连接说明 与树莓派的连线 NRF24L01 => 树莓派 GND          =>   GND VCC          =>    3.3V CE           = ...