MSER 仿射不变匹配

文章讨论了MSER作为仿射不变特征检测器的原理和应用,指出在OpenCV中MSER与AffineFeature2d结合的错误,并提供了一个MSER与SIFT结合的实现示例。文章强调了MSER对局部形状的估计以及在彩色图像上的问题,同时分析了匹配点的数量和质量,提出MSER对纹理和斑点边缘的要求较高,且原始MSER存在重复提取的问题,影响匹配效果。
摘要由CSDN通过智能技术生成

最大稳定极值区域MSER是一种不错的仿射不变提取算法,能够估计局部形状。基本原理就不概述了,作者本身已经开源,opencv也实现了相关的代码。MSER只是一个特征检测算法,如果想使用MSER匹配,那么还需要与其它描述符算法结合。但是尚未看到相关的开源代码。

OpenCV实践之MSER仿射匹配算法_AutoSleep的博客-CSDN博客MSER相关简述  极值稳定检测MSER算法是目前针对图像变形最为稳定的特征检测算法,主要采取分水岭算法来进行极值区域提取,具体细节就不多说了。大家可以参考MSER作者论文,当然也出现针对MSER算法的改进版本,分为两个方面:其一是对MSER算法进行加速,即计算效率提升;其二是针对彩色图像提出的MSCR算法,论文中述说对于彩色图像提取极值区域要优于MSER算法。但是,近两日我在OpenCV开放...https://blog.csdn.net/small_munich/article/details/80208248这一篇博客,将MSER和AffineFeature2d结合在一起使用是错误的。主要有两点:

1、MSER本身已经提供了局部形状,因此无需再使用二阶矩进行局部形状估计了。

2、AffineFeature2d本身的代码是有错误的,如果按照这篇博客的代码,会直接报错。

下面是本人关于MSER和SIFT结合的实现:

void AffineMSER_Impl::detectAndCompute(InputArray _img, InputArray mask, std::vector<KeyPoint>& keypoints, OutputArray _descriptors, bool useProvidedKeypoints)
	{
		Mat img = _img.getMat();
		std::vector<std::vector<Point> > msers;
		std::vector<Rect> bboxes;
		feature2D->detectRegions(img, msers, bboxes);

		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, gray_fpt, Size(), sig_diff, sig_diff);

		int  ncomps = (int)msers.size();

		keypoints.clear();

		Size patchSize(31*sqrt(2)+2, 31*sqrt(2)+2);
		Size2f blobSize(10, 10);

		std::vector<cv::Mat> vNormalPatches;
		const int n = MSER_ORI_HIST_BINS;
		std::vector<std::vector<KeyPoint> > pkeypoints;
		//截取归一化区域并计算主方向
#pragma omp parallel for
		for (int i = 0; i < ncomps; i++)
		{
			Mat normalPatch;
			KeyPoint kpt, pkpt;
			Rect r = bboxes[i];
			RotatedRect rect = fitEllipse(Mat(msers[i]));
			float diam = std::sqrt(rect.size.height * rect.size.width);

			if (diam > std::numeric_limits<float>::epsilon() && r.contains(rect.center))
			{

				//生成归一化Patch
				extractNormalPatch(gray_fpt, normalPatch, rect, patchSize, blobSize);
				//计算主方向和次主方向

				int radius = cvRound(MSER_ORI_RADIUS * sigma * 1.25);
				float hist[n];
				float omax = calcOrientationHist(normalPatch, Point(patchSize.width / 2, patchSize.height / 2), radius, MSER_ORI_SIG_FCTR * sigma * 1.25, hist, n);
				float mag_thr = (float)(omax * MSER_ORI_PEAK_RATIO);

				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 = rect.center;
						kpt.size = diam;//size是直径
						kpt.octave = 0;



						pkpt = kpt;
						pkpt.pt = Point2f((patchSize.width-1) / 2.0, (patchSize.height-1) / 2.0);
						pkpt.size = sigma * 1.25;//如果是SIFT描述符,覆盖范围为31x31

						Mat nPatch;

						normalPatch.convertTo(nPatch, CV_8U);

#pragma omp critical
						{
							std::vector<KeyPoint> pk(1, pkpt);
							pkeypoints.push_back(pk);
							vNormalPatches.push_back(nPatch.clone());
							keypoints.push_back(kpt);
						}
					}
				}


			}



		}




		//计算描述符


		if (_descriptors.needed())
		{
			Ptr<SIFT>  PtrSIFT = cv::SIFT::create();
			int dsize = 128;
			_descriptors.create((int)pkeypoints.size(), dsize, CV_32F);
			Mat descriptors = _descriptors.getMat();

#pragma omp parallel for
			for (int i = 0; i < pkeypoints.size(); i++)
			{
				std::vector<KeyPoint> pk = pkeypoints[i];
				Mat normalPatch = vNormalPatches[i];

				Mat tmpDesc;
				PtrSIFT->compute(normalPatch, pk, tmpDesc);
				tmpDesc.row(0).copyTo(descriptors.row(i));
			}

		}

	}

如果输入的是彩色图像,那么opencv会自动调用MSCR,MSCR会合并重复提取的区域(差异性非常小的区域)。外点剔除同时采用单应矩阵和基础矩阵,阈值分别为8和6像素。匹配结果如下(牛津数据 graf 1-4):

使用默认参数,灰度图像有1K个匹配点,彩色图像只有不到100个。原因是:

1、灰度图像提取的时候,很多区域被重复提取,彩色图像基本不存在这个问题。

2、匹配过程中 ,使用的最近邻匹配,匹配点数相当于最大召回点数了。如果使用最近邻次近邻距离比,灰度图像的匹配数量也会下降很多。经测试,距离比值阈值设置为0.8时,匹配数量只有252个了。这说明,的确存在大量的区域被重复多次提取了。

另外,经过测试graf 1-6的匹配,使用灰度图像,匹配策略使用最近邻,有300+个匹配点了。

 wall数据,使用默认参数,匹配数量很少,wall 1-6。

总结,

MSER算是一个比较不错的仿射不变特征了,但是对于纹理的要求比较高,要求大量的面积较大的斑点,斑点的边缘不能太模糊。

MSER对应的稳定区域的要求是非常严格的,并且原生的MSER会重复提取同一个区域,导致常用的最近次近距离比值并不是很适合。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值