本章摘要:上一章对目标追踪中的TTC有个大概的讲解。在此基础上,第八、九章将对关键点keypoints方法进行详细的讲解。主要内容:图像上的关键点具备什么样的特征,如何探测;对检测出来的关键点如何描述,以便于和其他关键点区别和匹配;对于不同帧之间的关键点如何实现匹配,进而实现目标追踪。本章主要讲解关键点探测。
图像上那么多像素点,什么样的点叫做关键点了,应该是能够唯一确定位置的点。周边像素值一致或者区别不明显,肯定是难以确定唯一位置的,能够确定位置的地方应该是像素值变化明显的地方,那么它们具备什么样的特征了,看看下图:
是不是可以得到下面的结果,直线上是难以确定唯一位置的,但是角点、椭圆中心可以,它们能够根据周边像素值比较准确的确定其(x, y)位置。后面主要对角点关键点进行分析。
上面的像素变化明显的地方如何度量了,那就是梯度,下面图直观的感受一下。可以看出像素值变化大的地方,梯度值很大。
那梯度值如何计算了,其实和常规梯度计算一样的:
上面公式体现在像素值梯度计算上,怎么样比较方便了,这里采用Sobel operator 梯度计算。下面程序段会帮助了解其原理。
x方向梯度值Ix的计算:
// load image from file
cv::Mat img;
img = cv::imread("./img1.png");
// convert image to grayscale
cv::Mat imgGray;
cv::cvtColor(img, imgGray, cv::COLOR_BGR2GRAY);
// create filter kernel
float sobel_x[9] = {-1, 0, +1,
-2, 0, +2,
-1, 0, +1};
cv::Mat kernel_x = cv::Mat(3, 3, CV_32F, sobel_x);
// apply filter
cv::Mat result_x;
cv::filter2D(imgGray, result_x, -1, kernel_x, cv::Point(-1, -1), 0, cv::BORDER_DEFAULT);
// show result
string windowName = "Sobel operator (x-direction)";
cv::namedWindow( windowName, 1 ); // create window
cv::imshow(windowName, result_x);
cv::waitKey(0); // wait for keyboard input before continuing
在进行上面梯度计算之前,还需要进行高斯平滑。因为原始图片可能会有噪点,可以采用高斯平滑减少他们的影响。
高斯平滑就是采用一定大小的窗口,对图片进行扫描过滤,这样就可以将像素周边的点以一定权重考虑进来,实现平滑的目的。
int filterSize = 5;
int stdDev = 2.0;
cv::GaussianBlur(imgGray, blurred, cv::Size(filterSize, filterSize), stdDev);
比如有下面这样一个角点,如何探测到,并且能够确定其位置了。
采用一个窗口,计算窗口内部像素值的累计和,然后移动窗口,看像素值之后是否会发生明显的变化。图a 两个方向上都不会,图b 只有水平方向上会发生明显变化,图c 两个方向上都会发生明显变化。这两个方向上都会发生明显变化的点,就是我们要找的角点了。
下面进行计算分析:
假如窗口水平和竖直方向分别移动了u, v,那么窗口w内的像素值变化量为:
对第一项进行泰勒展开可得:
带回公式可以得到:
称上面的H为协方差矩阵,其椭圆表示如下图所示。哪个方向越长,代表哪个方向的变化越明显更。
其中半长轴计算如下:
Harris为经典角点探测中比较代表性的,其response计算如下,其中k值一般取 k = 0.04 - 0.06。
经典关键点探测算法,它们更多的关注准确度,速度往往欠佳。
实时关键点检测算法:
关于上面关键点检测算法的应用,详见github,SFND_2D_Feature_Tracking,还对各个算法的性能对比进行了比较。
本章讲解了关键点的检测,下一章将会讨论如何描述检测出来的关键点,以便于和其他关键点区别和匹配。
Udacity 传感器融合课程笔记