无人机对地面运动目标定位---获取目标的移动方向和速度

news2025/2/22 19:46:00

目录

一、引子

        我们利用单目无人机通过等时间间隔拍照的形式对地面某移动目标进行定位,当前,我们已经获得了每张相片上该目标的三维坐标,并且知道该无人机在飞行过程中拍照的时间间隔,那么我们就可以通过一定的计算,得到目标的运动方向和运动速度。

二、代码解释

1.导入的数据是由相片名称及目标点的三维数据构成的txt文件,所以我们需要建立字符串分割函数,获取txt文件内的数据。

2.定义圆周率数值

3.定义方向计算函数

4.从txt文件提取所需信息

5.计算目标在相邻相片间的方向变化角

6.计算目标在相邻相片间的移动距离及运动速度

三、完整代码展示

四、结果展示

本文所有代码均由CSDN用户CV-X.WANG提供,任何个人或者团体,不得进行商用和教学活动,引用或部分引用,均需获得授权。


一、引子

        我们利用单目无人机通过等时间间隔拍照的形式对地面某移动目标进行定位,当前,我们已经获得了每张相片上该目标的三维坐标,并且知道该无人机在飞行过程中拍照的时间间隔,那么我们就可以通过一定的计算,得到目标的运动方向和运动速度。

二、代码解释

1.导入的数据是由相片名称及目标点的三维数据构成的txt文件,所以我们需要建立字符串分割函数,获取txt文件内的数据。

//字符串分割
vector<string> split(const string &s, char delimiter) {
	vector<string> tokens;
	string token;
	istringstream tokenStream(s);
	while (getline(tokenStream, token, delimiter)) {
		tokens.push_back(token);
	}
	return tokens;
}

2.定义圆周率数值

#define M_PI       3.14159265358979323846   // pi

3.定义方向计算函数

为获取目标在平面方向的移动方向,本文采用了在军事领域常见的360°方向法。即以正北为0°方向,顺时针方向为0-360°,比如说,正东方向:在我们的方向系统中即为90°方向。

这其中,

 double lon1_rad = lon1 * M_PI / 180.0;
 double lat1_rad = lat1 * M_PI / 180.0;
 double lon2_rad = lon2 * M_PI / 180.0;
 double lat2_rad = lat2 * M_PI / 180.0;

为弧度制。

//方向函数
double calculateDirectionAngle(double lon1, double lat1, double lon2, double lat2) {
	// Convert degrees to radians
	double lon1_rad = lon1 * M_PI / 180.0;
	double lat1_rad = lat1 * M_PI / 180.0;
	double lon2_rad = lon2 * M_PI / 180.0;
	double lat2_rad = lat2 * M_PI / 180.0;

	// Calculate delta longitude and convert to radians
	double delta_lon_rad = (lon2 - lon1) * M_PI / 180.0;

	// Calculate y and x components
	double y = sin(delta_lon_rad) * cos(lat2_rad);
	double x = cos(lat1_rad) * sin(lat2_rad) - sin(lat1_rad) * cos(lat2_rad) * cos(delta_lon_rad);

	// Calculate direction angle in radians
	double direction_rad = atan2(y, x);

	// Convert direction angle to degrees
	double direction_deg = direction_rad * 180.0 / M_PI;

	// Ensure direction angle is within [0, 360) degrees
	if (direction_deg < 0) {
		direction_deg += 360.0;
	}

	return direction_deg;
}

4.从txt文件提取所需信息


	ifstream file("LBH.txt");
	if (!file.is_open()) {
		cerr << "Could not open the file!" << endl;
		return 1;
	}

	string line;
	// Skip the header line
	getline(file, line);

	vector<vector<string>> extractedData;

	// Read each line from the file
	while (getline(file, line)) {
		vector<string> columns = split(line, '\t');
		if (columns.size() < 16) {
			cerr << "Invalid line format" << endl;
			continue;
		}

		// Extract the required columns: 0, 13, 14, 15
		vector<string> extractedColumns;
		extractedColumns.push_back(columns[0]);  // Image Name
		extractedColumns.push_back(columns[13]); // Longitude
		extractedColumns.push_back(columns[14]); // Latitude
		extractedColumns.push_back(columns[15]); // Altitude

		extractedData.push_back(extractedColumns);
	}

	file.close();

5.计算目标在相邻相片间的方向变化角

cout << "Direction angles between adjacent image centers:" << endl;
	for (size_t i = 1; i < extractedData.size(); ++i) {
		//三角函数计算用弧度制
		double lon1 = (stod(extractedData[i - 1][1]))* M_PI/180; // Longitude 
		double lat1 = (stod(extractedData[i - 1][2]))* M_PI / 180; // Latitude 
		double lon2 = (stod(extractedData[i][1]))* M_PI / 180;   // Longitude 
		double lat2 = (stod(extractedData[i][2]))* M_PI / 180;   // Latitude 
		//计算方向变化角也要用弧度制
		double direction_angle = calculateDirectionAngle(lon1, lat1, lon2, lat2);
		cout << "lon1=" << lon1 << endl << "lat1=" << lat1 << endl << "lon2=" << lon2 << endl << "lat2=" << lat2 << endl;
		// Output Direction
		cout << "Direction from " << extractedData[i - 1][0] << " to " << extractedData[i][0] << ": " << direction_angle << " degrees" << endl;

6.计算目标在相邻相片间的移动距离及运动速度

请注意:此处我们获得距离的计算式为:

这只是最简单的一个演示,实际情况下,我们需要考虑坐标系统、测区位置等等一系列的条件,从而获得更为精准的Distance。

double lon2_1 = lon2 - lon1;
		double lat2_1 = lat2 - lat1;
		double lon_ = lon2_1 / 2;//1/2的Δlon
		double lat_ = lat2_1 / 2; //1 / 2的Δlat
		double sin2lon_ = sin(lon_)*sin(lon_);//sin²(1/2Δlon)
		double sin2lat_ = sin(lat_)*sin(lat_); //sin²(1 / 2Δlat)
		double cos_lat1 = cos(lat1);
		double cos_lat2 = cos(lat2);
		double sqrtA = sqrt(sin2lat_+ cos_lat1* cos_lat2*sin2lon_);
		//cout << "Direction from " << extractedData[i - 1][0] << " to " << extractedData[i][0] << ": " << "sqrtA =" << sqrtA << endl;
		double asinA = asin(sqrtA);
		//长半轴 短半轴  单位是m
		int a_r = 6378137.0;
		int b_r = 6356752;
		double Earth_R = (2 * a_r + b_r) / 3;
		double Distance = 2 * Earth_R*asinA;
		cout << "Distance From " << extractedData[i - 1][0] << " to " << extractedData[i][0] << ": " << "=" << Distance <<" meter"<< endl;
		int time = 3;//拍照间隔 s
		double speed = Distance / time;
		cout << "Speed From " << extractedData[i - 1][0] << " to " << extractedData[i][0] << ": " << "=" << speed << " meter per second" << endl;
	}

三、完整代码展示

#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <cmath>

using namespace std;
#define M_PI       3.14159265358979323846   // pi
// Function to split a string by a delimiter
vector<string> split(const string &s, char delimiter) {
	vector<string> tokens;
	string token;
	istringstream tokenStream(s);
	while (getline(tokenStream, token, delimiter)) {
		tokens.push_back(token);
	}
	return tokens;
}

//  direction angle in degrees
//原理是 在平面上以正北方向为0°方向,顺时针为0-360°
double calculateDirectionAngle(double lon1, double lat1, double lon2, double lat2) {
	// Convert degrees to radians
	double lon1_rad = lon1 * M_PI / 180.0;
	double lat1_rad = lat1 * M_PI / 180.0;
	double lon2_rad = lon2 * M_PI / 180.0;
	double lat2_rad = lat2 * M_PI / 180.0;

	// Calculate delta longitude and convert to radians
	double delta_lon_rad = (lon2 - lon1) * M_PI / 180.0;

	// Calculate y and x components
	double y = sin(delta_lon_rad) * cos(lat2_rad);
	double x = cos(lat1_rad) * sin(lat2_rad) - sin(lat1_rad) * cos(lat2_rad) * cos(delta_lon_rad);

	// Calculate direction angle in radians
	double direction_rad = atan2(y, x);

	// Convert direction angle to degrees
	double direction_deg = direction_rad * 180.0 / M_PI;

	// Ensure direction angle is within [0, 360) degrees
	if (direction_deg < 0) {
		direction_deg += 360.0;
	}

	return direction_deg;
}

int main() {
	ifstream file("LBH.txt");
	if (!file.is_open()) {
		cerr << "Could not open the file!" << endl;
		return 1;
	}

	string line;
	// Skip the header line
	getline(file, line);

	vector<vector<string>> extractedData;

	// Read each line from the file
	while (getline(file, line)) {
		vector<string> columns = split(line, '\t');
		if (columns.size() < 16) {
			cerr << "Invalid line format" << endl;
			continue;
		}

		// Extract the required columns: 0, 13, 14, 15
		vector<string> extractedColumns;
		extractedColumns.push_back(columns[0]);  // Image Name
		extractedColumns.push_back(columns[13]); // Longitude
		extractedColumns.push_back(columns[14]); // Latitude
		extractedColumns.push_back(columns[15]); // Altitude

		extractedData.push_back(extractedColumns);
	}

	file.close();
	
	// Calculate direction angles between adjacent image centers
	cout << "Direction angles between adjacent image centers:" << endl;
	for (size_t i = 1; i < extractedData.size(); ++i) {
		//三角函数计算用弧度制
		double lon1 = (stod(extractedData[i - 1][1]))* M_PI/180; // Longitude 
		double lat1 = (stod(extractedData[i - 1][2]))* M_PI / 180; // Latitude 
		double lon2 = (stod(extractedData[i][1]))* M_PI / 180;   // Longitude 
		double lat2 = (stod(extractedData[i][2]))* M_PI / 180;   // Latitude 
		//计算方向变化角也要用弧度制
		double direction_angle = calculateDirectionAngle(lon1, lat1, lon2, lat2);
		cout << "lon1=" << lon1 << endl << "lat1=" << lat1 << endl << "lon2=" << lon2 << endl << "lat2=" << lat2 << endl;
		// Output Direction
		cout << "Direction from " << extractedData[i - 1][0] << " to " << extractedData[i][0] << ": " << direction_angle << " degrees" << endl;

		double lon2_1 = lon2 - lon1;
		double lat2_1 = lat2 - lat1;
		double lon_ = lon2_1 / 2;//1/2的Δlon
		double lat_ = lat2_1 / 2; //1 / 2的Δlat
		double sin2lon_ = sin(lon_)*sin(lon_);//sin²(1/2Δlon)
		double sin2lat_ = sin(lat_)*sin(lat_); //sin²(1 / 2Δlat)
		double cos_lat1 = cos(lat1);
		double cos_lat2 = cos(lat2);
		double sqrtA = sqrt(sin2lat_+ cos_lat1* cos_lat2*sin2lon_);
		//cout << "Direction from " << extractedData[i - 1][0] << " to " << extractedData[i][0] << ": " << "sqrtA =" << sqrtA << endl;
		double asinA = asin(sqrtA);
		//长半轴 短半轴  单位是m
		int a_r = 6378137.0;
		int b_r = 6356752;
		double Earth_R = (2 * a_r + b_r) / 3;
		double Distance = 2 * Earth_R*asinA;
		cout << "Distance From " << extractedData[i - 1][0] << " to " << extractedData[i][0] << ": " << "=" << Distance <<" meter"<< endl;
		int time = 3;//拍照间隔 s
		double speed = Distance / time;
		cout << "Speed From " << extractedData[i - 1][0] << " to " << extractedData[i][0] << ": " << "=" << speed << " meter per second" << endl;
	}
	//cin.get();
	
	return 0;
}

四、结果展示

本文所有代码均由CSDN用户CV-X.WANG提供,任何个人或者团体,不得进行商用和教学活动,引用或部分引用,均需获得授权。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1891832.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker学习笔记(一)概念理解

一、什么是docker容器 Docker容器是一种轻量级、可移植的软件封装技术&#xff0c;它允许开发者将应用程序及其依赖、配置文件、运行环境等打包到一个独立的、自包含的执行单元中。容器与虚拟机相似&#xff0c;都提供了隔离的运行环境&#xff0c;但容器更加轻量级&#xff0c…

职业本科扩容:教育改革的新篇章与挑战

高考结束后&#xff0c;李文莉同学并没有如释重负的感觉&#xff0c;因为她正在为选学校、选专业而纠结。幸运的是&#xff0c;今年我国职业本科院校又增加了十多所&#xff0c;这对学习成绩稍差、但动手能力较强的她来说&#xff0c;无疑是个好消息。这几天&#xff0c;她已将…

《数字图像处理与机器视觉》案例四 基于分水岭算法的粘连物体的分割与计数

一、引言 分水岭算法&#xff08;Watershed Algorithm&#xff09;&#xff0c;是一种基于拓扑理论的数学形态学的分割方法&#xff0c;其基本思想是把图像看作是测地学上的拓扑地貌&#xff0c;图像中每一点像素的灰度值表示该点的海拔高度&#xff0c;每一个局部极小值及其影…

【Python123题库】#判断闰年 #判断奇偶数 #分段函数A

禁止转载&#xff0c;原文&#xff1a;https://blog.csdn.net/qq_45801887/article/details/140079827 参考教程&#xff1a;B站视频讲解——https://space.bilibili.com/3546616042621301 有帮助麻烦点个赞 ~ ~ Python123题库 判断闰年判断奇偶数分段函数A 判断闰年 类型&am…

静态方法与实例方法的区别

静态方法与实例方法的区别 1、静态方法&#xff08;Static Methods&#xff09;1.1 调用方式1.2 访问权限 2、实例方法&#xff08;Instance Methods&#xff09;2.1 调用方式2.2 访问权限 3、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1…

DDR3(一)

目录 1 SDRAM1.1 同步动态随机存储器1.2 位宽1.3 SDRAM结构1.4 SDRAM引脚图 2 SDRAM操作指令2.1 读写指令2.2 刷新和预充电2.3 配置模式寄存器2.4 读/写突发2.5 数据屏蔽 SDRAM是DDR3的基础&#xff0c;在学习DDR3之前&#xff0c;我们先来学习一下SDRAM的相关知识。 1 SDRAM …

Spring容器生命周期中如前置运行程序和后置运行程序

在Spring容器加入一个实现了BeanPostProcessor接口bean实例&#xff0c;重写postProcessBeforeInitialization、postProcessAfterInitialization方法&#xff0c;在方法里面写具体的实现&#xff0c;从而达到Spring容器在初如化前或销毁时执行预定的程序&#xff0c;方法如下&a…

浅谈 Linux 中的 core dump 分析方法

文章目录 一、什么是 core dump二、发生 core dump 的原因1. 空指针或非法指针引起 core dump2. 数组越界或指针越界引起的 core dump3. 数据竞争导致 core dump4. 代码不规范 三、core dump 分析方法1. 启用 core dump2. 触发 core dump2-1. 因空指针解引用而崩溃2-2. 通过 SI…

S272钡铼技术4G无线RTU支持多路DIN输入和模拟量转换至4G网络

钡铼第四代RTU S272是一款先进的工业级4G远程遥测终端&#xff0c;为各种远程工业数据采集和控制系统提供了高效解决方案。结合了现代通信技术和多功能的输入输出接口&#xff0c;S272不仅支持多路数字量和模拟量输入&#xff0c;还具备灵活的扩展性和强大的控制功能&#xff0…

如何利用小猪APP分发轻松将网页封装成APP

什么是网页封装APP&#xff1f; 假设你有一个非常棒的网站&#xff0c;但你希望用户能更方便地在手机上访问它。你可能会考虑将该网页封装成一个APP。封装APP其实就是将网页内容打包成一个移动应用&#xff0c;这样用户可以像使用其他APP一样方便地使用你的服务。 APP分发www…

大华设备接入GB28181/GAT1400视频汇聚管理平台EasyCVR安防监控系统的具体操作步骤

智慧城市/视频汇聚/安防监控平台EasyCVR兼容性强&#xff0c;支持多协议接入&#xff0c;包括国标GB/T 28181协议、GA/T 1400协议、部标JT808协议、RTMP、RTSP/Onvif协议、海康Ehome、海康SDK、大华SDK、华为SDK、宇视SDK、乐橙SDK、萤石云SDK等&#xff0c;并能对外分发RTMP、…

动物检测yolo格式数据集(水牛 、大象 、犀牛 、斑马四类)

动物检测数据集 1、下载地址&#xff1a; https://download.csdn.net/download/qq_15060477/89512588?spm1001.2101.3001.9500 2、数据集介绍 本数据集含有四种动物可以检测&#xff0c;分别是水牛 、大象 、犀牛 、斑马四类&#xff0c;数据集格式为yolo格式&#xff0c;…

java进行音视频的拆分和拼接

一、下载ffmpeg并安装 官网地址https://ffmpeg.org/download.html 载后解压缩如下 D:\google-download\ffmpeg-2024-01-28-git-e0da916b8f-essentials_build\bin>ls ffmpeg.exe ffplay.exe ffprobe.exe 展示三个exe可执行文件 配置环境变量 配置后直接在cmd输入ffmpeg…

首家!腾讯云数据万象通过中国信通院智能存储专项测试

2024年6月19日&#xff0c;由中国通信标准化协会主办&#xff0c;中国通信标准化协会大数据技术标准推进委员会(CCSA TC601)承办的首届“数据智能大会”在京隆重召开。腾讯云存储受邀出席了活动&#xff0c;大会中“可信数据智能”系列评估测试结果正式颁布&#xff0c;经过严苛…

AI是在帮助开发者还是取代他们?

一&#xff1a;介绍 生成式人工智能&#xff08;AIGC&#xff09;在软件开发领域的应用确实为开发者带来了很多便利和效率提升。AI工具可以通过代码生成、错误检测、自动化测试等功能&#xff0c;帮助开发者更快速地开发和优化软件&#xff0c;减少重复性工作&#xff0c;提高…

商标的近似分辩,商标起名称时注意!

曾有过网友发来商标名称&#xff0c;普推知商标老杨说有近似&#xff0c;然后网友起过新名称还是存有近似&#xff0c;或者加字&#xff0c;后面加的通用词&#xff0c;与先有商标名称也是近似。 “良信健康”这个名称健康是行业通用词&#xff0c;加成健康后变成四个字&#x…

C++ 语法

一、头文件与源文件 头文件用于声明函数,类似于java中service层的接口; 源文件用于实现头文件函数,相当于java中serviceImpl层的实现类; 定义接口 实现接口 使用接口 二、指针概述 定义与使用 定义一个指针p用于存a变量的内存地址,即指针就是地址; 解引用可以获取或修改…

【C++】 解决 C++ 语言报错:Double Free or Corruption

文章目录 引言 双重释放或内存破坏&#xff08;Double Free or Corruption&#xff09;是 C 编程中常见且严重的内存管理问题。当程序尝试多次释放同一块内存或对已经释放的内存进行操作时&#xff0c;就会导致双重释放或内存破坏错误。这种错误不仅会导致程序崩溃&#xff0c…

提升Android Studio开发体验:使用Kelp插件实现颜色和图标预览

提升Android Studio开发体验&#xff1a;使用Kelp插件实现颜色和图标预览 在Android开发中&#xff0c;自动补全功能对于提高开发效率至关重要。然而&#xff0c;默认的Android Studio并不能预览颜色和图标&#xff0c;这使得开发者在选择资源时常常感到困惑。本文将介绍如何使…

sql优化-单表优化

文章目录 0、索引优化原则1、在docker内部连接mysql2、数据准备3、创建表 dept 和 emp4、插入50万数据到 emp 表中4.1、创建函数4.2、存储过程4.3、调用存储过程 5、查找姓名以"abc"开头的员工信息5.1、执行计划 select * from emp where name like abc%;5.2、sql优化…