为什么 RANSAC 不删除 SIFT 匹配中的所有异常值?
Why doesn't RANSAC remove all the outliers in SIFT matches?
我用SIFT检测,描述两张图片的特征点如下。
void FeaturePointMatching::SIFTFeatureMatchers(cv::Mat imgs[2], std::vector<cv::Point2f> fp[2])
{
cv::SiftFeatureDetector dec;
std::vector<cv::KeyPoint>kp1, kp2;
dec.detect(imgs[0], kp1);
dec.detect(imgs[1], kp2);
cv::SiftDescriptorExtractor ext;
cv::Mat desp1, desp2;
ext.compute(imgs[0], kp1, desp1);
ext.compute(imgs[1], kp2, desp2);
cv::BruteForceMatcher<cv::L2<float> > matcher;
std::vector<cv::DMatch> matches;
matcher.match(desp1, desp2, matches);
std::vector<cv::DMatch>::iterator iter;
fp[0].clear();
fp[1].clear();
for (iter = matches.begin(); iter != matches.end(); ++iter)
{
//if (iter->distance > 1000)
// continue;
fp[0].push_back(kp1.at(iter->queryIdx).pt);
fp[1].push_back(kp2.at(iter->trainIdx).pt);
}
// remove outliers
std::vector<uchar> mask;
cv::findFundamentalMat(fp[0], fp[1], cv::FM_RANSAC, 3, 1, mask);
std::vector<cv::Point2f> fp_refined[2];
for (size_t i = 0; i < mask.size(); ++i)
{
if (mask[i] != 0)
{
fp_refined[0].push_back(fp[0][i]);
fp_refined[1].push_back(fp[1][i]);
}
}
std::swap(fp_refined[0], fp[0]);
std::swap(fp_refined[1], fp[1]);
}
在上面的代码中,我使用findFundamentalMat()
去除异常值,但在结果img1 and img2中仍然有一些错误的匹配。在图像中,每条绿线连接匹配的特征点对。请忽略红色标记。我找不到任何错误,任何人都可以给我一些提示吗?提前致谢。
RANSAC代表RANdom SAmple Consensus,它不去除异常值,它选择一组点来计算该组点的基础矩阵。然后你需要使用刚刚用 RANSAC 计算的基本矩阵进行重新投影以去除异常值。
RANSAC 只是稳健的估计器之一。原则上,可以使用多种方法,但 RANSAC 已被证明可以很好地工作,只要您的输入数据不受异常值支配。您可以检查 RANSAC 上的其他变体,如 MSAC、MLESAC、MAPSAC 等,它们也有一些其他有趣的属性。您可能会发现这个 CVPR 演示文稿很有趣 (http://www.imgfsr.com/CVPR2011/Tutorial6/RANSAC_CVPR2011.pdf)
根据输入数据的质量,您可以按此处所述估计最佳 RANSAC 迭代次数 (https://en.wikipedia.org/wiki/RANSAC#Parameters)
同样,它是一种稳健的估计方法。您可以采用其他统计方法,例如使用重尾分布、修剪最小二乘法等对数据建模。
在您的代码中,您缺少 RANSAC 步骤。 RANSAC 基本上有 2 个步骤:
generate hypothesis (do a random selection of data points necessary to fit your mode: training data).
model evaluation (evaluate your model on the rest of the points: testing data)
iterate and choose the model that gives the lowest testing error.
与任何算法一样,ransac 并不完美。您可以尝试 运行 其他不负责任的(在 opencv 实现中)健壮的算法,例如 LMEDS。您可以重申,使用最后标记为异常值的点作为新估计的输入。您可以改变阈值和置信度。我建议 运行 ransac 1 ~ 3 次然后 运行 LMEDS,它不需要阈值,但只适用于至少 +50% 的内点。
而且,您可能会遇到几何顺序问题:
*如果两个立体声之间的基线太小,基本矩阵估计可能不可靠,为了您的目的,最好使用 findHomography() 代替。
*如果您的图像有一些 barrel/pincushin 失真,它们不符合对极几何并且基本矩阵不是 link 匹配的正确数学模型。在这种情况下,您可能需要校准相机,然后 运行 undistort() 然后处理输出图像。
我用SIFT检测,描述两张图片的特征点如下。
void FeaturePointMatching::SIFTFeatureMatchers(cv::Mat imgs[2], std::vector<cv::Point2f> fp[2])
{
cv::SiftFeatureDetector dec;
std::vector<cv::KeyPoint>kp1, kp2;
dec.detect(imgs[0], kp1);
dec.detect(imgs[1], kp2);
cv::SiftDescriptorExtractor ext;
cv::Mat desp1, desp2;
ext.compute(imgs[0], kp1, desp1);
ext.compute(imgs[1], kp2, desp2);
cv::BruteForceMatcher<cv::L2<float> > matcher;
std::vector<cv::DMatch> matches;
matcher.match(desp1, desp2, matches);
std::vector<cv::DMatch>::iterator iter;
fp[0].clear();
fp[1].clear();
for (iter = matches.begin(); iter != matches.end(); ++iter)
{
//if (iter->distance > 1000)
// continue;
fp[0].push_back(kp1.at(iter->queryIdx).pt);
fp[1].push_back(kp2.at(iter->trainIdx).pt);
}
// remove outliers
std::vector<uchar> mask;
cv::findFundamentalMat(fp[0], fp[1], cv::FM_RANSAC, 3, 1, mask);
std::vector<cv::Point2f> fp_refined[2];
for (size_t i = 0; i < mask.size(); ++i)
{
if (mask[i] != 0)
{
fp_refined[0].push_back(fp[0][i]);
fp_refined[1].push_back(fp[1][i]);
}
}
std::swap(fp_refined[0], fp[0]);
std::swap(fp_refined[1], fp[1]);
}
在上面的代码中,我使用findFundamentalMat()
去除异常值,但在结果img1 and img2中仍然有一些错误的匹配。在图像中,每条绿线连接匹配的特征点对。请忽略红色标记。我找不到任何错误,任何人都可以给我一些提示吗?提前致谢。
RANSAC代表RANdom SAmple Consensus,它不去除异常值,它选择一组点来计算该组点的基础矩阵。然后你需要使用刚刚用 RANSAC 计算的基本矩阵进行重新投影以去除异常值。
RANSAC 只是稳健的估计器之一。原则上,可以使用多种方法,但 RANSAC 已被证明可以很好地工作,只要您的输入数据不受异常值支配。您可以检查 RANSAC 上的其他变体,如 MSAC、MLESAC、MAPSAC 等,它们也有一些其他有趣的属性。您可能会发现这个 CVPR 演示文稿很有趣 (http://www.imgfsr.com/CVPR2011/Tutorial6/RANSAC_CVPR2011.pdf)
根据输入数据的质量,您可以按此处所述估计最佳 RANSAC 迭代次数 (https://en.wikipedia.org/wiki/RANSAC#Parameters)
同样,它是一种稳健的估计方法。您可以采用其他统计方法,例如使用重尾分布、修剪最小二乘法等对数据建模。
在您的代码中,您缺少 RANSAC 步骤。 RANSAC 基本上有 2 个步骤:
generate hypothesis (do a random selection of data points necessary to fit your mode: training data).
model evaluation (evaluate your model on the rest of the points: testing data)
iterate and choose the model that gives the lowest testing error.
与任何算法一样,ransac 并不完美。您可以尝试 运行 其他不负责任的(在 opencv 实现中)健壮的算法,例如 LMEDS。您可以重申,使用最后标记为异常值的点作为新估计的输入。您可以改变阈值和置信度。我建议 运行 ransac 1 ~ 3 次然后 运行 LMEDS,它不需要阈值,但只适用于至少 +50% 的内点。
而且,您可能会遇到几何顺序问题:
*如果两个立体声之间的基线太小,基本矩阵估计可能不可靠,为了您的目的,最好使用 findHomography() 代替。
*如果您的图像有一些 barrel/pincushin 失真,它们不符合对极几何并且基本矩阵不是 link 匹配的正确数学模型。在这种情况下,您可能需要校准相机,然后 运行 undistort() 然后处理输出图像。