首先目标的坐标信息和track id是已知的。
基本原理:
记录目标上一次的坐标信息和当前的坐标信息,二者相连的线段如果与警戒线相交,那么则说明有越线的行为。因此问题就成了如何判断两条线段是否相交。
基础知识
平面向量
若已知点a(x1, y1),b(x2,y2),那么向量ab为(x2 - x1, y2 - y1)
向量积
如果向量a(x1, y1),向量b(x2, y2), 那么a * b = (x1*y2 - x2*y1)
若结果小于0,表示向量b在向量a的顺时针方向;若结果大于0,表示向量b在向量a的逆时针方向;若等于0,表示向量a与向量b平行
如图
向量AB(2,2),向量AC(3,0), AB*AC = (2*0 - 2*3) = -6
AB*AC < 0, 说明 AC在AB的顺时针方向
实现方案
判断点与线段的关系
如图
向量AB(1, 2),AC(1,0),AD(1,-2)
AB*AC = -2 、 AD*AC = 2、 AC*AD = -2
B、D分别在线段AC的两侧,向量AC在向量AB的顺时针方向,AB×AC < 0;向量AC在向量AD的逆时针方向,AD×AC > 0,两叉乘结果异号
所以如果向量积结果异号,表示B和D分别在直线AC的两边,若向量积结果同号则表示B、D两点都在AC的一边
判断线段是否相交
通过前面的铺垫我们就有了判断线段是否相交的方法
先判断C、D点在AB的两侧:AD*AB 与 AC*AB异号。
再判断A、B点在CD的两侧: CA*CD 与 CB*CD异号。
特殊情况的考虑
如果线段1的端点的最大横坐标 < 线段2的端点最小横坐标,或者 如果线段1的端点的最大纵坐标 < 线段2的端点最小纵坐标,那么一定是不会相交的。我们就可以事先排除,以降低计算量。
代码实现
基于以上原理实现一种越线检测算法
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HOST_ANALY_MAX_TRACK_NUM (128)
#define HOST_TRACK_NONE (-22)
#define HOST_MIN(m, n) (((m) > (n)) ? (n) : (m))
#define HOST_MAX(m, n) (((m) > (n)) ? (m) : (n))
typedef enum
{
HOST_OBJ_TYPE_UNKNOW = -1,
HOST_OBJ_TYPE_VEHICLE = 0, //车
HOST_OBJ_TYPE_PERSON = 1, //人
HOST_OBJ_TYPE_FACE = 2, //人脸
HOST_OBJ_TYPE_PLATE = 3, //车牌
HOST_OBJ_TYPE_BIKE = 4, //自行车
HOST_OBJ_TYPE_MOTOR = 5, //
HOST_OBJ_TYPE_BOAT = 6, //船
HOST_OBJ_TYPE_SMOKE = 7, //烟
HOST_OBJ_TYPE_FIRE = 8, //火
HOST_OBJ_TYPE_FACEMASK = 9, //口罩
HOST_OBJ_TYPE_MAX
}host_obj_type_e;
typedef struct _host_obj_t
{
int track_id; //追踪ID, 用来区分目标
host_obj_type_e cls;
int x;
int y;
int width;
int height;
}host_obj_t;
typedef struct _host_analy_point_t
{
int x;
int y;
}host_analy_point_t;
typedef struct _host_trip_wire_t
{
int direction;//方向
host_analy_point_t start;//起始点
host_analy_point_t end;//结束点
}host_trip_wire_t;
typedef struct _host_obj_coord_t
{
int track_id; //追踪ID, 用来区分目标
host_obj_type_e cls;
int sub;
host_analy_point_t coord1;
host_analy_point_t coord2;
}host_obj_coord_t;
typedef struct _obj_coore_info_t
{
unsigned int m_nIndex; //记录用到的下标
host_obj_coord_t obj_list[HOST_ANALY_MAX_TRACK_NUM];
}obj_coore_info_t;
typedef struct _obj_trip_wire_t
{
obj_coore_info_t item;
}obj_trip_wire_t;
typedef struct _host_analy_t
{
obj_trip_wire_t trip_wire;
}host_analy_t;
static host_analy_t *s_host_analy_proc = NULL;
int host_analy_init()
{
s_host_analy_proc = (host_analy_t *)malloc(sizeof(host_analy_t));
memset(s_host_analy_proc, 0, sizeof(host_analy_t));
for (int i = 0; i < HOST_ANALY_MAX_TRACK_NUM; ++i)
{
s_host_analy_proc->trip_wire.item.obj_list[i].track_id = HOST_TRACK_NONE;
}
return 0;
}
void host_analy_deinit()
{
if (s_host_analy_proc)
{
free(s_host_analy_proc);
s_host_analy_proc = NULL;
}
}
static int _host_find_pos(obj_coore_info_t *pParam, int track_id, host_obj_type_e cls)
{
int nIndex;
for (int i = 0; i < HOST_ANALY_MAX_TRACK_NUM; ++i)
{
if ((pParam->obj_list[i].track_id == track_id)
&& (pParam->obj_list[i].cls == cls)
&& (HOST_TRACK_NONE != pParam->obj_list[i].track_id))
return i;
}
if (pParam->m_nIndex >= HOST_ANALY_MAX_TRACK_NUM)
{
pParam->m_nIndex = 0;
nIndex = 0;
}
nIndex = pParam->m_nIndex % HOST_ANALY_MAX_TRACK_NUM;
pParam->m_nIndex++;
memset(&pParam->obj_list[nIndex], 0, sizeof(host_obj_coord_t));
pParam->obj_list[nIndex].track_id = HOST_TRACK_NONE;
return nIndex;
}
static int _host_obj_update(host_obj_t &obj, host_obj_coord_t &coord)
{
int centre_x = obj.width/2 + obj.x;
int centre_y = obj.height/2 + obj.y;
coord.cls = obj.cls;
coord.track_id = obj.track_id;
if (0 == coord.sub)
{
coord.coord1.x = centre_x;
coord.coord1.y = centre_y;
coord.sub = 1;
return -1;
}
else if (1 == coord.sub)
{
coord.coord2.x = centre_x;
coord.coord2.y = centre_y;
coord.sub = 2;
}
else
{
coord.coord1.x = coord.coord2.x;
coord.coord1.y = coord.coord2.y;
coord.coord2.x = centre_x;
coord.coord2.y = centre_y;
coord.sub = 2;
}
return 0;
}
int _host_compute(host_analy_point_t s, host_analy_point_t e) //计算叉乘的结果
{
int ret = 0;
ret = (s.x * e.y) - (s.y * e.x);
return ret;
}
int _host_cross_line(obj_coore_info_t *trip_wire, host_obj_t &obj, host_analy_point_t line_s, host_analy_point_t line_e)
{
int nRet = -1;
host_analy_point_t obj_s,obj_e;
int nIndex = _host_find_pos(trip_wire, obj.track_id, obj.cls);
nRet = _host_obj_update(obj, trip_wire->obj_list[nIndex]);
if (0 != nRet)
return nRet;
obj_s.x = trip_wire->obj_list[nIndex].coord1.x; obj_s.y = trip_wire->obj_list[nIndex].coord1.y;
obj_e.x = trip_wire->obj_list[nIndex].coord2.x; obj_e.y = trip_wire->obj_list[nIndex].coord2.y;
//
if ((HOST_MAX(obj_s.x, obj_e.x) <= HOST_MIN(line_s.x, line_e.x)) ||
(HOST_MAX(obj_s.y, obj_e.y) <= HOST_MIN(line_s.y, line_e.y)) ||
(HOST_MAX(line_s.x, line_e.x) <= HOST_MIN(obj_s.x, obj_e.x)) ||
(HOST_MAX(line_s.y, line_e.y) <= HOST_MIN(obj_s.y, obj_e.y)))
{
return -1;
}
//线段相交判断
host_analy_point_t AB,AC,AD;
host_analy_point_t CD,CA,CB;
AB.x = obj_e.x - obj_s.x; AB.y = obj_e.y - obj_s.y;
AC.x = line_s.x - obj_s.x; AC.y = line_s.y - obj_s.y;
AD.x = line_e.x - obj_s.x; AD.y = line_e.y - obj_s.y;
CD.x = line_e.x - line_s.x; CD.y = line_e.y - line_s.y;
CA.x = obj_s.x - line_s.x; CA.y = obj_s.y - line_s.y;
CB.x = obj_e.x - line_s.x; CB.y = obj_e.y - line_s.y;
int AB_AC = _host_compute(AB, AC);
int AB_AD = _host_compute(AB, AD);
int CD_CA = _host_compute(CD, CA);
int CD_CB = _host_compute(CD, CB);
printf("AB(%d, %d), AC(%d, %d), AB(%d, %d), AD(%d, %d), CD(%d, %d), CA(%d, %d), CD(%d, %d), CB(%d, %d)\n",\
AB.x, AB.y, AC.x, AC.y, AB.x, AB.y, AD.x, AD.y, CD.x, CD.y, CA.x, CA.y, CD.x, CD.y, CB.x, CB.y);
printf("AB_AC = %d, AB_AD = %d, CD_CA = %d, CD_CB = %d\n", AB_AC, AB_AD, CD_CA, CD_CB);
if((AB_AC > 0 && AB_AD > 0) || (AB_AC < 0 && AB_AD < 0) ||
(CD_CA > 0 && CD_CB > 0) || (CD_CA < 0 && CD_CB < 0))
{
return -1;
}
//方向判断
if (CD_CA > 0)//direction = 1
{
return 1;
}
else if (CD_CA < 0)//direction = 0
{
return 2;;
}
else
{
printf("%s, %d : AB(%d, %d), AC(%d, %d), AB(%d, %d), AD(%d, %d), CD(%d, %d), CA(%d, %d), CD(%d, %d), CB(%d, %d)\n", __FILE__, __LINE__,
AB.x, AB.y, AC.x, AC.y, AB.x, AB.y, AD.x, AD.y, CD.x, CD.y, CA.x, CA.y, CD.x, CD.y, CB.x, CB.y);
printf("AB_AC = %d, AB_AD = %d, CD_CA = %d, CD_CB = %d\n", AB_AC, AB_AD, CD_CA, CD_CB);
}
return 0;
}
int host_trip_wire_analysis(host_obj_t obj, host_trip_wire_t param)
{
if (obj.track_id < 0)
return -1;
int nRet = -1;
obj_coore_info_t *trip_wire = &s_host_analy_proc->trip_wire.item;
host_analy_point_t line_s,line_e;
line_s.x = param.start.x; line_s.y = param.start.y;
line_e.x = param.end.x; line_e.y = param.end.y;
nRet = _host_cross_line(trip_wire, obj, line_s, line_e);
if (nRet <= 0)
return -1;
if (((1 == nRet) && (1 == param.direction))
|| ((2 == nRet) && (0 == param.direction))
|| (2 == param.direction))
nRet = 0;
else
nRet = -1;
printf("trip_wire alarm, nRet = %d, direction = %d\n", nRet, param.direction);
return nRet;
}
int main()
{
host_analy_init();
host_trip_wire_t param;
param.direction = 6;
param.start.x = 6;
param.start.y = 6;
param.end.x = 6;
param.end.y = 0;
host_obj_t obj;
obj.track_id = 100;
obj.cls = HOST_OBJ_TYPE_VEHICLE;
obj.x = 1;
obj.y = 1;
obj.width = 1;
obj.height = 1;
host_trip_wire_analysis(obj, param);
obj.x = 3;
obj.y = 3;
obj.width = 1;
obj.height = 1;
host_trip_wire_analysis(obj, param);
obj.x = 4;
obj.y = 4;
obj.width = 1;
obj.height = 1;
host_trip_wire_analysis(obj, param);
obj.x = 8;
obj.y = 4;
obj.width = 1;
obj.height = 1;
host_trip_wire_analysis(obj, param);
host_analy_deinit();
return 0;
}