Moraver算子提取影像特征点

01 Moraver算子

1.基本原理

        Moravec于1977年提出利用灰度方差提取点特征的算子,是一种基于灰度方差的角点检测方法,它通过计算图像中每个像素点沿着水平、垂直、对角线及反对角线的四个方向的灰度方差来检测角点。

2.算法步骤

(1)兴趣值计算

        对于图像中的每个像素点,以其为中心取一个窗口,计算该窗口内像素在四个方向上的灰度差的平方和。如公式(1)所示。(注意在此处c为列,r为行)。

         其中K为窗口大小一半取整,对于整幅图像来说,窗口大小可以忽略不计,因此不考虑边缘像素处理。

        取计算结果的最小值作为兴趣值。

(2)阈值筛选

        给定一个经验阈值,将兴趣值大于该阈值的点作为候选点。

(3)非极大值抑制

        给定另一个窗口,选取兴趣值最大的点,作为特征点。

02 C语言(c++)代码实现

#include <iostream>
#include <stdio.h>
#include <omp.h>
#include <opencv2/opencv.hpp>
#include <iomanip>

using namespace cv;
using namespace std;
//文件读取,灰度图或者RGB图像
void readData(const char* filePath, int r, Mat& img) {
	if (r == 1)
		img = imread(filePath, IMREAD_GRAYSCALE);
	else
		img = imread(filePath);
}
//计算兴趣值
void Moravec_iv(Mat& iv, Mat img, int win_size) {
	int k = win_size / 2;
	for (int i = k; i < img.rows - k; i++) {
		for (int j = k; j < img.cols - k; j++) {
			double v1 = 0, v2 = 0, v3 = 0, v4 = 0;
			for (int l = -k; l <= k - 1; l++) {
				double temp1 = img.at<uchar>(i, j + l) - img.at<uchar>(i, j + l + 1);
				v1 += temp1 * temp1;
				double temp2 = img.at<uchar>(i + l, j + l) - img.at<uchar>(i + l + 1, j + l + 1);
				v2 += temp2 * temp2;
				double temp3 = img.at<uchar>(i + l, j) - img.at<uchar>(i + l + 1, j);
				v3 += temp3 * temp3;
				double temp4 = img.at<uchar>(i - l, j + l) - img.at<uchar>(i - l - 1, j + l + 1);
				v4 += temp4 * temp4;
			}
			iv.at<double>(i, j) = fmin(fmin(v1, v2), fmin(v3, v4));
		}
	}
}
//阈值筛选
void Moravec_threshold_value_points(Mat& iv, Mat img, int win_size, double threshold_value) {
	for (int i = 0; i < img.rows; i++) {
		for (int j = 0; j < img.cols; j++) {
			if (iv.at<double>(i, j) > threshold_value)
				iv.at<double>(i, j) = iv.at<double>(i, j);
			else
				iv.at<double>(i, j) = 0;
		}
	}
}
//寻找抑制窗口内的极大值
void find_max_in_window(Mat img, Mat iv, int window_size, int row, int col, int& max_row, int& max_col) {
	int k = window_size / 2;
	double max_value = 0;
	max_row = -1;
	max_col = -1;

	for (int i = -k; i <=k; i++) {
		for (int j = -k; j <= k; j++) {
			int r = row + i;
			int c = col + j;
			if (r >= 0 && r < img.rows && c >= 0 && c < img.cols) {
				double value = iv.at<double>(r, c);
				if (value > max_value) {
					max_value = value;
					max_row = r;
					max_col = c;
				}
			}
		}
	}
}
//特征点选取
void Moravec_extremum_points(Mat iv, Mat img, Mat& mask, int win_size1, int win_size2, double threshold_value) {
	int k = win_size2 / 2;
    //注意为整个窗口滑动而不是逐个像素滑动
	for (int i = k; i < img.rows - k; i+= win_size2){
		for (int j = k; j < img.cols - k; j+= win_size2){
			int max_row, max_col;
			find_max_in_window(img, iv, win_size2, i, j, max_row, max_col);
			if (max_row >= 0 && max_row < img.rows && max_col >= 0 && max_col < img.cols)
			mask.at<double>(max_row, max_col) = 1;
		}
	}
}

int main() {
	Mat img;
	const char* filePath = "img.jpg";
	readData(filePath, 1, img);
	if (img.empty()) {
		cerr << "无法读取图像文件: " << filePath << endl;
		return -1;
	}
	cout << "文件已经读取" << endl;

	Mat iv = Mat::zeros(img.rows, img.cols, CV_64F);
	Mat mask = Mat::zeros(img.rows, img.cols, CV_64F);
	int win_size = 5;//兴趣值计算窗口
	int win_size2 = 100;//抑制窗口
	int threshold_value = 2000;//经验阈值
	Moravec_iv(iv, img, win_size);
	cout << "兴趣值已经计算" << endl;
	Moravec_threshold_value_points(iv, img, win_size, threshold_value);
	cout << "候选点已经选取" << endl;
	Moravec_extremum_points(iv, img, mask, win_size, win_size2, threshold_value);
	cout << "极值点已经选择" << endl;

	Mat img_with_points;
	readData(filePath, 2, img_with_points);
	int count = 0;
	for (int i = 0; i < mask.rows; i++) {
		for (int j = 0; j < mask.cols; j++) {
			if (mask.at<double>(i, j) == 1) {
				circle(img_with_points, Point(j, i), 2.5, Scalar(0, 0, 255), -1);
				string pointIndex = to_string(count);
				putText(img_with_points, pointIndex, Point(j + 5, i - 5), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255), 1);//根据图像大小需要调整字体,确保正确显示
				count++;
			}
		}
	}

	cout << "共有" << count << "个特征点" << endl;
    //调整图像显示比例
	int screenWidth = 1920;
	int screenHeight = 1080;
	int winWidth = img.cols, winHeight = img.rows;
	double imgRatio = static_cast<double>(img.cols) / img.rows;
	
	if (img.cols > screenWidth)
	{
		winWidth = screenWidth;
		winHeight = winWidth / imgRatio;
	}
	else if (img.rows > screenHeight)
	{
		winHeight = screenHeight;
		winWidth = winHeight * imgRatio;
	}

	namedWindow("Image with Points", WINDOW_NORMAL);
	resizeWindow("Image with Points", winWidth, winHeight);
	imshow("Image with Points", img_with_points);
	waitKey(0);
	destroyAllWindows();
	return 0;
}

03 结果展示

        原始图像:

        提取特征点叠加之后的图像:

智能网联汽车的安全员高级考试涉及多个方面的专业知识,包括但不限于自动驾驶技术原理、车辆传感器融合、网络安全防护以及法律法规等内容。以下是针对该主题的一些核心知识点解析: ### 关于智能网联车安全员高级考试的核心内容 #### 1. 自动驾驶分级标准 国际自动机工程师学会(SAE International)定义了六个级别的自动驾驶等级,从L0到L5[^1]。其中,L3及以上级别需要安全员具备更高的应急处理能力。 #### 2. 车辆感知系统的组成与功能 智能网联车通常配备多种传感器,如激光雷达、毫米波雷达、摄像头和超声波传感器等。这些设备协同工作以实现环境感知、障碍物检测等功能[^2]。 #### 3. 数据通信与网络安全 智能网联车依赖V2X(Vehicle-to-Everything)技术进行数据交换,在此过程中需防范潜在的网络攻击风险,例如中间人攻击或恶意软件入侵[^3]。 #### 4. 法律法规要求 不同国家和地区对于无人驾驶测试及运营有着严格的规定,考生应熟悉当地交通法典中有关自动化驾驶部分的具体条款[^4]。 ```python # 示例代码:模拟简单决策逻辑 def decide_action(sensor_data): if sensor_data['obstacle'] and not sensor_data['emergency']: return 'slow_down' elif sensor_data['pedestrian_crossing']: return 'stop_and_yield' else: return 'continue_driving' example_input = {'obstacle': True, 'emergency': False, 'pedestrian_crossing': False} action = decide_action(example_input) print(f"Action to take: {action}") ``` 需要注意的是,“橙点同学”作为特定平台上的学习资源名称,并不提供官方认证的标准答案集;建议通过正规渠道获取教材并参加培训课程来准备此类资格认证考试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值