You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
681 lines
21 KiB
681 lines
21 KiB
// This file is part of OpenCV project. |
|
// It is subject to the license terms in the LICENSE file found in the top-level directory |
|
// of this distribution and at http://opencv.org/license.html |
|
|
|
/* |
|
* Functions to perform affine adaptation of keypoint and to calculate descriptors of elliptic regions |
|
*/ |
|
|
|
#include "precomp.hpp" |
|
#include "opencv2/imgproc.hpp" |
|
#include "opencv2/imgproc/types_c.h" |
|
|
|
namespace { |
|
|
|
using namespace cv; |
|
using namespace cv::xfeatures2d; |
|
|
|
/* |
|
* Functions to perform affine adaptation of circular keypoint |
|
*/ |
|
void calcAffineCovariantRegions(const Mat& image, const std::vector<KeyPoint>& keypoints, std::vector<Elliptic_KeyPoint>& affRegions); |
|
void calcAffineCovariantDescriptors( const Ptr<DescriptorExtractor>& dextractor, const Mat& img, std::vector<Elliptic_KeyPoint>& affRegions, Mat& descriptors ); |
|
|
|
void calcSecondMomentMatrix(const Mat & dx2, const Mat & dxy, const Mat & dy2, Point p, Matx22f& M); |
|
bool calcAffineAdaptation(const Mat & image, Elliptic_KeyPoint& keypoint); |
|
float selIntegrationScale(const Mat & image, float si, Point c); |
|
float selDifferentiationScale(const Mat & image, Mat & Lxm2smooth, Mat & Lxmysmooth, Mat & Lym2smooth, float si, Point c); |
|
float calcSecondMomentSqrt(const Mat & dx2, const Mat & dxy, const Mat & dy2, Point p, Matx22f& Mk); |
|
float normMaxEval(Matx22f & U, Mat& uVal, Mat& uVect); |
|
|
|
/* |
|
* Calculates second moments matrix in point p |
|
*/ |
|
void calcSecondMomentMatrix(const Mat & dx2, const Mat & dxy, const Mat & dy2, Point p, Matx22f & M) |
|
{ |
|
int x = p.x; |
|
int y = p.y; |
|
|
|
M(0, 0) = dx2.at<float> (y, x); |
|
M(0, 1) = M(1, 0) = dxy.at<float> (y, x); |
|
M(1, 1) = dy2.at<float> (y, x); |
|
} |
|
|
|
/* |
|
* Performs affine adaptation |
|
*/ |
|
bool calcAffineAdaptation(const Mat & fimage, Elliptic_KeyPoint & keypoint) |
|
{ |
|
Matx23f transf; /*Transformation matrix*/ |
|
Matx21f size; /*Image size after transformation*/ |
|
Matx21f c; /*Transformed point*/ |
|
Matx21f p; /*Image point*/ |
|
|
|
Matx22f U(1.f, 0.f, 0.f, 1.f); /*Normalization matrix*/ |
|
|
|
Mat warpedImg, Lxm2smooth, Lym2smooth, Lxmysmooth, img_roi; |
|
Matx22f Mk; |
|
float Qinv = 1, q, si = keypoint.si; |
|
bool divergence = false, convergence = false; |
|
int i = 0; |
|
|
|
//Coordinates in image |
|
int py = (int) keypoint.pt.y; |
|
int px = (int) keypoint.pt.x; |
|
|
|
//Roi coordinates |
|
int roix, roiy; |
|
|
|
//Coordinates in U-trasformation |
|
int cx = px; |
|
int cy = py; |
|
int cxPr = cx; |
|
int cyPr = cy; |
|
|
|
float radius = keypoint.size / 2 * 1.4f; |
|
float half_width, half_height; |
|
|
|
Rect roi; |
|
float ax1, ax2; |
|
float phi = 0; |
|
ax1 = ax2 = keypoint.size / 2; |
|
Mat drawImg; |
|
|
|
//Affine adaptation |
|
while (i <= 10 && !divergence && !convergence) |
|
{ |
|
//Transformation matrix |
|
transf = Matx23f( |
|
U(0,0), U(0,1), 0.f, |
|
U(1,0), U(1,1), 0.f |
|
); |
|
keypoint.transf = transf; |
|
|
|
Size_<float> boundingBox; |
|
|
|
float ac_b2 = float(determinant(U)); |
|
boundingBox.width = ceil(U(1, 1)/ac_b2 * 3 * si*1.4f ); |
|
boundingBox.height = ceil(U(0, 0)/ac_b2 * 3 * si*1.4f ); |
|
|
|
//Create window around interest point |
|
half_width = std::min((float) std::min(fimage.cols - px-1, px), boundingBox.width); |
|
half_height = std::min((float) std::min(fimage.rows - py-1, py), boundingBox.height); |
|
roix = max(px - (int) boundingBox.width, 0); |
|
roiy = max(py - (int) boundingBox.height, 0); |
|
roi = Rect(roix, roiy, px - roix + int(half_width)+1, py - roiy + int(half_height)+1); |
|
|
|
//create ROI |
|
img_roi = fimage(roi); |
|
|
|
|
|
//Point within the ROI |
|
p(0, 0) = float(px - roix); |
|
p(1, 0) = float(py - roiy); |
|
|
|
if (half_width <= 0 || half_height <= 0) |
|
return divergence; |
|
|
|
//Find coordinates of square's angles to find size of warped ellipse's bounding box |
|
float u00 = U(0, 0); |
|
float u01 = U(0, 1); |
|
float u10 = U(1, 0); |
|
float u11 = U(1, 1); |
|
|
|
float minx = u01 * img_roi.rows < 0 ? u01 * img_roi.rows : 0; |
|
float miny = u10 * img_roi.cols < 0 ? u10 * img_roi.cols : 0; |
|
float maxx = (u00 * img_roi.cols > u00 * img_roi.cols + u01 * img_roi.rows ? u00 |
|
* img_roi.cols : u00 * img_roi.cols + u01 * img_roi.rows) - minx; |
|
float maxy = (u11 * img_roi.rows > u10 * img_roi.cols + u11 * img_roi.rows ? u11 |
|
* img_roi.rows : u10 * img_roi.cols + u11 * img_roi.rows) - miny; |
|
|
|
//Shift |
|
transf(0, 2) = -minx; |
|
transf(1, 2) = -miny; |
|
|
|
/*float min_width = minx >= 0 ? u00 * img_roi.cols - u01 * img_roi.rows : u00 * img_roi.cols |
|
+ u01 * img_roi.rows; |
|
float min_height = miny >= 0 ? u11 * img_roi.rows - u10 * img_roi.cols : u10 * img_roi.cols |
|
+ u11 * img_roi.rows;*/ |
|
|
|
if (maxx >= 2*radius+1 && maxy >= 2*radius+1) |
|
{ |
|
//Size of normalized window must be 2*radius |
|
//Transformation |
|
Mat warpedImgRoi; |
|
warpAffine(img_roi, warpedImgRoi, transf, Size(int(maxx), int(maxy)),INTER_AREA, BORDER_REPLICATE); |
|
|
|
//Point in U-Normalized coordinates |
|
c = U * p; |
|
cx = int(c(0, 0) - minx); |
|
cy = int(c(1, 0) - miny); |
|
|
|
if (warpedImgRoi.rows > 2 * radius+1 && warpedImgRoi.cols > 2 * radius+1) |
|
{ |
|
//Cut around normalized patch |
|
roix = std::max(cx - int(ceil(radius)), 0); |
|
roiy = std::max(cy - int(ceil(radius)), 0); |
|
roi = Rect(roix, roiy, |
|
cx - roix + std::min(int(ceil(radius)), warpedImgRoi.cols - cx-1)+1, |
|
cy - roiy + std::min(int(ceil(radius)), warpedImgRoi.rows - cy-1)+1); |
|
warpedImg = warpedImgRoi(roi); |
|
|
|
//Coordinates in cutted ROI |
|
cx = cx - roix; |
|
cy = cy - roiy; |
|
} else |
|
warpedImgRoi.copyTo(warpedImg); |
|
|
|
//Integration Scale selection |
|
si = selIntegrationScale(warpedImg, si, Point(cx, cy)); |
|
//Differentation scale selection |
|
selDifferentiationScale(warpedImg, Lxm2smooth, Lxmysmooth, Lym2smooth, si, |
|
Point(cx, cy)); |
|
|
|
//Spatial Localization |
|
cxPr = cx; //Previous iteration point in normalized window |
|
cyPr = cy; |
|
|
|
float cornMax = 0; |
|
for (int j = 0; j < 3; j++) |
|
{ |
|
for (int t = 0; t < 3; t++) |
|
{ |
|
float dx2 = Lxm2smooth.at<float> (cyPr - 1 + j, cxPr - 1 + t); |
|
float dy2 = Lym2smooth.at<float> (cyPr - 1 + j, cxPr - 1 + t); |
|
float dxy = Lxmysmooth.at<float> (cyPr - 1 + j, cxPr - 1 + t); |
|
float det = dx2 * dy2 - dxy * dxy; |
|
float tr = dx2 + dy2; |
|
float cornerness = det - (0.04f * tr*tr); |
|
if (cornerness > cornMax) |
|
{ |
|
cornMax = cornerness; |
|
cx = cxPr - 1 + t; |
|
cy = cyPr - 1 + j; |
|
} |
|
} |
|
} |
|
|
|
//Transform point in image coordinates |
|
p(0, 0) = float(px); |
|
p(1, 0) = float(py); |
|
//Displacement vector |
|
c(0, 0) = float(cx - cxPr); |
|
c(1, 0) = float(cy - cyPr); |
|
//New interest point location in image |
|
p = p + Matx22f(Matx22d(U).inv()) * c; |
|
px = int(p(0, 0)); |
|
py = int(p(1, 0)); |
|
|
|
q = calcSecondMomentSqrt(Lxm2smooth, Lxmysmooth, Lym2smooth, Point(cx, cy), Mk); |
|
|
|
float ratio = 1 - q; |
|
|
|
//if ratio == 1 means q == 0 and one axes equals to 0 |
|
if (!cvIsNaN(ratio) && ratio != 1) |
|
{ |
|
//Update U matrix |
|
U = U * Mk; |
|
|
|
Mat uVal, uV; |
|
eigen(U, uVal, uV); |
|
|
|
Qinv = normMaxEval(U, uVal, uV); |
|
|
|
//Keypoint doesn't converge |
|
if (Qinv >= 6) |
|
divergence = true; |
|
|
|
//Keypoint converges |
|
else if (ratio <= 0.05f) |
|
{ |
|
convergence = true; |
|
|
|
//Set transformation matrix |
|
transf = Matx23f( |
|
U(0,0), U(0,1), 0.f, |
|
U(1,0), U(1,1), 0.f |
|
); |
|
keypoint.transf = transf; |
|
|
|
ax1 = 1.f / std::abs(uVal.at<float> (0, 0)) * 3 * si; |
|
ax2 = 1.f / std::abs(uVal.at<float> (1, 0)) * 3 * si; |
|
phi = float(atan(uV.at<float> (1, 0) / uV.at<float> (0, 0)) * (180) / CV_PI); |
|
keypoint.axes = Size_<float> (ax1, ax2); |
|
keypoint.angle = phi; |
|
keypoint.pt = Point2f( (float) px, (float) py); |
|
keypoint.si = si; |
|
keypoint.size = 2 * 3 * si; |
|
|
|
} else |
|
radius = 3 * si * 1.4f; |
|
|
|
} else divergence = true; |
|
|
|
} else divergence = true; |
|
|
|
++i; |
|
} |
|
|
|
return convergence; |
|
} |
|
|
|
/* |
|
* Selects the integration scale that maximize LoG in point c |
|
*/ |
|
float selIntegrationScale(const Mat & image, float si, Point c) |
|
{ |
|
Mat Lap, L; |
|
int cx = c.x; |
|
int cy = c.y; |
|
float maxLap = 0; |
|
float maxsx = si; |
|
int gsize; |
|
float sigma, sigma_prev = 0; |
|
|
|
image.copyTo(L); |
|
/* Search best integration scale between previous and successive layer |
|
*/ |
|
for (float u = 0.7f; u <= 1.41f; u += 0.1f) |
|
{ |
|
float sik = u * si; |
|
sigma = sqrt(powf(sik, 2) - powf(sigma_prev, 2)); |
|
|
|
gsize = int(ceil(sigma * 3)) * 2 + 1; |
|
|
|
GaussianBlur(L, L, Size(gsize, gsize), sigma); |
|
sigma_prev = sik; |
|
|
|
Laplacian(L, Lap, CV_32F, 3); |
|
|
|
float lapVal = sik * sik * std::abs(Lap.at<float> (cy, cx)); |
|
|
|
if (u == 0.7f) |
|
maxLap = lapVal; |
|
|
|
if (lapVal >= maxLap) |
|
{ |
|
maxLap = lapVal; |
|
maxsx = sik; |
|
} |
|
} |
|
return maxsx; |
|
} |
|
|
|
/* |
|
* Calculates second moments matrix square root |
|
*/ |
|
float calcSecondMomentSqrt(const Mat & dx2, const Mat & dxy, const Mat & dy2, Point p, Matx22f & Mk) |
|
{ |
|
Mat V, eigVal, Vinv, D; |
|
Matx22f M; |
|
|
|
calcSecondMomentMatrix(dx2, dxy, dy2, p, M); |
|
|
|
/* * |
|
* M = V * D * V.inv() |
|
* V has eigenvectors as columns |
|
* D is a diagonal Matrix with eigenvalues as elements |
|
* V.inv() is the inverse of V |
|
* */ |
|
|
|
eigen(M, eigVal, V); |
|
V = V.t(); |
|
Vinv = V.inv(); |
|
|
|
float eval1 = eigVal.at<float> (0, 0) = sqrt(eigVal.at<float> (0, 0)); |
|
float eval2 = eigVal.at<float> (1, 0) = sqrt(eigVal.at<float> (1, 0)); |
|
|
|
D = Mat::diag(eigVal); |
|
|
|
//square root of M |
|
Mk = Mat(V * D * Vinv); |
|
//return q isotropic measure |
|
return min(eval1, eval2) / max(eval1, eval2); |
|
} |
|
|
|
float normMaxEval(Matx22f & U, Mat & uVal, Mat & uVec) |
|
{ |
|
/* * |
|
* Decomposition: |
|
* U = V * D * V.inv() |
|
* V has eigenvectors as columns |
|
* D is a diagonal Matrix with eigenvalues as elements |
|
* V.inv() is the inverse of V |
|
* */ |
|
uVec = uVec.t(); |
|
Mat uVinv = uVec.inv(); |
|
|
|
//Normalize min eigenvalue to 1 to expand patch in the direction of min eigenvalue of U.inv() |
|
float uval1 = uVal.at<float> (0, 0); |
|
float uval2 = uVal.at<float> (1, 0); |
|
|
|
if (std::abs(uval1) < std::abs(uval2)) |
|
{ |
|
uVal.at<float> (0, 0) = 1; |
|
uVal.at<float> (1, 0) = uval2 / uval1; |
|
} else |
|
{ |
|
uVal.at<float> (1, 0) = 1; |
|
uVal.at<float> (0, 0) = uval1 / uval2; |
|
} |
|
|
|
Mat D = Mat::diag(uVal); |
|
//U normalized |
|
U = Mat(uVec * D * uVinv); |
|
|
|
return max(std::abs(uVal.at<float> (0, 0)), std::abs(uVal.at<float> (1, 0))) / min( |
|
std::abs(uVal.at<float> (0, 0)), std::abs(uVal.at<float> (1, 0))); //define the direction of warping |
|
} |
|
|
|
/* |
|
* Selects diffrentiation scale |
|
*/ |
|
float selDifferentiationScale(const Mat & img, Mat & Lxm2smooth, Mat & Lxmysmooth, |
|
Mat & Lym2smooth, float si, Point c) |
|
{ |
|
float s = 0.5f; |
|
float sdk = s * si; |
|
float sigma_prev = 0, sigma; |
|
|
|
Mat L, dx2, dxy, dy2; |
|
|
|
double qMax = 0; |
|
|
|
//Gaussian kernel size |
|
int gsize; |
|
Size ksize; |
|
|
|
img.copyTo(L); |
|
|
|
while (s <= 0.751f) |
|
{ |
|
Matx22f M; |
|
float sd = s * si; |
|
|
|
//Smooth previous smoothed image L |
|
sigma = sqrt(powf(sd, 2) - powf(sigma_prev, 2)); |
|
|
|
gsize = int(ceil(sigma * 3)) * 2 + 1; |
|
|
|
GaussianBlur(L, L, Size(gsize, gsize), sigma); |
|
|
|
sigma_prev = sd; |
|
|
|
//X and Y derivatives |
|
Mat Lx, Ly; |
|
Sobel(L, Lx, L.depth(), 1, 0, 1); |
|
Lx = Lx * sd; |
|
Sobel(L, Ly, L.depth(), 0, 1, 1); |
|
Ly = Ly * sd; |
|
|
|
//Size of gaussian kernel |
|
gsize = int(ceil(si * 3)) * 2 + 1; |
|
ksize = Size(gsize, gsize); |
|
|
|
Mat Lxm2 = Lx.mul(Lx); |
|
GaussianBlur(Lxm2, dx2, ksize, si); |
|
|
|
Mat Lym2 = Ly.mul(Ly); |
|
GaussianBlur(Lym2, dy2, ksize, si); |
|
|
|
Mat Lxmy = Lx.mul(Ly); |
|
GaussianBlur(Lxmy, dxy, ksize, si); |
|
|
|
calcSecondMomentMatrix(dx2, dxy, dy2, Point(c.x, c.y), M); |
|
|
|
//calc eigenvalues |
|
Mat eval; |
|
eigen(M, eval); |
|
double eval1 = std::abs(eval.at<float> (0, 0)); |
|
double eval2 = std::abs(eval.at<float> (1, 0)); |
|
double q = min(eval1, eval2) / max(eval1, eval2); |
|
|
|
if (q >= qMax) |
|
{ |
|
qMax = q; |
|
sdk = sd; |
|
dx2.copyTo(Lxm2smooth); |
|
dxy.copyTo(Lxmysmooth); |
|
dy2.copyTo(Lym2smooth); |
|
|
|
} |
|
s += 0.05f; |
|
} |
|
|
|
return sdk; |
|
} |
|
|
|
void calcAffineCovariantRegions(const Mat & image, const std::vector<KeyPoint> & keypoints, |
|
std::vector<Elliptic_KeyPoint> & affRegions) |
|
{ |
|
for (size_t i = 0; i < keypoints.size(); ++i) |
|
{ |
|
KeyPoint kp = keypoints[i]; |
|
Elliptic_KeyPoint ex(kp.pt, 0, Size_<float> (kp.size / 2, kp.size / 2), kp.size, |
|
kp.size / 6); |
|
|
|
if (calcAffineAdaptation(image, ex)) |
|
affRegions.push_back(ex); |
|
} |
|
//Erase similar keypoint |
|
float maxDiff = 4; |
|
Mat colorimg; |
|
for (size_t i = 0; i < affRegions.size(); i++) |
|
{ |
|
Elliptic_KeyPoint kp1 = affRegions[i]; |
|
for (size_t j = i+1; j < affRegions.size(); j++){ |
|
|
|
Elliptic_KeyPoint kp2 = affRegions[j]; |
|
|
|
if(norm(kp1.pt-kp2.pt)<=maxDiff){ |
|
float phi1, phi2; |
|
Size axes1, axes2; |
|
float si1, si2; |
|
phi1 = kp1.angle; |
|
phi2 = kp2.angle; |
|
axes1 = kp1.axes; |
|
axes2 = kp2.axes; |
|
si1 = kp1.si; |
|
si2 = kp2.si; |
|
if(std::abs(phi1-phi2)<15 && std::max(si1,si2)/std::min(si1,si2)<1.4f && axes1.width-axes2.width<5 && axes1.height-axes2.height<5){ |
|
affRegions.erase(affRegions.begin()+j); |
|
j--; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
void calcAffineCovariantDescriptors(const Ptr<DescriptorExtractor>& dextractor, const Mat& img, |
|
std::vector<Elliptic_KeyPoint>& affRegions, Mat& descriptors) |
|
{ |
|
|
|
assert(!affRegions.empty()); |
|
int descriptorSize = dextractor->descriptorSize(); |
|
int descriptorType = dextractor->descriptorType(); |
|
descriptors.create(Size(descriptorSize, int(affRegions.size())), descriptorType); |
|
descriptors.setTo(0); |
|
|
|
int i = 0; |
|
|
|
for (std::vector<Elliptic_KeyPoint>::iterator it = affRegions.begin(); it < affRegions.end(); ++it) |
|
{ |
|
Point p = it->pt; |
|
|
|
Matx21f size; |
|
size(0, 0) = size(1, 0) = it->size; |
|
|
|
//U matrix |
|
Matx23f transf = it->transf; |
|
Matx22f U( |
|
transf(0,0), transf(0,1), |
|
transf(1,0), transf(1,1) |
|
); |
|
|
|
float radius = it->size / 2; |
|
float si = it->si; |
|
|
|
Size_<float> boundingBox; |
|
|
|
float ac_b2 = float(determinant(U)); |
|
boundingBox.width = ceil(U(1, 1)/ac_b2 * 3 * si ); |
|
boundingBox.height = ceil(U(0, 0)/ac_b2 * 3 * si ); |
|
|
|
//Create window around interest point |
|
float half_width = std::min((float) std::min(img.cols - p.x-1, p.x), boundingBox.width); |
|
float half_height = std::min((float) std::min(img.rows - p.y-1, p.y), boundingBox.height); |
|
int roix = max(p.x - (int) boundingBox.width, 0); |
|
int roiy = max(p.y - (int) boundingBox.height, 0); |
|
Rect roi = Rect(roix, roiy, p.x - roix + int(half_width)+1, p.y - roiy + int(half_height)+1); |
|
|
|
Mat img_roi = img(roi); |
|
|
|
size(0, 0) = float(img_roi.cols); |
|
size(1, 0) = float(img_roi.rows); |
|
|
|
size = U * size; |
|
|
|
Mat transfImgRoi, transfImg; |
|
warpAffine(img_roi, transfImgRoi, transf, Size(int(ceil(size(0, 0))), int(ceil(size(1, 0)))), |
|
INTER_AREA, BORDER_DEFAULT); |
|
|
|
Matx21f c; //Transformed point |
|
Matx21f pt; //Image point |
|
//Point within the Roi |
|
pt(0, 0) = float(p.x - roix); |
|
pt(1, 0) = float(p.y - roiy); |
|
|
|
//Point in U-Normalized coordinates |
|
c = U * pt; |
|
float cx = c(0, 0); |
|
float cy = c(1, 0); |
|
|
|
//Cut around point to have patch of 2*keypoint->size |
|
|
|
roix = std::max(int(ceil(cx - radius)), 0); |
|
roiy = std::max(int(ceil(cy - radius)), 0); |
|
|
|
roi = Rect(roix, roiy, int(ceil(std::min(cx - roix + radius, size(0, 0)))), |
|
int(ceil(std::min(cy - roiy + radius, size(1, 0))))); |
|
transfImg = transfImgRoi(roi); |
|
|
|
cx = c(0, 0) - roix; |
|
cy = c(1, 0) - roiy; |
|
|
|
Mat tmpDesc; |
|
KeyPoint kp(Point(int(cx), int(cy)), it->size); |
|
|
|
std::vector<KeyPoint> k(1, kp); |
|
|
|
transfImg.convertTo(transfImg, CV_8U); |
|
dextractor->compute(transfImg, k, tmpDesc); |
|
|
|
tmpDesc.row(0).copyTo(descriptors.row(i)); |
|
|
|
i++; |
|
|
|
} |
|
|
|
} |
|
|
|
} // anonymous namespace |
|
|
|
namespace cv |
|
{ |
|
namespace xfeatures2d |
|
{ |
|
class AffineFeature2D_Impl : public AffineFeature2D |
|
{ |
|
public: |
|
AffineFeature2D_Impl( |
|
Ptr<FeatureDetector> keypoint_detector, |
|
Ptr<DescriptorExtractor> descriptor_extractor |
|
) : m_keypoint_detector(keypoint_detector) |
|
, m_descriptor_extractor(descriptor_extractor) {} |
|
protected: |
|
using Feature2D::detect; // overload, don't hide |
|
void detect(InputArray image, std::vector<Elliptic_KeyPoint>& keypoints, InputArray mask); |
|
void detectAndCompute(InputArray image, InputArray mask, std::vector<Elliptic_KeyPoint>& keypoints, OutputArray descriptors, bool useProvidedKeypoints); |
|
void detectAndCompute(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints, OutputArray descriptors, bool useProvidedKeypoints); |
|
int descriptorSize() const; |
|
int descriptorType() const; |
|
int defaultNorm() const; |
|
private: |
|
Ptr<FeatureDetector> m_keypoint_detector; |
|
Ptr<DescriptorExtractor> m_descriptor_extractor; |
|
}; |
|
|
|
Ptr<AffineFeature2D> AffineFeature2D::create( |
|
Ptr<FeatureDetector> keypoint_detector, |
|
Ptr<DescriptorExtractor> descriptor_extractor) |
|
{ |
|
return makePtr<AffineFeature2D_Impl>(keypoint_detector, descriptor_extractor); |
|
} |
|
|
|
void AffineFeature2D_Impl::detect( |
|
InputArray image, |
|
std::vector<Elliptic_KeyPoint>& keypoints, |
|
InputArray mask) |
|
{ |
|
std::vector<KeyPoint> non_elliptic_keypoints; |
|
m_keypoint_detector->detect(image, non_elliptic_keypoints, mask); |
|
Mat fimage; |
|
image.getMat().convertTo(fimage, CV_32F, 1.f/255); |
|
calcAffineCovariantRegions(fimage, non_elliptic_keypoints, keypoints); |
|
} |
|
|
|
void AffineFeature2D_Impl::detectAndCompute( |
|
InputArray image, |
|
InputArray mask, |
|
std::vector<Elliptic_KeyPoint>& keypoints, |
|
OutputArray descriptors, |
|
bool useProvidedKeypoints) |
|
{ |
|
if(!useProvidedKeypoints) |
|
{ |
|
std::vector<KeyPoint> non_elliptic_keypoints; |
|
m_keypoint_detector->detect(image, non_elliptic_keypoints, mask); |
|
Mat fimage; |
|
image.getMat().convertTo(fimage, CV_32F, 1.f/255); |
|
calcAffineCovariantRegions(fimage, non_elliptic_keypoints, keypoints); |
|
} |
|
if(descriptors.needed())calcAffineCovariantDescriptors(m_descriptor_extractor, image.getMat(), keypoints, descriptors.getMatRef()); |
|
} |
|
|
|
void AffineFeature2D_Impl::detectAndCompute( |
|
InputArray image, |
|
InputArray mask, |
|
std::vector<KeyPoint>& keypoints, |
|
OutputArray descriptors, |
|
bool useProvidedKeypoints) |
|
{ |
|
if(!useProvidedKeypoints) |
|
{ |
|
m_keypoint_detector->detect(image, keypoints, mask); |
|
} |
|
if(descriptors.needed()) { |
|
Mat fimage; |
|
image.getMat().convertTo(fimage, CV_32F, 1.f/255); |
|
std::vector<Elliptic_KeyPoint> elliptic_keypoints; |
|
calcAffineCovariantRegions(fimage, keypoints, elliptic_keypoints); |
|
calcAffineCovariantDescriptors(m_descriptor_extractor, image.getMat(), elliptic_keypoints, descriptors.getMatRef()); |
|
} |
|
} |
|
|
|
int AffineFeature2D_Impl::descriptorSize() const |
|
{ |
|
return m_descriptor_extractor->descriptorSize(); |
|
} |
|
|
|
int AffineFeature2D_Impl::descriptorType() const |
|
{ |
|
return m_descriptor_extractor->descriptorType(); |
|
} |
|
|
|
int AffineFeature2D_Impl::defaultNorm() const |
|
{ |
|
return m_descriptor_extractor->defaultNorm(); |
|
} |
|
|
|
} |
|
}
|
|
|