OpenCV温故而知新: 人跌倒侦测 4


应用场景

跌倒侦测主要应用于针对老人、小孩的住家看护之类的场景,如:家里的,或者养老院的老人。一旦出现跌倒,必须做到一定的反应。

工作原理

利用背景差检测画面的差异,并检测差异部分是否接近、类似人形。

补充说明

由于本算法对其应用场景有一定的特殊要求,若是放到不太合适的地方容易出现许多误报的状况。

以下是接口说明。

  1. 全域类别说明:

struct COEF_ELLIPSE{

//The parameters of the ellipse=========

int x ; //椭圆中心点x坐标

int y ; //椭圆中心点y坐标

int x_t_1 ;  //椭圆中心点上一时刻x坐标

int y_t_1 ;  //椭圆中心点上一时刻y坐标

int x_t_2 ;  //椭圆中心点前两时刻x坐标

int y_t_2 ;  //椭圆中心点前两时刻y坐标

double RegionSize;  //记录该前景区域的pixel数

double a ; //椭圆短轴长

double a_1;  //上一时刻椭圆短轴长

double b ; //椭圆长轴长

double b_1;  //上一时刻椭圆长轴长

double theta ; //椭圆与x轴方向的夹角

double theta_t_1 ;  //上一时刻的夹角

double theta_t_2 ;  //前2时刻的夹角

//======================================

//The foreground image and the motion history image=======

IplImage* Img_MHI ;   //Motion History Image

IplImage* Img_peoples ;  //The Foregrounde Image

IplImage* Img_peoples_t_1 ;  //The Foregrounde Image

//========================================================

//The conuter=====================================

double C_motion ;   //coefficient of motion

int Fall_cof_count ;  //累积符合条件的frame数

int Usual_cof_count ;   //累积正常情况的frame数

int cof_t_1 ;  //上一时刻的状态,1-unusual, -1-usual

long int fal_time ;  //跌倒后维持在地板上的时间,若超过此时间人未站起来即为跌倒事件

//================================================

//operators=======================================

bool check_updata ;  //判断这些参数是否有被更新过, false = 未更新过, true = 更新过

bool Fall_detected;  //若有跌倒事件发生为true

COEF_ELLIPSE* next_node;  //用于link list,连结下一个节点用

//================================================

};

class CFallDetect {

private:

struct COEF_ELLIPSE* DataObj ;  //人型对象的数据串结

int nWidth ;  //the size of the frame

int nHeight ;

double pi ;  //定义圆周率

int count ;  //计算现在的frame数,用于判断建立background的frame数

int UpdateCount ;  //updata background frequence

int people_area ;  //define the size of people region

int Fill_val ;  //The parameters of the function, cvFloodFill

CvPoint seed_point;  //They are used in the function, Find_object

CvScalar new_val ;  //填充前景时的新值,用于找寻前景位置

CvScalar lo_diff ;  //填充颜色所需要的参数

CvScalar up_diff ;  //填充颜色所需要的参数

CvConnectedComp comp;  //填充完前景后所记录的信息皆在此

int peoples_detect_last_time ;  //纪录上一时刻侦测到的人员数

int peoples_detect_this_time ;  //记录此时刻侦测到的人员数

int coef_peoples_detect ;  //记录前景detect的状态

double a ;  //椭圆的短轴长

double b ;  //椭圆的长轴长

double theta ;  //椭圆与水平方向的夹角

int C_motionthr ;  //动量的门坎值

double Ratiothr ;  //长轴短轴比的门坎值

double Thetathr ;  //椭圆与水平方向夹角的变化量门坎值

double Center_Positionthr ;  //中心点变化量门坎值

int After_Falltim ;  //跌到后维持低motion的时间长度门坎,用于判断跌倒事件的发生

int Fall_detect ;  //若有跌倒事件发生为 1

int Fall_num ;  //纪录跌倒的次数

public:

IplImage *Foreground ;  //前景影像

IplImage *Object ;  //找出的人的影像

IplImage *Background ;  //背景模型

IplImage *frame_copy ;  //待处理的影像

CFallDetect(int ,int ,int ,int ) ;   //参数化建构子

virtual ~CFallDetect() ;   //解构子

void DoDetect(bool, int, int, double);  //最上层的函式

void UpdateBackgroundImage(int, int, double) ;  // 建背景影像与更新

void GetForeground(char*, int ) ;  // 取得前景影像

void RGB_TO_YUV(unsigned char *,double*,double* ,double *) ; //转换至YUVspace

void Find_Object() ;  //侦测跌倒事件

void Ellipse_Parameter(IplImage*,int* ,int* ) ; //compute the parameters of the ellipse

void Set_Node(IplImage* ,int ,int ,double) ; //set new node

void Find_Match(struct COEF_ELLIPSE** ,int ,int ) ; //画面中有多人时,判断此时刻与上一

时刻match的资料

void Updata_Node(struct COEF_ELLIPSE** ,IplImage* ,int ,int ,double );  //更新节点数据

void Motion_History_Image(IplImage* ,IplImage*

,struct COEF_ELLIPSE* ) ;//compute the motion history image

int Fall_Detect(struct COEF_ELLIPSE *) ;  //Detect Falls

int Alarm();  //若有跌倒事件发出警讯

};

2.成员函式说明

CFallDetect::CFallDetect(int w,int h,int Fall_tim,int obj_area){

目的:Initial all variables we will use in the program

方法:建构子

参数:

Parameter

Type

Description

w

int

输入的画面的宽

h

int

输入的画面的高

Fall_tim

int

跌倒后躺在地下的时间,若超过此值即判定为跌倒

obj_area

int

设定是为人的前景区域大小的门坎值

}

CFallDetect::~CFallDetect(){

目的:释放内存

方法:解构子

}

int CFallDetect::Alarm(){

目的:发出alram讯号

方法:若全域参数Fall_detect为true时,回传1若否回传0

回传:

value

Type

Description

0

int

没有侦测到跌倒事件

1

int

有侦测到跌倒事件

}

void CFallDetect::DoDetect(bool bulidbackground,int Sub_Thr,int update_freq,double update_we){

目的:整个系统的最上层

方法:依照所设定的时间点,呼叫所需要的副函式

参数:

Parameter

Type

Description

bulidbackground

Bool

使否为建立背景模型的时间点

Sub_Thr

int

前景与背景分离出来所需相差的门坎值

update_freq

int

背景更新频率

update_we

Double

背景模型更新的权重

}

void CFallDetect::RGB_TO_YUV(unsigned char *DataSource,double* Y,double* U,double *V){

目的:转换RGB color domain到YUV color domain

方法:利用函式中的数学运算

参数:

Parameter

Type

Description

DataSource

unsigned char*

指向IplImage影像data指针

Y

double

Y channel的值

U

double

U channel的值

V

double

V channel的值

}

void CFallDetect::UpdateBackgroundImage(int IntervalFrame, int select, double alpha){

目的:更新背景模型

方法:利用alpha权重,加权此时刻的输入影像与上一时刻的背景模型,运算后更新之。主要更新的区域为非前景的对应区域中,但每隔1000张画面针对整张画面做更新。

参数:

Parameter

Type

Description

IntervalFrame

int

背景模型更新的频率

select

int

为0则做初始建立背景模型的运算,为1做更新背景模型的运算

alpha

double

更新背景模型的权重参数

}

void CFallDetect::GetForeground(char* COLOR_SPACE_TYPE, int background_thresh){

目的:取得前景影像

方法:直接将输入的影像对背景模型转到相同的color space下做相减,若pixel差值大于门坎值则判定为前景,此为需要经过膨胀与侵蚀的型态处理运算

参数:

Parameter

Type

Description

COLOR_SPACE_TYPE

char*

欲处理运算的color space,提供 USE_HSV 、USE_YUV 与 USE_RGB可以使用。

background_thresh

int

前景与背景的差异门坎值

}

void CFallDetect::Find_Object(){

目的:判断跌倒事件,包含建立人型对象串结结构、更新人型对象节点、计算人型前景椭圆参数、判断跌倒

方法:呼叫对应的副函式,详细内容请看各个有使用到的副函式的说明

}

void CFallDetect::Find_Match(struct COEF_ELLIPSE** update_ptr,int object_x,int object_y){

目的:比对目前的资料是要更新到link list串结中那个节点

方法:已知目前中心点,去比对目前link list中所有的中心点看哪比距离最近,此节点即为我们欲更新的节点

参数:

Parameter

Type

Description

update_ptr

struct COEF_ELLIPSE**

计算完成后即为欲更新的那个节点的内存位置。

object_xh

int

计算出来的前景中心点x坐标

object_y

int

计算出来的前景中心点y坐标

}

void CFallDetect::Updata_Node(struct COEF_ELLIPSE** update_ptr,IplImage* Img_Object,int

object_x,int object_y,double obj_size){

目的:比对出欲更新的节点后,利用此函式更新节点的信息

方法:将目前数值更新到目标节点中

参数:

Parameter

Type

Description

update_ptr

struct COEF_ELLIPSE**

欲更新的那个节点的内存位置。

Img_Object

IplImage*

欲记录下来的此时侦测到的前景影像

object_x

int

计算出来的前景中心点x坐标

object_y

Int

计算出来的前景中心点y坐标

obj_size

double

该前景区域的pixel数

}

void CFallDetect::Ellipse_Parameter(IplImage* PeopleImg,int* x,int* y){

目的:计算fit 前景的椭圆的参数

方法:利用型态分析做处理

参数:

Parameter

Type

Description

PeopleImg

IplImage*

侦测出来的单人前景影像

x

int*

计算出来后即为的前景中心点x坐标

y

int*

计算出来后即为的前景中心点y坐标

}

void CFallDetect::Set_Node(IplImage* Img_Temp_people,int object_x,int object_y,double region_size){

目的:当画面中有多个人员时,需要新增一个人员对象节点,以link list串结在一起

方法:初始化节点,并寻找现有的串结数据的最后一笔数据,并连结上去

参数:

Parameter

Type

Description

Img_Temp_people

IplImage*

找到的新前景影像。

object_x

int

计算出来的前景中心点x坐标

object_y

int

计算出来的前景中心点y坐标

region_size

double

该前景区域的总共pixel数

}

void CFallDetect::Motion_History_Image(IplImage* people_copy,IplImage* Img_peoples

,struct COEF_ELLIPSE* Coef_peoples){

目的:计算动量参数

方法:利用Motion History Image(MHI)去计算动量的参数,MHI主要记录了现在与过去的动量。

参数:

Parameter

Type

Description

people_copy

IplImage*

上一时刻的前景。

Img_peoples

int

此时刻的前景

Coef_peoples

int

人型对象串结欲更新节点的内存位置

}

int CFallDetect::Fall_Detect(struct COEF_ELLIPSE *People){

目的:判断跌倒

方法:先利用4个参数:动量大小、长轴短轴比的变化量、长轴与水平方向夹角的变化量、中心点位移的变化量,定义出有可能跌倒的时间点,在有可能跌倒的时间点后,于我们设定的时间内若不在有大动量产生,此时即确定侦测出一个跌倒事件。

参数:

Parameter

Type

Description

People

struct COEF_ELLIPSE *

人型对象的数据串结。

回传:

Value

Type

Description

-1

int

没有跌倒事件

2

int

侦测到跌倒事件

}

测试程序及序列

测试程序说明:

  • 指定测试视频:libxxxdetect_test.exe 111.avi,这个111.avi是你输入的视频文件。若不指定则默认打开当前目录下的libxxxdetect_sample.avi文件,若这个文件不存在则打开电脑上的摄像头。
  • 开始后请先通过鼠标拖拉点选设置检测区域。
  • 附带文件:无。
  • 测试程序快捷键:按r重新设定ROI检测区域,按p暂停处理,按t or ESC键中止。

Leave a Reply to Jacky Wei Cancel reply

Your email address will not be published. Required fields are marked *

4 thoughts on “OpenCV温故而知新: 人跌倒侦测

  • lori

    您好,偶然看到個溫故知新的偵測人跌倒的部分,感到非常的欣喜,

    不過學生有些疑慮,多人偵測部分,說明是有新的人進來就新增加連結,可是人在影像中一直在移動,請問是怎麼確認新加進的資料確實是新進入的物體?

    同理中….也不懂怎麼在多人當中.判斷到有人跌倒….

    • Jacky Wei Post author

      Dear Lori,
      我这边这个算法实现的还是非常单纯(如果要说的好听点的话)的。其只是判断有没有新的人横向的类似人体的差异图(取灰度图与背景图比较)出现,并持续一段时间(可设定参数)。若是则认为有人物跌倒,反之认为正常。
      移动的人不会被误判为跌倒。但若是画面中有多人,并且多人围观一个跌倒的人的话,再并且多人中有人与跌倒的人重合,则容易被忽略。

      • lori

        非常感謝您的回應!
        確實在重和人體過多的時候,取得的前景會是橫向的.
        感覺您的演算法適用在距離較遠,人與人較為分散的廣場上.
        若是室內影像太近,可能就會誤判了.(希望沒有理解錯誤.)
        有種豁然開朗的感覺.
        謝謝您的說明!

        • Jacky Wei Post author

          感覺您的演算法適用在距離較遠,人與人較為分散的廣場上.

          是的.

          不仅如此,其实绝大多数的这种intellegent算法都会有类似的局限性,就是需要在一种特定的场景里才能正确的、准确的工作。

          不然,就得先从机器视觉开始做起,先做测距、做标定,然后再来分析识别具体场景及物体。。。。

          但这对一般程序员来说都很难