opencv的Xfeature模块实现了affine_feature2d,网上存在一些基于affine_feature2d的Harris-Affine实现。比如
Harris-Affine仿射不变特征匹配算法_AutoSleep的博客-CSDN博客
https://github.com/SmallMunich/HarrisAffineMatch_OpenCV.git
但是这些代码可以说都是有问题的,原因在于opencv中的AffineFeature2D的实现是存在错误的。
错误主要集中在calcAffineCovariantDescriptors函数,存在两点问题:
1、使用了大量的ROI操作,存在溢出的可能。如果直接使用上面的代码,一般会报错,提示范围溢出。
2、calcAffineCovariantDescriptors提取了归一化的patch,但是并没有实现主方向的估计。基本上opencv特征算法的主方向估计和特征点提取是同时实现的,由于直接调用描述符的compute函数,因此缺少了主方向计算的过程。
AffineFeature2D在opencv3+版本的时候已经存在,目前为止仍没有被合并到feature2d模块,估计也是这些原因。
修改后的代码如下:(部分参数可能不是最优的)
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);
Mat fimg;
float sigma = 1.6;
Mat gray, gray_fpt;
if (img.channels() == 3 || img.channels() == 4)
{
cvtColor(img, gray, COLOR_BGR2GRAY);
gray.convertTo(gray_fpt, DataType<float>::type, 1, 0);
}
else
img.convertTo(gray_fpt, DataType<float>::type, 1, 0);
float sig_diff = sqrtf(std::max(sigma * sigma - 0.5f * 0.5f, 0.01f));
GaussianBlur(gray_fpt, fimg, Size(), sig_diff, sig_diff);
sigma = 1.6 * 1.25;
int i = 0;
std::vector<cv::Mat> vNormalPatches;
const int n = ORI_HIST_BINS;
std::vector<std::vector<KeyPoint> > pkeypoints;
//可改成openmp并行
for (std::vector<Elliptic_KeyPoint>::iterator it = affRegions.begin(); it < affRegions.end(); ++it)
{
Point p = it->pt;
Matx21f size,pt;
size(0, 0) = size(1, 0) = it->size;
pt(0, 0) = p.x;
pt(1, 0) = p.y;
//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;//radius=3*si;
//float si = it->si;
//patch的半径是 size * 0.5,如果是orb描述符,需要注意的是orb算子的边界过滤值需要设置为0,否则可能会被remove掉。
//pt = size * 0.5*sqrt(2) - U * pt;//乘以1.414是考虑到sift主方向后需要旋转。
int PatchSize = it->size * sqrt(2)*2;//此处的值可能需要酌情调整
Matx21f PSize;
PSize(0, 0) = PSize(1, 0) = PatchSize;
pt = PSize*0.5 - U * pt;//乘以1.414是考虑到sift主方向后需要旋转。
transf(0, 2) = pt(0, 0);
transf(1, 2) = pt(1, 0);
Mat warpPatch,normalPatch;
warpAffine(fimg, warpPatch, transf, Size(PatchSize, PatchSize), INTER_LINEAR, BORDER_DEFAULT);
int normalPatchSize = 31 * sqrt(2);
resize(warpPatch, normalPatch, Size(normalPatchSize, normalPatchSize),0,0, INTER_LINEAR);
int radius = cvRound( ORI_RADIUS * sigma);
float hist[n];
float omax = calcOrientationHist(normalPatch, Point((normalPatch.cols-1.0) / 2, (normalPatch.rows - 1.0) / 2), radius, ORI_SIG_FCTR * sigma, hist, n);
//float mag_thr = (float)(omax * ORI_PEAK_RATIO);
float mag_thr = (float)(omax * 1);
KeyPoint kpt, pkpt;
//尽量少的修改的代码,只考虑一个主方向
for (int j = 0; j < n; j++)
{
int l = j > 0 ? j - 1 : n - 1;
int r2 = j < n - 1 ? j + 1 : 0;
if (hist[j] > hist[l] && hist[j] > hist[r2] && hist[j] >= mag_thr)
{
float bin = j + 0.5f * (hist[l] - hist[r2]) / (hist[l] - 2 * hist[j] + hist[r2]);
bin = bin < 0 ? n + bin : bin >= n ? bin - n : bin;
kpt.angle = 360.f - (float)((360.f / n) * bin);//此处的坐标系已经是图像坐标系下了
if (std::abs(kpt.angle - 360.f) < FLT_EPSILON)
kpt.angle = 0.f;
kpt.pt = p;
kpt.size = it->size;//size是直径
kpt.octave = 0;
}
}
pkpt = kpt;
pkpt.pt = Point2f((normalPatch.cols - 1.0) / 2.0, (normalPatch.rows - 1.0) / 2.0);
pkpt.size = 2 * sigma;//如果是SIFT描述符,覆盖范围为31x31
Mat nPatch;
normalPatch.convertTo(nPatch, CV_8U);
std::vector<KeyPoint> pk(1, pkpt);
Mat tmpDesc;
dextractor->compute(nPatch, pk, tmpDesc);
tmpDesc.row(0).copyTo(descriptors.row(i));
i++;
}
}
测试的时候,特征提取使用Harris-Laplace,特征描述使用SIFT,牛津数据 graf 1-4匹配结果如下:
opencv的Harris-Laplace使用默认参数只能提取1500左右点,经过局部形状估计后,收敛的点只有一半左右,并且基于二阶矩的局部形状估计非常耗费时间。匹配结果不如https://blog.csdn.net/yunleaf/article/details/131448204MSER相关简述 极值稳定检测MSER算法是目前针对图像变形最为稳定的特征检测算法,主要采取分水岭算法来进行极值区域提取,具体细节就不多说了。大家可以参考MSER作者论文,当然也出现针对MSER算法的改进版本,分为两个方面:其一是对MSER算法进行加速,即计算效率提升;MSER算是一个比较不错的仿射不变特征了,但是对于纹理的要求比较高,要求局部大量的面积较大的斑点,斑点的边缘不能太模糊。另外,经过测试graf 1-6的匹配,使用灰度图像,匹配策略使用最近邻,有300+个匹配点了。https://blog.csdn.net/yunleaf/article/details/131448204
Harris和确定尺度的laplace本身就不是很合适的,效果比较差也是显而易见的。