Moravec(莫拉维克)影像特征点提取(含原理与C代码)

目录

一、Moravec算子介绍

1.基本原理

这是一种基于灰度方差的角点检测算子,该算子计算图像中每个像素点沿着水平、垂直、对角线及反对角线的四个方向的灰度方差,其中的最小值选作该像素点的兴趣值 IV,再通过局部非极大值抑制来检测其是否为特征点(角点)。

2.算法步骤

(1)计算各像元的兴趣值 IV(Interest Value) 。以像素(c,r) 为中心的 _w x w_的影像窗口(如 5×5 的窗口),计算下图中所示四个方向相邻像素灰度差的平方和:

Moravec(莫拉维克)影像特征点提取(含原理与C代码)
其计算公式为:
Moravec(莫拉维克)影像特征点提取(含原理与C代码)
其中 k =INT (w/ 2),即窗口的一半取整。取其中最小者作为该像素(c,r)的兴趣值。

(2)给定一经验阈值,将兴趣值大于该阈值的点作为候选点。阈值的原则应 以候选点中包括的所需要的特征点而又不含过多的非特征点为原则。
(3)选取候选点中的极值点作为特征点。在一定大小的窗口内,将候选点中兴趣值不是最大者均去掉,仅留下一个兴趣值最大者,该像素即为一个特征点(抑制局部非最大)。

; 二、基于C语言的算法描述

1.影像数据介绍

已知同一地点的左右两张 bmp 格式的影像,其中左影像的大小为 1023x942px,右影像的大小为 805×887 px,如下图所示:

Moravec(莫拉维克)影像特征点提取(含原理与C代码)

; 2.编程思路

  • 使用 OpenCV 以灰度图的方式读取目标影像(左);
  • 定义一个指定大小的兴趣值窗口wxw,其一半大小为k = int(w/ 2);
  • 定义与目标图像相同大小的单通道兴趣值矩阵valueMat ,用来存储每个像素的兴趣值(外围像素由于无法计算则默认为 0);
  • 以图像左上角为原点,从图像的第(k, k) 个元素开始,滑动此窗口,同时计算每个窗口中心像素四个方向相邻像素的灰度差平方和,并选取最小值作为中心像素的兴趣值,接着将其存入valueMat ,这样就把兴趣值及其坐标关联起来;
  • 定义一个抑制窗口m x m ,其一半大小为n = int(m / 2) ;
  • 定从valueMat 矩阵的第(n, n) 像素开始,以其为中心滑动抑制窗口,选出窗口内兴趣值最大的像素点,若其兴趣值大于给定阈值,则其作为特征点。为了避免特征点的重叠,该抑制窗口的大小可以设置得稍大一些。这样就得到了特征点的坐标(x, y),将其存入 vector 数组;
  • 以 RGB 方式重新读取目标影像(为了标记效果明显),遍历 vector 特征点数组,将其标记在新的目标影像中即得到目标影像特征点提取结果。

3.特征点提取算法阈值设定分析

  • 首先,统计每个抑制窗口内最大兴趣值,并进行可视化:

Moravec(莫拉维克)影像特征点提取(含原理与C代码)
  • 进一步,对其进行细化得到如下图:
    Moravec(莫拉维克)影像特征点提取(含原理与C代码)
    设置兴趣值窗口为7,已知窗口为21,调节阈值得到如下结果:
  • 阈值threshold=1000:

Moravec(莫拉维克)影像特征点提取(含原理与C代码)
  • 阈值threshold=1500,2000:
    Moravec(莫拉维克)影像特征点提取(含原理与C代码)
    结论:最后分析以上三图,可知当阈值为 1000 时的非明显特征点较多,因此应当提高阈值,结合散点图,阈值应该大于 1500,当阈值等于 1500 时,图像仍存在一些非特征点;当阈值提到到 2000 时,虽然非明显特征点被舍去,但是一些明显特征点也被舍去(如图九,图十中红圈所示),因此阈值应该介于 1500-2000。最终结合视觉效果,阈值选为 1700:
    Moravec(莫拉维克)影像特征点提取(含原理与C代码)

; 4.窗口大小对特征点提取结果的影响

1.兴趣值窗口:

  • 兴趣值窗口直接影响 Moravec 算子提取的特征点的个数,兴趣值窗口直接影响 Moravec 算子提取的特征点的个数:

兴趣值窗口特征点个数556277889*9133

2.抑制窗口:

  • 影响特征点的密度,密度越低,特征点的个数越少。

三、代码实现

1.OpenCV的配置

2.C语言代码

#include"stdafx.h"
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;

Mat Moravec(Mat srcImg, int  winSize, int threshold, int restrainWinSize,  vector <Point3f> &featurePt);

int main()
{

    string image_path= "u0369_panLeft.bmp";

    Mat img_source = imread(image_path, IMREAD_GRAYSCALE);

    if (img_source.empty())
    {
        cout<<"Could not read the imageL"<<endl;
        system("pause");
        return 1;
    }

    int  winSize = 9;

    vector <Point3f> featurePt1;

    cout<<"正在进行影像特征点随机提取...."<<endl;

    clock_t start1 = clock();

    Mat featureImg = Moravec(img_source, winSize, 1700,21,featurePt1);
    clock_t finish1 = clock();
    cout << "耗时:" << (double)(finish1 - start1) / CLOCKS_PER_SEC << "s" << endl;

    imshow("特征点提取影像(左)", featureImg);
    waitKey(0);

    imwrite("featureImg1.jpg", featureImg);
    cout << "保存到当前文件目录中" << "featureImg1.jpg" << endl;
    return 0;
}

Mat Moravec(Mat srcImg, int  winSize, int threshold, int restrainWinSize,vector <Point3f> &featurePt)
{

    int rows = srcImg.rows;
    int cols = srcImg.cols;

    int k = winSize / 2;

    Mat valueMat = Mat::zeros(srcImg.rows, srcImg.cols, CV_32FC1);

    for (int c = k; c < srcImg.rows - k; c++)
    {
        for (int r = k; r < srcImg.cols - k; r++)
        {

            int V1 = 0, V2 = 0, V3 = 0, V4 = 0;
            for (int i = -k; i  k - 1; i++)
            {
                V1 += (srcImg.at<uchar>(c + i, r) - srcImg.at<uchar>(c + i + 1, r))*(srcImg.at<uchar>(c + i, r) - srcImg.at<uchar>(c + i + 1, r));
                V2 += (srcImg.at<uchar>(c + i, r + i) - srcImg.at<uchar>(c + i + 1, r + i + 1))*(srcImg.at<uchar>(c + i, r + i) - srcImg.at<uchar>(c + i + 1, r + i + 1));
                V3 += (srcImg.at<uchar>(c, r + i) - srcImg.at<uchar>(c, r + i + 1))*(srcImg.at<uchar>(c, r + i) - srcImg.at<uchar>(c, r + i + 1));
                V4 += (srcImg.at<uchar>(c + i, r - i) - srcImg.at<uchar>(c + i + 1, r - i - 1))*(srcImg.at<uchar>(c + i, r - i) - srcImg.at<uchar>(c + i + 1, r - i - 1));
            }

            float IV = min(min(V1, V2), min(V3, V4));

            valueMat.at<float>(c, r) = IV;
        }
    }

    int windowSize = restrainWinSize;

    int halfWindow = windowSize / 2;
    for (int y = halfWindow; y < valueMat.rows - halfWindow; y += windowSize)
    {
        for (int x = halfWindow; x < valueMat.cols - halfWindow; x += windowSize)
        {

            float max = 0;

            bool Flag = 0;

            Point3f pt;
            pt.x = -1;
            pt.y = -1;

            pt.z = 0;

            for (int i = -halfWindow; i  halfWindow; i++)
            {
                for (int j = -halfWindow; j  halfWindow; j++)
                {
                    float value;

                    value = valueMat.at<float>(y + i, x + j);

                    if (value > max)
                    {
                        max = value;
                        pt.x = x + j;
                        pt.y = y + i;
                        pt.z = value;
                        Flag = 1;
                    }
                }
            }

            if (Flag == 1 && max >threshold)
            {
                featurePt.push_back(pt);
            }
        }
    }

    string image_path = "u0369_panLeft.bmp";

    Mat img_source = imread(image_path, IMREAD_COLOR);

    int radius = 4;
    for (int i = 0; i < featurePt.size(); i++)
    {
        int xx = featurePt.at(i).x;
        int yy = featurePt.at(i).y;

        circle(img_source, Point(xx, yy), radius, Scalar(0, 255, 255), 1, CV_AA);

        putText(img_source, to_string(i), Point(xx+2, yy-2), FONT_HERSHEY_SIMPLEX, 0.4, CV_RGB(255, 0, 0), 1.8,  CV_AA);

        line(img_source, Point(xx - radius - 1, yy), Point(xx + radius + 1, yy), Scalar(0,255 , 255), 1, CV_AA);
        line(img_source, Point(xx, yy - radius - 1), Point(xx, yy + radius + 1), Scalar(0,255, 255), 1, CV_AA);
    }

    return img_source;
}
  • 评价:提取的特征点的在信息丰富的区域很集中,而贫乏区域几乎没有的特点,如最左边几乎没有特征点。
  • 特征点提取需要控制特征点的密度,在整幅影像中按一定比例选取特征点,并将极值点周围的其他点去掉,这种方法选取的点集中在信息丰富的区域,而在信息贫乏的区域则没有点或很少点。因此为了控制特征点的密度,就需要调节 Moravec 算子中抑制窗口的大小,来减少极值点周围的其他点。

3.最终提取结果图

左影像:

Moravec(莫拉维克)影像特征点提取(含原理与C代码)

; 四、均匀特征点提取

1.保持兴趣值窗口为 7,阈值设为 0,抑制窗口为 100 (很大就行,目的就是抑制完全周围一定范围的点,相当于画了格网一样),这种方法就相当于把整幅图像均匀分割成许多 100*100 的小图像,然后每个小图像里选取一个特征点。这种方法得到的特征点分布均匀,但是有些非特征点也会被提取出来(仅需修改上述代码的窗口、阈值等即可)。
2.结果图如下:

Moravec(莫拉维克)影像特征点提取(含原理与C代码)

五、影像相关系数匹配

待续:基于Moravec算子的影像相关系数匹配:
匹配结果:

Moravec(莫拉维克)影像特征点提取(含原理与C代码)
后续已更新:Moravec(莫拉维克)影像特征点提取之相关系数影像匹配
2021.12.25.
Moravec(莫拉维克)影像特征点提取(含原理与C代码)

Original: https://blog.csdn.net/qq_46877697/article/details/122147221
Author: 山 沐
Title: Moravec(莫拉维克)影像特征点提取(含原理与C代码)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/631794/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球