C实现简易运动轨迹检测的程序
2013-05-24 17:00
591 查看
2011-4-25
这几天,XXX的项目让我做了一个运动轨迹检测的程序,主要用来检测汽车和给定路线的偏移问题,和定位汽车主要在什么路段上。
如下图
下面是一些算法和资料:
首先,要确定移动的点,也就是汽车和线段之间的距离,不能直接理解成点到直线的距离,因为当出现下面的情况的时候,点P到BC和到A的距离都是一样
的,这样就区分不点到底靠近哪条线上了。很显然,点固然靠近的应该是线段AB,所以我对这种情况进行了一些改进,如果遇到这种情况,那么直接计算P点到B之间的距离。其实这个程序的关键都是算点到线段的距离,而不是点到线段的高,这些要分清楚。
点到线段距离的计算:
点到直线的距离可以直接做垂线求取,但线段是有首尾点的,若要求距离则要考虑首尾点。
点和线段的关系大致可以有下面几种:
有特殊情况,是P点和A或B重合,否则,根据∠PAB或∠PBA的角度可以有图1、图2、图4三种情况(包括点在AB之间,算是零度角)。
我做的算法可以快速、简洁地判断角度是钝角还是锐角。
在求垂线距离时,用海伦公式取代三角函数,使得程序看起来很简洁。
1.
double GetPointDistance(CPoint p1, CPoint p2)
2.
{
3.
return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
4.
}
5.
float GetNearestDistance(CPoint PA, CPoint PB, CPoint P3)
6.
{
7.
8.
//----------图2--------------------
9.
float a,b,c;
10.
a=GetPointDistance(PB,P3);
11.
if(a<=0.00001)
12.
return 0.0f;
13.
b=GetPointDistance(PA,P3);
14.
if(b<=0.00001)
15.
return 0.0f;
16.
c=GetPointDistance(PA,PB);
17.
if(c<=0.00001)
18.
return a;//如果PA和PB坐标相同,则退出函数,并返回距离
19.
//------------------------------
20.
21.
if(a*a>=b*b+c*c)//--------图3--------
22.
return b; //如果是钝角返回b
23.
if(b*b>=a*a+c*c)//--------图4-------
24.
return a; //如果是钝角返回a
25.
26.
//图1
27.
float l=(a+b+c)/2; //周长的一半
28.
float s=sqrt(l*(l-a)*(l-b)*(l-c)); //海伦公式求面积,也可以用矢量求
29.
return 2*s/c;
30.
}
下面的程序虽然没用上,还是用经纬度来判断偏移的,不过也贴上,怕以后用到哈。
根据经纬度坐标计算实际距离
double hypot(double x, double y) {
return sqrt(x * x + y * y);
}
double distance(double wd1, double jd1, double wd2, double jd2) {// 根据经纬度坐标计算实际距离
double x, y, out;
double PI = 3.1415926535898;
double R = 6.371229 * 1e6;
x = (jd2 - jd1) * PI * R * cos( ( (wd1 + wd2) / 2) * PI / 180) / 180;
y = (wd2 - wd1) * PI * R / 180;
out = hypot(x, y);
return out;
}
判断汽车轨迹是否偏离的算法其实不难,因为通过计算点到每个线段的距离,找出最小的距离,判断是否小于门限0.0001度(就是50米)就好了。然后返回一个0或者1。嘿嘿,简单吧。
举个例子,比如有8个点,必然有7个线段,依次计算7个线段的长度,然后计算点到7个线段的距离,找出最小的距离,再拿来和门限比较就OK了。
最近我程序构架思想大改,虽然是C语言,但是我引入C++的面向对象思想,运用封装和抽象的思想,大量使用指针和结构体。我用结构体封装了私有变量和函数,同时也提供公共变量和函数。我尽量给用户最简单的和最傻瓜的使用方法,也方便以后自己。
测试平台:Eclipse CDT
三个文件,.h .c
还有个test.c(主要用来演示)
下面是程序:
//Track_Detect.h
#ifndef TRACK_DETECT_H_
#define TRACK_DETECT_H_
#include
<stdio.h>
#include
<stdlib.h>
#include
<math.h>
#include
<stdint.h>
#define THRESHOLD_MILES 50
#define THRESHOLD_DEGREE 0.0001
struct Road_coordinate
{
double x;
double y;
};
struct GetNearestDistance_Private
{
double TempA,TempB,TempC;
double perimeter;
double area;
double (*GetPointDistance)(struct Road_coordinate p1, struct
Road_coordinate p2);
};
struct MinDistance_Of_Roads_Private
{
uint32_t Data_Size;
uint32_t Data_Resolution;
double *Temp_Data;
double minTemp;
};
struct GPS_Track_Detect_Private
{
//struct Road_coordinate *RXY;
double (*GetNearestDistance)(struct Road_coordinate PA, struct
Road_coordinate PB, struct Road_coordinate PC);
struct MinDistance_Of_Roads_Private
MinDistance_Of_Roads;
};
struct GPS_Track_Detect_Public
{
struct Road_coordinate *set_p;
uint32_t num;
struct Road_coordinate *move_p;
uint8_t MinNum;
double (*MinDistance_Of_Roads)(struct Road_coordinate *set_p,
uint32_t num, struct Road_coordinate *move_p, uint8_t
*MinNum);
};
//外部函数
extern double MinDistance_Of_Roads(struct
Road_coordinate *set_p, uint32_t num, struct Road_coordinate
*move_p, uint8_t *MinNum);
extern uint32_t GPS_Track_Detect(uint32_t
*deviate_flag, double *minValue, struct GPS_Track_Detect_Public
*p);
//注意set_p和move_p是指针
#define GPS_Track_Detect_MinDistance(set_p, num,
move_p, MinNum) MinDistance_Of_Roads(set_p, num, move_p,
MinNum)
#endif
//Track_Detect.c
//门限是0.0001度,就是50米
#include "Track_Detect.h"
//私有函数声明区
static double GetPointDistance(struct
Road_coordinate p1, struct Road_coordinate p2);
static double GetNearestDistance(struct
Road_coordinate PA, struct Road_coordinate PB, struct
Road_coordinate PC);
static double GetPointDistance(struct
Road_coordinate p1, struct Road_coordinate p2)
{
return
sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}
static double GetNearestDistance(struct
Road_coordinate PA, struct Road_coordinate PB, struct
Road_coordinate PC)
{
struct GetNearestDistance_Private *this = (struct
GetNearestDistance_Private *) malloc(sizeof(struct
GetNearestDistance_Private));
this->GetPointDistance =
GetPointDistance;
this->TempA =
this->GetPointDistance(PB,PC);
double return_value = 0.0;
if(this->TempA <= 0.00001)
{
free(this);
return 0.0f;
}
this->TempB =
this->GetPointDistance(PA,PC);
if(this->TempB <=0.00001 )
{
//return_value = this->TempB;
free(this);
return 0.0f;
}
this->TempC =
this->GetPointDistance(PA,PB);
if(this->TempC <= 0.00001)
{
return_value = this->TempA;
free(this);
return return_value;//如果PA和PB坐标相同,则退出函数,并返回距离
}
if(this->TempA * this->TempA
>= this->TempB *
this->TempB + this->TempC *
this->TempC)
{
return_value = this->TempB;
//如果是钝角返回TempB
free(this);
return return_value;
}
if(this->TempB * this->TempB
>= this->TempA *
this->TempA + this->TempC *
this->TempC)
{
return_value = this->TempA;
free(this);
return return_value;
//如果是钝角返回TempA
}
this->perimeter = (this->TempA +
this->TempB + this->TempC) /
2;
//周长的一半
this->area = sqrt(this->perimeter *
(this->perimeter - this->TempA) *
(this->perimeter - this->TempB) *
(this->perimeter -
this->TempC)); //海伦公式求面积,也可以用矢量求
return_value = 2 *
this->area / this->TempC;
free(this);
return return_value;
}
double MinDistance_Of_Roads(struct Road_coordinate
*set_p, uint32_t num, struct Road_coordinate *move_p, uint8_t
*MinNum)
{
uint32_t i = 0;
double return_value = 0.0;
struct GPS_Track_Detect_Private *this = (struct
GPS_Track_Detect_Private *) malloc(sizeof(struct
GPS_Track_Detect_Private));
this->GetNearestDistance =
GetNearestDistance;
this->MinDistance_Of_Roads.Data_Resolution =
sizeof(set_p[0]);
this->MinDistance_Of_Roads.Data_Size =
this->MinDistance_Of_Roads.Data_Resolution *
num;//动态分配数据空间
this->MinDistance_Of_Roads.Temp_Data = (double
*)malloc(this->MinDistance_Of_Roads.Data_Size);
//printf("%d\n",
this->MinDistance_Of_Roads.Data_Size);
//printf("%d\n",
this->MinDistance_Of_Roads.Data_Resolution);
for(i = 0; i <
(this->MinDistance_Of_Roads.Data_Size /
this->MinDistance_Of_Roads.Data_Resolution - 1 );
i++)
{
*(this->MinDistance_Of_Roads.Temp_Data + i) =
this->GetNearestDistance(set_p[i], set_p[i + 1],
*move_p);
//printf("%f\n",*(this->MinDistance_Of_Roads.Temp_Data
+ i));
}
this->MinDistance_Of_Roads.minTemp =
*(this->MinDistance_Of_Roads.Temp_Data +
0);
for(i = 1; i <
(this->MinDistance_Of_Roads.Data_Size /
this->MinDistance_Of_Roads.Data_Resolution - 1 );
i++)
{
if(*(this->MinDistance_Of_Roads.Temp_Data + i)
<
this->MinDistance_Of_Roads.minTemp)
{
this->MinDistance_Of_Roads.minTemp =
*(this->MinDistance_Of_Roads.Temp_Data +
i);
if(MinNum != NULL)
*MinNum = i;
}
}
free(this->MinDistance_Of_Roads.Temp_Data);
return_value =
this->MinDistance_Of_Roads.minTemp;
free(this);
//printf("\n\n\n");
return return_value;
}
//deviate_flag中
0
表示不偏移
1表示偏移
uint32_t GPS_Track_Detect(uint32_t *deviate_flag,
double *minValue, struct GPS_Track_Detect_Public *p)
{
p->MinDistance_Of_Roads =
MinDistance_Of_Roads;
*minValue =
p->MinDistance_Of_Roads(p->set_p,
p->num, p->move_p,
&p->MinNum);
*deviate_flag = THRESHOLD_DEGREE >= *minValue ? 0 :
1;
return 0;
}
//
测试文件,使用范例Track_Detect_test.c
#include "Track_Detect.h"
struct Road_coordinate RoadXY[] = {
{25.037936,98.431538},
{25.035104,98.429070},
{25.046580,98.411377},
{25.049696,98.409866},
{25.050273,98.407812},
{25.053200,98.406574},
{25.056470,98.406300},
{25.056452,98.404327}
};
int main(void) {
struct Road_coordinate test_dat = {.x = 25.050273, .y =
98.407712};
struct GPS_Track_Detect_Public GTDtest_dat;
GTDtest_dat.move_p = &test_dat;
GTDtest_dat.num = 8;
GTDtest_dat.set_p = RoadXY;
double minValue;
uint32_t deviate_flag;
GPS_Track_Detect(&deviate_flag,
&minValue,
>Dtest_dat);
printf("%d\n",GTDtest_dat.MinNum);
printf("\n\n");
printf("%f\n",minValue);
printf("%d\n",deviate_flag);
printf("\n\n");
uint8_t num;
printf("%f\n", GPS_Track_Detect_MinDistance(RoadXY, 8,
&test_dat, &num));
printf("%d\n",num);
return EXIT_SUCCESS;
}
这几天,XXX的项目让我做了一个运动轨迹检测的程序,主要用来检测汽车和给定路线的偏移问题,和定位汽车主要在什么路段上。
如下图
下面是一些算法和资料:
首先,要确定移动的点,也就是汽车和线段之间的距离,不能直接理解成点到直线的距离,因为当出现下面的情况的时候,点P到BC和到A的距离都是一样
的,这样就区分不点到底靠近哪条线上了。很显然,点固然靠近的应该是线段AB,所以我对这种情况进行了一些改进,如果遇到这种情况,那么直接计算P点到B之间的距离。其实这个程序的关键都是算点到线段的距离,而不是点到线段的高,这些要分清楚。
点到线段距离的计算:
点到直线的距离可以直接做垂线求取,但线段是有首尾点的,若要求距离则要考虑首尾点。
点和线段的关系大致可以有下面几种:
有特殊情况,是P点和A或B重合,否则,根据∠PAB或∠PBA的角度可以有图1、图2、图4三种情况(包括点在AB之间,算是零度角)。
我做的算法可以快速、简洁地判断角度是钝角还是锐角。
在求垂线距离时,用海伦公式取代三角函数,使得程序看起来很简洁。
1.
double GetPointDistance(CPoint p1, CPoint p2)
2.
{
3.
return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
4.
}
5.
float GetNearestDistance(CPoint PA, CPoint PB, CPoint P3)
6.
{
7.
8.
//----------图2--------------------
9.
float a,b,c;
10.
a=GetPointDistance(PB,P3);
11.
if(a<=0.00001)
12.
return 0.0f;
13.
b=GetPointDistance(PA,P3);
14.
if(b<=0.00001)
15.
return 0.0f;
16.
c=GetPointDistance(PA,PB);
17.
if(c<=0.00001)
18.
return a;//如果PA和PB坐标相同,则退出函数,并返回距离
19.
//------------------------------
20.
21.
if(a*a>=b*b+c*c)//--------图3--------
22.
return b; //如果是钝角返回b
23.
if(b*b>=a*a+c*c)//--------图4-------
24.
return a; //如果是钝角返回a
25.
26.
//图1
27.
float l=(a+b+c)/2; //周长的一半
28.
float s=sqrt(l*(l-a)*(l-b)*(l-c)); //海伦公式求面积,也可以用矢量求
29.
return 2*s/c;
30.
}
下面的程序虽然没用上,还是用经纬度来判断偏移的,不过也贴上,怕以后用到哈。
根据经纬度坐标计算实际距离
double hypot(double x, double y) {
return sqrt(x * x + y * y);
}
double distance(double wd1, double jd1, double wd2, double jd2) {// 根据经纬度坐标计算实际距离
double x, y, out;
double PI = 3.1415926535898;
double R = 6.371229 * 1e6;
x = (jd2 - jd1) * PI * R * cos( ( (wd1 + wd2) / 2) * PI / 180) / 180;
y = (wd2 - wd1) * PI * R / 180;
out = hypot(x, y);
return out;
}
判断汽车轨迹是否偏离的算法其实不难,因为通过计算点到每个线段的距离,找出最小的距离,判断是否小于门限0.0001度(就是50米)就好了。然后返回一个0或者1。嘿嘿,简单吧。
举个例子,比如有8个点,必然有7个线段,依次计算7个线段的长度,然后计算点到7个线段的距离,找出最小的距离,再拿来和门限比较就OK了。
最近我程序构架思想大改,虽然是C语言,但是我引入C++的面向对象思想,运用封装和抽象的思想,大量使用指针和结构体。我用结构体封装了私有变量和函数,同时也提供公共变量和函数。我尽量给用户最简单的和最傻瓜的使用方法,也方便以后自己。
测试平台:Eclipse CDT
三个文件,.h .c
还有个test.c(主要用来演示)
下面是程序:
//Track_Detect.h
#ifndef TRACK_DETECT_H_
#define TRACK_DETECT_H_
#include
<stdio.h>
#include
<stdlib.h>
#include
<math.h>
#include
<stdint.h>
#define THRESHOLD_MILES 50
#define THRESHOLD_DEGREE 0.0001
struct Road_coordinate
{
double x;
double y;
};
struct GetNearestDistance_Private
{
double TempA,TempB,TempC;
double perimeter;
double area;
double (*GetPointDistance)(struct Road_coordinate p1, struct
Road_coordinate p2);
};
struct MinDistance_Of_Roads_Private
{
uint32_t Data_Size;
uint32_t Data_Resolution;
double *Temp_Data;
double minTemp;
};
struct GPS_Track_Detect_Private
{
//struct Road_coordinate *RXY;
double (*GetNearestDistance)(struct Road_coordinate PA, struct
Road_coordinate PB, struct Road_coordinate PC);
struct MinDistance_Of_Roads_Private
MinDistance_Of_Roads;
};
struct GPS_Track_Detect_Public
{
struct Road_coordinate *set_p;
uint32_t num;
struct Road_coordinate *move_p;
uint8_t MinNum;
double (*MinDistance_Of_Roads)(struct Road_coordinate *set_p,
uint32_t num, struct Road_coordinate *move_p, uint8_t
*MinNum);
};
//外部函数
extern double MinDistance_Of_Roads(struct
Road_coordinate *set_p, uint32_t num, struct Road_coordinate
*move_p, uint8_t *MinNum);
extern uint32_t GPS_Track_Detect(uint32_t
*deviate_flag, double *minValue, struct GPS_Track_Detect_Public
*p);
//注意set_p和move_p是指针
#define GPS_Track_Detect_MinDistance(set_p, num,
move_p, MinNum) MinDistance_Of_Roads(set_p, num, move_p,
MinNum)
#endif
//Track_Detect.c
//门限是0.0001度,就是50米
#include "Track_Detect.h"
//私有函数声明区
static double GetPointDistance(struct
Road_coordinate p1, struct Road_coordinate p2);
static double GetNearestDistance(struct
Road_coordinate PA, struct Road_coordinate PB, struct
Road_coordinate PC);
static double GetPointDistance(struct
Road_coordinate p1, struct Road_coordinate p2)
{
return
sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}
static double GetNearestDistance(struct
Road_coordinate PA, struct Road_coordinate PB, struct
Road_coordinate PC)
{
struct GetNearestDistance_Private *this = (struct
GetNearestDistance_Private *) malloc(sizeof(struct
GetNearestDistance_Private));
this->GetPointDistance =
GetPointDistance;
this->TempA =
this->GetPointDistance(PB,PC);
double return_value = 0.0;
if(this->TempA <= 0.00001)
{
free(this);
return 0.0f;
}
this->TempB =
this->GetPointDistance(PA,PC);
if(this->TempB <=0.00001 )
{
//return_value = this->TempB;
free(this);
return 0.0f;
}
this->TempC =
this->GetPointDistance(PA,PB);
if(this->TempC <= 0.00001)
{
return_value = this->TempA;
free(this);
return return_value;//如果PA和PB坐标相同,则退出函数,并返回距离
}
if(this->TempA * this->TempA
>= this->TempB *
this->TempB + this->TempC *
this->TempC)
{
return_value = this->TempB;
//如果是钝角返回TempB
free(this);
return return_value;
}
if(this->TempB * this->TempB
>= this->TempA *
this->TempA + this->TempC *
this->TempC)
{
return_value = this->TempA;
free(this);
return return_value;
//如果是钝角返回TempA
}
this->perimeter = (this->TempA +
this->TempB + this->TempC) /
2;
//周长的一半
this->area = sqrt(this->perimeter *
(this->perimeter - this->TempA) *
(this->perimeter - this->TempB) *
(this->perimeter -
this->TempC)); //海伦公式求面积,也可以用矢量求
return_value = 2 *
this->area / this->TempC;
free(this);
return return_value;
}
double MinDistance_Of_Roads(struct Road_coordinate
*set_p, uint32_t num, struct Road_coordinate *move_p, uint8_t
*MinNum)
{
uint32_t i = 0;
double return_value = 0.0;
struct GPS_Track_Detect_Private *this = (struct
GPS_Track_Detect_Private *) malloc(sizeof(struct
GPS_Track_Detect_Private));
this->GetNearestDistance =
GetNearestDistance;
this->MinDistance_Of_Roads.Data_Resolution =
sizeof(set_p[0]);
this->MinDistance_Of_Roads.Data_Size =
this->MinDistance_Of_Roads.Data_Resolution *
num;//动态分配数据空间
this->MinDistance_Of_Roads.Temp_Data = (double
*)malloc(this->MinDistance_Of_Roads.Data_Size);
//printf("%d\n",
this->MinDistance_Of_Roads.Data_Size);
//printf("%d\n",
this->MinDistance_Of_Roads.Data_Resolution);
for(i = 0; i <
(this->MinDistance_Of_Roads.Data_Size /
this->MinDistance_Of_Roads.Data_Resolution - 1 );
i++)
{
*(this->MinDistance_Of_Roads.Temp_Data + i) =
this->GetNearestDistance(set_p[i], set_p[i + 1],
*move_p);
//printf("%f\n",*(this->MinDistance_Of_Roads.Temp_Data
+ i));
}
this->MinDistance_Of_Roads.minTemp =
*(this->MinDistance_Of_Roads.Temp_Data +
0);
for(i = 1; i <
(this->MinDistance_Of_Roads.Data_Size /
this->MinDistance_Of_Roads.Data_Resolution - 1 );
i++)
{
if(*(this->MinDistance_Of_Roads.Temp_Data + i)
<
this->MinDistance_Of_Roads.minTemp)
{
this->MinDistance_Of_Roads.minTemp =
*(this->MinDistance_Of_Roads.Temp_Data +
i);
if(MinNum != NULL)
*MinNum = i;
}
}
free(this->MinDistance_Of_Roads.Temp_Data);
return_value =
this->MinDistance_Of_Roads.minTemp;
free(this);
//printf("\n\n\n");
return return_value;
}
//deviate_flag中
0
表示不偏移
1表示偏移
uint32_t GPS_Track_Detect(uint32_t *deviate_flag,
double *minValue, struct GPS_Track_Detect_Public *p)
{
p->MinDistance_Of_Roads =
MinDistance_Of_Roads;
*minValue =
p->MinDistance_Of_Roads(p->set_p,
p->num, p->move_p,
&p->MinNum);
*deviate_flag = THRESHOLD_DEGREE >= *minValue ? 0 :
1;
return 0;
}
//
测试文件,使用范例Track_Detect_test.c
#include "Track_Detect.h"
struct Road_coordinate RoadXY[] = {
{25.037936,98.431538},
{25.035104,98.429070},
{25.046580,98.411377},
{25.049696,98.409866},
{25.050273,98.407812},
{25.053200,98.406574},
{25.056470,98.406300},
{25.056452,98.404327}
};
int main(void) {
struct Road_coordinate test_dat = {.x = 25.050273, .y =
98.407712};
struct GPS_Track_Detect_Public GTDtest_dat;
GTDtest_dat.move_p = &test_dat;
GTDtest_dat.num = 8;
GTDtest_dat.set_p = RoadXY;
double minValue;
uint32_t deviate_flag;
GPS_Track_Detect(&deviate_flag,
&minValue,
>Dtest_dat);
printf("%d\n",GTDtest_dat.MinNum);
printf("\n\n");
printf("%f\n",minValue);
printf("%d\n",deviate_flag);
printf("\n\n");
uint8_t num;
printf("%f\n", GPS_Track_Detect_MinDistance(RoadXY, 8,
&test_dat, &num));
printf("%d\n",num);
return EXIT_SUCCESS;
}
相关文章推荐
- 行星运动轨迹的程序实现
- 行星运动轨迹的程序实现
- Android程序:简易浏览器的实现(WebView)
- OpenCV实现静止背景下运动目标的检测
- iOS程序自动检测更新的实现
- Python实现的检测web服务器健康状况的小程序
- 微信小程序 | 多个按钮或VIEW,点击改变状态 简易的实现方法
- VIBE运动目标检测算法实现
- c语言实现的简易窗口程序
- 基于Face++实现的人脸检测(年龄检测)Android程序
- 运动物体目标检测实现—基于OpenCV
- 智能车运动状态实时检测系统的设计及实现
- 使用多线程和Udp实现简易聊天程序
- 基于百度地图记录运动轨迹案例分析与实现
- 运动区域检测方法(一)——帧间差分法的简单实现
- 【opencv】基于opencv实现运动目标检测之帧差法
- 4000 python+opencv实现运动检测追踪拍照
- Android实现简易计步器功能,隔天步数清零,查看历史运动纪录
- socket实现简易聊天小程序