harris-Affine实现

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本身就不是很合适的,效果比较差也是显而易见的。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值