当前位置:首页 > 消费电子 > 消费电子
[导读]摄像头“移动侦测”最怕两件事:像素一变就报,手机被树叶晃到轰炸;算法和上传耦合,网络一抖事件丢了。嵌入式端正确做法是采集线程出帧→算法线程抽帧做帧差→事件队列去抖→上报线程发MQTT,本地先判定,网络上只传“事件”,不传视频流。


摄像头“移动侦测”最怕两件事:像素一变就报,手机被树叶晃到轰炸;算法和上传耦合,网络一抖事件丢了。嵌入式端正确做法是采集线程出帧→算法线程抽帧做帧差→事件队列去抖→上报线程发MQTT,本地先判定,网络上只传“事件”,不传视频流。

一、别全分辨率跑算法

1080p逐帧算帧差,MIPS直接爆。工程上抽帧+缩放:

采集走V4L2/MIPICSI,取YUV或MJPEG解码出Y通道

缩到320×240或160×120足够

5~10fps抽帧即可,家门口场景不需要30fps

只处理ROI区域,草坪/树冠直接屏蔽

#define MW 320

#define MH 240

static uint8_t prev[MW*MH];

static uint8_t bg[MW*MH];


int motion_blocks(uint8_t*cur, uint8_t*roi_mask,

                 int th, int min_area){

   int hit=0, pix=0;

   for(int y=0;y<MH;y++){

       for(int x=0;x<MW;x++){

           int i=y*MW+x;

           if(roi_mask && !roi_mask[i]) continue;

           int d = abs(cur[i]-bg[i]);

           if(d>th){

               pix++;

               int bx=x/16, by=y/16;

               hit |= (1<<(by*20+bx)%32);   // 粗略块标记

           }

       }

   }

   return pix>=min_area ? pix : 0;

}

帧差阈值一般15~30,最小面积按场景标,门口人体几百像素起步。

二、背景建模别用“首帧定死”

纯帧差遇光照渐变会漏。嵌入式够用的是Surendra式更新:运动区保留旧背景,静止区慢追当前帧。

void bg_update(uint8_t*cur, uint8_t*mask, int alpha){

   for(int i=0;i<MW*MH;i++){

       if(mask[i]) continue;          // 运动像素不更新

       bg[i] = (bg[i]*(256-alpha) + cur[i]*alpha)>>8;

   }

}

alpha取8~16,背景几秒跟一次,既能抗光漂移,又不会把慢速移动目标融进背景。

三、去抖:连续帧+冷却时间

单帧像素变化=飞虫、红外亮点、窗帘晃。 必须做两层过滤:

typedef struct {

   int   confirm_cnt;

   uint32_t last_alarm_ms;

} motion_fsm_t;


int motion_decide(motion_fsm_t*m, int pix,

                 uint32_t now, int need_frames){

   if(pix>0){

       m->confirm_cnt++;

   }else{

       m->confirm_cnt=0;

   }

   if(m->confirm_cnt>=need_frames){          // 连续3帧

       if(now-m->last_alarm_ms > COOLDOWN_MS){ // 冷却10s

           m->last_alarm_ms = now;

           m->confirm_cnt=0;

           return 1;

       }

   }

   return 0;

}

规则:

连续2~3帧确认,过滤瞬时干扰

同场景冷却10~30s,避免一个人走过去报5条

ROI分区独立计数,院子里树动不影响门口报警

高配才上人形分类;基础IPC用ROI+面积+连续帧,误报能压掉大半。

四、事件队列解耦算法与上传

算法线程别直接调mqtt_publish,网络阻塞会拖慢侦测。统一发事件:

typedef struct {

   uint32_t seq;

   uint32_t ts;

   int      pix;

   uint8_t  zone;

   uint8_t  snap;     // 是否带抓拍

} alarm_evt_t;


QueueHandle_t evt_q;


void algo_task(void*p){

   for(;;){

       uint8_t*frame = get_small_y();

       int pix = motion_blocks(frame, roi, TH, MIN_AREA);

       if(motion_decide(&fsm, pix, now(), 3)){

           alarm_evt_t e = {

               .seq = ++g_seq,

               .ts  = rtc_sec(),

               .pix = pix,

               .zone= 0

           };

           xQueueSend(evt_q, &e, 0);

           snap_request();      // 异步抓一帧JPEG

       }

       bg_update(frame, cur_mask, 12);

       vTaskDelay(pdMS_TO_TICKS(100)); // 10fps

   }

}

五、上报线程:QoS1+断网补传

报警事件不能丢,用MQTT QoS1;网络断了进本地环形缓冲,恢复后按seq补。

#define EVT_SLOTS 32

static alarm_evt_t ring[EVT_SLOTS];


void report_task(void*p){

   alarm_evt_t e;

   for(;;){

       xQueueReceive(evt_q,&e,portMAX_DELAY);

       char buf[96];

       snprintf(buf,sizeof(buf),

           "{\"seq\":%u,\"zone\":%d,\"pix\":%d,\"ts\":%u}",

           e.seq,e.zone,e.pix,e.ts);

       if(mqtt_connected()){

           mqtt_publish_qos1("cam/01/motion", buf);

           flush_ring();           // 补发断网期事件

       }else{

           ring[e.seq%EVT_SLOTS]=e; // 先缓存

       }

   }

}

重连别死循环秒重连,指数退避1/2/4/8…最大60s:

int backoff = 1000;

void on_disconnect(){

   vTaskDelay(backoff);

   mqtt_reconnect();

   backoff = backoff*2>60000?60000:backoff*2;

}

补传限速,别一次性灌几十条把新事件堵住;报警类优先,状态类可丢。

六、快速上传的几个细节

抓拍异步:算法只发事件,JPEG抓拍由单独DMA/编码任务出,不占侦测周期

本地先响:蜂鸣器/GPIO联动在事件入队瞬间做,不等云端回执

LWT配置:设备掉线Broker发遗嘱,平台知道离线

KeepAlive适配:弱网RTT大时心跳别30s硬卡,否则误断连

时间戳对齐:RTC或NTP对时,补传事件别用到达时间

区域独立ROI掩码:门口/围墙开侦测,草坪/天空关掉

七、落坑清单

全分辨率30fps跑帧差→CPU满载掉帧

单帧变化直接报警→飞虫树叶狂推

算法线程里阻塞发MQTT→侦测卡死

断网事件不缓存→丢报警

重连固定1s→基站弱信号雪崩

没冷却时间→一人走过报5条

背景首帧写死→白天黄昏全误报

ROI不屏蔽绿植→户外必炸

只发像素变化不上区域→分不清人和猫

八、落地顺序

摄像头出Y帧,缩到320×240

ROI掩码配置(门口/围墙)

帧差+背景慢更新

运动像素统计+最小面积

连续帧确认+冷却时间

事件结构体入队列

上报线程MQTT QoS1

断网环形缓冲+退避重连+补传

抓拍异步+本地GPIO联动

本地移动侦测的本质不是“检测得有多聪明”,是先别被像素噪声骗;快速上传的本质不是“每次都立马发”,是事件进队列、网络层异步兜底。嵌入式摄像头稳不稳,就看算法任务和上报任务有没有切开——耦合在一起的项目,网络一抖要么丢报警要么卡侦测。基础帧差+ROI+连续帧确认,再加事件队列解耦,家用/商铺IPC够用;要再降误报才上人形分类,别一上来就怼模型。



本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭