|
|
|
@ -53,31 +53,31 @@ static void |
|
|
|
|
HarrisResponses(const Mat& img, vector<KeyPoint>& pts, int blockSize, float harris_k) |
|
|
|
|
{ |
|
|
|
|
CV_Assert( img.type() == CV_8UC1 && blockSize*blockSize <= 2048 ); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
size_t ptidx, ptsize = pts.size(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const uchar* ptr00 = img.ptr<uchar>(); |
|
|
|
|
int step = (int)(img.step/img.elemSize1()); |
|
|
|
|
int r = blockSize/2; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float scale = (1 << 2) * blockSize * 255.0f; |
|
|
|
|
scale = 1.0f / scale; |
|
|
|
|
float scale_sq_sq = scale * scale * scale * scale; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AutoBuffer<int> ofsbuf(blockSize*blockSize); |
|
|
|
|
int* ofs = ofsbuf; |
|
|
|
|
for( int i = 0; i < blockSize; i++ ) |
|
|
|
|
for( int j = 0; j < blockSize; j++ ) |
|
|
|
|
ofs[i*blockSize + j] = (int)(i*step + j); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for( ptidx = 0; ptidx < ptsize; ptidx++ ) |
|
|
|
|
{ |
|
|
|
|
int x0 = cvRound(pts[ptidx].pt.x - r); |
|
|
|
|
int y0 = cvRound(pts[ptidx].pt.y - r); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const uchar* ptr0 = ptr00 + y0*step + x0; |
|
|
|
|
int a = 0, b = 0, c = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for( int k = 0; k < blockSize*blockSize; k++ ) |
|
|
|
|
{ |
|
|
|
|
const uchar* ptr = ptr0 + ofs[k]; |
|
|
|
@ -98,13 +98,13 @@ static float IC_Angle(const Mat& image, const int half_k, Point2f pt, |
|
|
|
|
const vector<int> & u_max) |
|
|
|
|
{ |
|
|
|
|
int m_01 = 0, m_10 = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const uchar* center = &image.at<uchar> (cvRound(pt.y), cvRound(pt.x)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Treat the center line differently, v=0
|
|
|
|
|
for (int u = -half_k; u <= half_k; ++u) |
|
|
|
|
m_10 += u * center[u]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Go line by line in the circular patch
|
|
|
|
|
int step = (int)image.step1(); |
|
|
|
|
for (int v = 1; v <= half_k; ++v) |
|
|
|
@ -120,7 +120,7 @@ static float IC_Angle(const Mat& image, const int half_k, Point2f pt, |
|
|
|
|
} |
|
|
|
|
m_01 += v * v_sum; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return fastAtan2((float)m_01, (float)m_10); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -134,10 +134,10 @@ static void computeOrbDescriptor(const KeyPoint& kpt, |
|
|
|
|
//angle = cvFloor(angle/12)*12.f;
|
|
|
|
|
angle *= (float)(CV_PI/180.f); |
|
|
|
|
float a = (float)cos(angle), b = (float)sin(angle); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const uchar* center = &img.at<uchar>(cvRound(kpt.pt.y), cvRound(kpt.pt.x)); |
|
|
|
|
int step = (int)img.step; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 1 |
|
|
|
|
#define GET_VALUE(idx) \ |
|
|
|
|
center[cvRound(pattern[idx].x*b + pattern[idx].y*a)*step + \
|
|
|
|
@ -153,7 +153,7 @@ static void computeOrbDescriptor(const KeyPoint& kpt, |
|
|
|
|
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)) |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if( WTA_K == 2 ) |
|
|
|
|
{ |
|
|
|
|
for (int i = 0; i < dsize; ++i, pattern += 16) |
|
|
|
@ -175,7 +175,7 @@ static void computeOrbDescriptor(const KeyPoint& kpt, |
|
|
|
|
val |= (t0 < t1) << 6; |
|
|
|
|
t0 = GET_VALUE(14); t1 = GET_VALUE(15); |
|
|
|
|
val |= (t0 < t1) << 7; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
desc[i] = (uchar)val; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -186,16 +186,16 @@ static void computeOrbDescriptor(const KeyPoint& kpt, |
|
|
|
|
int 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; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -211,7 +211,7 @@ static void computeOrbDescriptor(const KeyPoint& kpt, |
|
|
|
|
if( 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; |
|
|
|
@ -219,7 +219,7 @@ static void computeOrbDescriptor(const KeyPoint& kpt, |
|
|
|
|
if( 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; |
|
|
|
@ -227,7 +227,7 @@ static void computeOrbDescriptor(const KeyPoint& kpt, |
|
|
|
|
if( 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; |
|
|
|
@ -235,23 +235,23 @@ static void computeOrbDescriptor(const KeyPoint& kpt, |
|
|
|
|
if( t3 > t2 ) t2 = t3, v = 3; |
|
|
|
|
k = t0 > t2 ? u : v; |
|
|
|
|
val |= k << 6; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
desc[i] = (uchar)val; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
CV_Error( CV_StsBadSize, "Wrong WTA_K. It can be only 2, 3 or 4." ); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#undef GET_VALUE |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void initializeOrbPattern( const Point* pattern0, vector<Point>& pattern, int ntuples, int tupleSize, int poolSize ) |
|
|
|
|
{ |
|
|
|
|
RNG rng(0x12345678); |
|
|
|
|
int i, k, k1; |
|
|
|
|
pattern.resize(ntuples*tupleSize); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for( i = 0; i < ntuples; i++ ) |
|
|
|
|
{ |
|
|
|
|
for( k = 0; k < tupleSize; k++ ) |
|
|
|
@ -545,7 +545,7 @@ static void makeRandomPattern(int patchSize, Point* pattern, int npoints) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline float getScale(int level, int firstLevel, double scaleFactor) |
|
|
|
|
{ |
|
|
|
|
return (float)std::pow(scaleFactor, (double)(level - firstLevel)); |
|
|
|
@ -570,8 +570,8 @@ int ORB::descriptorSize() const |
|
|
|
|
int ORB::descriptorType() const |
|
|
|
|
{ |
|
|
|
|
return CV_8U; |
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** Compute the ORB features and descriptors on an image
|
|
|
|
|
* @param img the image to compute the features and descriptors on |
|
|
|
|
* @param mask the mask to apply |
|
|
|
@ -599,7 +599,7 @@ static void computeOrientation(const Mat& image, vector<KeyPoint>& keypoints, |
|
|
|
|
keypoint->angle = IC_Angle(image, halfPatchSize, keypoint->pt, umax); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Compute the ORB keypoints on an image
|
|
|
|
|
* @param image_pyramid the image pyramid to compute the features and descriptors on |
|
|
|
@ -614,11 +614,11 @@ static void computeKeyPoints(const vector<Mat>& imagePyramid, |
|
|
|
|
{ |
|
|
|
|
int nlevels = (int)imagePyramid.size(); |
|
|
|
|
vector<int> nfeaturesPerLevel(nlevels); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// fill the extractors and descriptors for the corresponding scales
|
|
|
|
|
float factor = (float)(1.0 / scaleFactor); |
|
|
|
|
float ndesiredFeaturesPerScale = nfeatures*(1 - factor)/(1 - (float)pow((double)factor, (double)nlevels)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int sumFeatures = 0; |
|
|
|
|
for( int level = 0; level < nlevels-1; level++ ) |
|
|
|
|
{ |
|
|
|
@ -627,19 +627,19 @@ static void computeKeyPoints(const vector<Mat>& imagePyramid, |
|
|
|
|
ndesiredFeaturesPerScale *= factor; |
|
|
|
|
} |
|
|
|
|
nfeaturesPerLevel[nlevels-1] = std::max(nfeatures - sumFeatures, 0); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Make sure we forget about what is too close to the boundary
|
|
|
|
|
//edge_threshold_ = std::max(edge_threshold_, patch_size_/2 + kKernelWidth / 2 + 2);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// pre-compute the end of a row in a circular patch
|
|
|
|
|
int halfPatchSize = patchSize / 2; |
|
|
|
|
vector<int> umax(halfPatchSize + 1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int v, v0, vmax = cvFloor(halfPatchSize * sqrt(2.f) / 2 + 1); |
|
|
|
|
int vmin = cvCeil(halfPatchSize * sqrt(2.f) / 2); |
|
|
|
|
for (v = 0; v <= vmax; ++v) |
|
|
|
|
umax[v] = cvRound(sqrt((double)halfPatchSize * halfPatchSize - v * v)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Make sure we are symmetric
|
|
|
|
|
for (v = halfPatchSize, v0 = 0; v >= vmin; --v) |
|
|
|
|
{ |
|
|
|
@ -648,37 +648,37 @@ static void computeKeyPoints(const vector<Mat>& imagePyramid, |
|
|
|
|
umax[v] = v0; |
|
|
|
|
++v0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
allKeypoints.resize(nlevels); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int level = 0; level < nlevels; ++level) |
|
|
|
|
{ |
|
|
|
|
int nfeatures = nfeaturesPerLevel[level]; |
|
|
|
|
allKeypoints[level].reserve(nfeatures*2); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vector<KeyPoint> & keypoints = allKeypoints[level]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Detect FAST features, 20 is a good threshold
|
|
|
|
|
FastFeatureDetector fd(20, true); |
|
|
|
|
fd.detect(imagePyramid[level], keypoints, maskPyramid[level]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Remove keypoints very close to the border
|
|
|
|
|
KeyPointsFilter::runByImageBorder(keypoints, imagePyramid[level].size(), edgeThreshold); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if( scoreType == ORB::HARRIS_SCORE ) |
|
|
|
|
{ |
|
|
|
|
// Keep more points than necessary as FAST does not give amazing corners
|
|
|
|
|
KeyPointsFilter::retainBest(keypoints, 2 * nfeatures); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Compute the Harris cornerness (better scoring than FAST)
|
|
|
|
|
HarrisResponses(imagePyramid[level], keypoints, 7, HARRIS_K); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//cull to the final desired level, using the new Harris scores or the original FAST scores.
|
|
|
|
|
KeyPointsFilter::retainBest(keypoints, nfeatures);
|
|
|
|
|
|
|
|
|
|
KeyPointsFilter::retainBest(keypoints, nfeatures); |
|
|
|
|
|
|
|
|
|
float sf = getScale(level, firstLevel, scaleFactor); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set the level of the coordinates
|
|
|
|
|
for (vector<KeyPoint>::iterator keypoint = keypoints.begin(), |
|
|
|
|
keypointEnd = keypoints.end(); keypoint != keypointEnd; ++keypoint) |
|
|
|
@ -686,12 +686,12 @@ static void computeKeyPoints(const vector<Mat>& imagePyramid, |
|
|
|
|
keypoint->octave = level; |
|
|
|
|
keypoint->size = patchSize*sf; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
computeOrientation(imagePyramid[level], keypoints, halfPatchSize, umax); |
|
|
|
|
} |
|
|
|
|
}
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Compute the ORB decriptors
|
|
|
|
|
* @param image the image to compute the features and descriptors on |
|
|
|
|
* @param integral_image the integral image of the image (can be empty, but the computation will be slower) |
|
|
|
@ -706,12 +706,12 @@ static void computeDescriptors(const Mat& image, vector<KeyPoint>& keypoints, Ma |
|
|
|
|
CV_Assert(image.type() == CV_8UC1); |
|
|
|
|
//create the descriptor mat, keypoints.size() rows, BYTES cols
|
|
|
|
|
descriptors = Mat::zeros((int)keypoints.size(), dsize, CV_8UC1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < keypoints.size(); i++) |
|
|
|
|
computeOrbDescriptor(keypoints[i], image, &pattern[0], descriptors.ptr((int)i), dsize, WTA_K); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Compute the ORB features and descriptors on an image
|
|
|
|
|
* @param img the image to compute the features and descriptors on |
|
|
|
|
* @param mask the mask to apply |
|
|
|
@ -725,21 +725,21 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke |
|
|
|
|
{ |
|
|
|
|
bool do_keypoints = !useProvidedKeypoints; |
|
|
|
|
bool do_descriptors = _descriptors.needed(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if( (!do_keypoints && !do_descriptors) || _image.empty() ) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//ROI handling
|
|
|
|
|
const int HARRIS_BLOCK_SIZE = 9; |
|
|
|
|
int halfPatchSize = patchSize / 2; |
|
|
|
|
int border = std::max(edgeThreshold, std::max(halfPatchSize, HARRIS_BLOCK_SIZE/2))+1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Mat image = _image.getMat(), mask = _mask.getMat(); |
|
|
|
|
if( image.type() != CV_8UC1 ) |
|
|
|
|
cvtColor(_image, image, CV_BGR2GRAY); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int nlevels = this->nlevels; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if( !do_keypoints ) |
|
|
|
|
{ |
|
|
|
|
// if we have pre-computed keypoints, they may use more levels than it is set in parameters
|
|
|
|
@ -756,7 +756,7 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke |
|
|
|
|
nlevels = std::max(nlevels, std::max(_keypoints[i].octave, 0)); |
|
|
|
|
nlevels++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Pre-compute the scale pyramids
|
|
|
|
|
vector<Mat> imagePyramid(nlevels), maskPyramid(nlevels); |
|
|
|
|
for (int level = 0; level < nlevels; ++level) |
|
|
|
@ -766,49 +766,48 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke |
|
|
|
|
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)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if( !mask.empty() ) |
|
|
|
|
{ |
|
|
|
|
masktemp = Mat(wholeSize, mask.type()); |
|
|
|
|
maskPyramid[level] = masktemp(Rect(border, border, sz.width, sz.height)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Compute the resized image
|
|
|
|
|
if( level != firstLevel ) |
|
|
|
|
{ |
|
|
|
|
if( level < firstLevel ) |
|
|
|
|
{ |
|
|
|
|
resize(image, imagePyramid[level], sz, scale, scale, INTER_LINEAR); |
|
|
|
|
resize(image, imagePyramid[level], sz, 0, 0, INTER_LINEAR); |
|
|
|
|
if (!mask.empty()) |
|
|
|
|
resize(mask, maskPyramid[level], sz, scale, scale, INTER_LINEAR); |
|
|
|
|
copyMakeBorder(imagePyramid[level], temp, border, border, border, border, |
|
|
|
|
BORDER_REFLECT_101+BORDER_ISOLATED); |
|
|
|
|
resize(mask, maskPyramid[level], sz, 0, 0, INTER_LINEAR); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
resize(imagePyramid[level-1], imagePyramid[level], sz, |
|
|
|
|
1./scaleFactor, 1./scaleFactor, INTER_LINEAR); |
|
|
|
|
resize(imagePyramid[level-1], imagePyramid[level], sz, 0, 0, INTER_LINEAR); |
|
|
|
|
if (!mask.empty()) |
|
|
|
|
resize(maskPyramid[level-1], maskPyramid[level], sz, |
|
|
|
|
1./scaleFactor, 1./scaleFactor, INTER_LINEAR); |
|
|
|
|
copyMakeBorder(imagePyramid[level], temp, border, border, border, border, |
|
|
|
|
BORDER_REFLECT_101+BORDER_ISOLATED); |
|
|
|
|
{ |
|
|
|
|
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); |
|
|
|
|
if (!mask.empty()) |
|
|
|
|
copyMakeBorder(maskPyramid[level], masktemp, border, border, border, border, |
|
|
|
|
BORDER_CONSTANT+BORDER_ISOLATED); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
copyMakeBorder(image, temp, border, border, border, border, |
|
|
|
|
BORDER_REFLECT_101); |
|
|
|
|
image.copyTo(imagePyramid[level]); |
|
|
|
|
if( !mask.empty() ) |
|
|
|
|
mask.copyTo(maskPyramid[level]); |
|
|
|
|
copyMakeBorder(mask, masktemp, border, border, border, border, |
|
|
|
|
BORDER_CONSTANT+BORDER_ISOLATED); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if( !mask.empty() ) |
|
|
|
|
copyMakeBorder(maskPyramid[level], masktemp, border, border, border, border, |
|
|
|
|
BORDER_CONSTANT+BORDER_ISOLATED); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Pre-compute the keypoints (we keep the best over all scales, so this has to be done beforehand
|
|
|
|
|
vector < vector<KeyPoint> > allKeypoints; |
|
|
|
|
if( do_keypoints ) |
|
|
|
@ -817,19 +816,19 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke |
|
|
|
|
computeKeyPoints(imagePyramid, maskPyramid, allKeypoints, |
|
|
|
|
nfeatures, firstLevel, scaleFactor, |
|
|
|
|
edgeThreshold, patchSize, scoreType); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// make sure we have the right number of keypoints keypoints
|
|
|
|
|
/*vector<KeyPoint> temp;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int level = 0; level < n_levels; ++level) |
|
|
|
|
{ |
|
|
|
|
vector<KeyPoint>& keypoints = all_keypoints[level]; |
|
|
|
|
temp.insert(temp.end(), keypoints.begin(), keypoints.end()); |
|
|
|
|
keypoints.clear(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
KeyPoint::retainBest(temp, n_features_); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (vector<KeyPoint>::iterator keypoint = temp.begin(), |
|
|
|
|
keypoint_end = temp.end(); keypoint != keypoint_end; ++keypoint) |
|
|
|
|
all_keypoints[keypoint->octave].push_back(*keypoint);*/ |
|
|
|
@ -838,19 +837,19 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke |
|
|
|
|
{ |
|
|
|
|
// Remove keypoints very close to the border
|
|
|
|
|
KeyPointsFilter::runByImageBorder(_keypoints, image.size(), edgeThreshold); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Cluster the input keypoints depending on the level they were computed at
|
|
|
|
|
allKeypoints.resize(nlevels); |
|
|
|
|
for (vector<KeyPoint>::iterator keypoint = _keypoints.begin(), |
|
|
|
|
keypointEnd = _keypoints.end(); keypoint != keypointEnd; ++keypoint) |
|
|
|
|
allKeypoints[keypoint->octave].push_back(*keypoint); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Make sure we rescale the coordinates
|
|
|
|
|
for (int level = 0; level < nlevels; ++level) |
|
|
|
|
{ |
|
|
|
|
if (level == firstLevel) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vector<KeyPoint> & keypoints = allKeypoints[level]; |
|
|
|
|
float scale = 1/getScale(level, firstLevel, scaleFactor); |
|
|
|
|
for (vector<KeyPoint>::iterator keypoint = keypoints.begin(), |
|
|
|
@ -858,10 +857,10 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke |
|
|
|
|
keypoint->pt *= scale; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Mat descriptors; |
|
|
|
|
vector<Point> pattern; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if( do_descriptors ) |
|
|
|
|
{ |
|
|
|
|
int nkeypoints = 0; |
|
|
|
@ -874,19 +873,19 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke |
|
|
|
|
_descriptors.create(nkeypoints, descriptorSize(), CV_8U); |
|
|
|
|
descriptors = _descriptors.getMat(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const int npoints = 512; |
|
|
|
|
Point patternbuf[npoints]; |
|
|
|
|
const Point* pattern0 = (const Point*)bit_pattern_31_; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if( patchSize != 31 ) |
|
|
|
|
{ |
|
|
|
|
pattern0 = patternbuf; |
|
|
|
|
makeRandomPattern(patchSize, patternbuf, npoints); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CV_Assert( WTA_K == 2 || WTA_K == 3 || WTA_K == 4 ); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if( WTA_K == 2 ) |
|
|
|
|
std::copy(pattern0, pattern0 + npoints, std::back_inserter(pattern)); |
|
|
|
|
else |
|
|
|
@ -895,7 +894,7 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke |
|
|
|
|
initializeOrbPattern(pattern0, pattern, ntuples, WTA_K, npoints); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_keypoints.clear(); |
|
|
|
|
int offset = 0; |
|
|
|
|
for (int level = 0; level < nlevels; ++level) |
|
|
|
@ -903,15 +902,15 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke |
|
|
|
|
// Get the features and compute their orientation
|
|
|
|
|
vector<KeyPoint>& keypoints = allKeypoints[level]; |
|
|
|
|
int nkeypoints = (int)keypoints.size(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Compute the descriptors
|
|
|
|
|
if (do_descriptors) |
|
|
|
|
{ |
|
|
|
|
Mat desc; |
|
|
|
|
if (!descriptors.empty())
|
|
|
|
|
if (!descriptors.empty()) |
|
|
|
|
{ |
|
|
|
|
desc = descriptors.rowRange(offset, offset + nkeypoints); |
|
|
|
|
}
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
offset += nkeypoints; |
|
|
|
|
// preprocess the resized image
|
|
|
|
@ -920,7 +919,7 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke |
|
|
|
|
GaussianBlur(workingMat, workingMat, Size(7, 7), 2, 2, BORDER_REFLECT_101); |
|
|
|
|
computeDescriptors(workingMat, keypoints, desc, pattern, descriptorSize(), WTA_K); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Copy to the output data
|
|
|
|
|
if (level != firstLevel) |
|
|
|
|
{ |
|
|
|
@ -933,11 +932,11 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke |
|
|
|
|
_keypoints.insert(_keypoints.end(), keypoints.begin(), keypoints.end()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ORB::detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask) const |
|
|
|
|
{ |
|
|
|
|
(*this)(image, mask, keypoints, noArray(), false); |
|
|
|
|
}
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ORB::computeImpl( const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors) const |
|
|
|
|
{ |
|
|
|
|