基于c/c++的一种越线检测算法

首先目标的坐标信息和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;
}

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值