明天又要去面试了,趁次机会也将以前做的东西总结一下,为以后理解提供方便,也再加深下印象。
网络视频监控与人脸识别主要由三个程序组成:1、视频采集与传输程序;2、接受与显示程序;3、人脸识别程序。下面就分别来分析一下这三个程序。
一、视频采集与传输程序(Servfox)
关键部分解析:
1、视频数据采集(可采用共享内存方式和读方式)
int v4lGrab (struct vdIn *vd )
{
static int frame = 0;
int len;
int size;
int erreur = 0;
int jpegsize = 0;
struct frame_t *headerframe;
double timecourant =0;
double temps = 0;
timecourant = ms_time();
if (vd->grabMethod) /*共享内存方式*/
{
vd->vmmap.height = vd->hdrheight;
vd->vmmap.width = vd->hdrwidth;
vd->vmmap.format = vd->formatIn;
/*该函数成功返回则表示一帧采集已完成,采集到的图像数据放到
起始地址为 vd->map+vd->mbuf.offsets[vd->frame]
的内存区中,读取该内存区中的数据便可得到图像数据。
接着可以做下一次的 VIDIOCMCAPTURE。*/
if (ioctl (vd->fd, VIDIOCSYNC, &vd->vmmap.frame) < 0)
{
perror ("cvsync err\n");
erreur = -1;
}
/* Is there someone using the frame */
while((vd->framelock[vd->frame_cour] != 0) && vd->signalquit)
usleep(1000);
pthread_mutex_lock (&vd->grabmutex);
temps = ms_time();
/*采集完成,进行jpeg压缩处理,里面大有文章*/
jpegsize= convertframe(vd->ptframe[vd->frame_cour]+ sizeof(struct frame_t),
vd->pFramebuffer + vd->videombuf.offsets[vd->vmmap.frame],
vd->hdrwidth,vd->hdrheight,vd->formatIn,vd->framesizeIn);
/*填充数据帧信息头*/
headerframe=(struct frame_t*)vd->ptframe[vd->frame_cour];
snprintf(headerframe->header,5,"%s","SPCA");
headerframe->seqtimes = ms_time();
headerframe->deltatimes=(int)(headerframe->seqtimes-timecourant);
headerframe->w = vd->hdrwidth;
headerframe->h = vd->hdrheight;
headerframe->size = (( jpegsize < 0)?0:jpegsize);
headerframe->format = vd->formatIn;
headerframe->nbframe = frame++;
// printf("compress frame %d times %f\n",frame, headerframe->seqtimes-temps);
pthread_mutex_unlock (&vd->grabmutex);
/************************************/
if ((ioctl (vd->fd, VIDIOCMCAPTURE, &(vd->vmmap))) < 0)
{
perror ("cmcapture");
if(debug) printf (">>cmcapture err \n");
erreur = -1;
}
vd->vmmap.frame = (vd->vmmap.frame + 1) % vd->videombuf.frames;
vd->frame_cour = (vd->frame_cour +1) % OUTFRMNUMB;
//if(debug) printf("frame nb %d\n",vd->vmmap.frame);
}
else /* 读方式*/
{
size = vd->framesizeIn;
len = read (vd->fd, vd->pFramebuffer, size);
if (len < 0 )
{
if(debug) printf ("v4l read error\n");
if(debug) printf ("len %d asked %d \n", len, size);
return 0;
}
/* Is there someone using the frame */
while((vd->framelock[vd->frame_cour] != 0)&& vd->signalquit)
usleep(1000);
pthread_mutex_lock (&vd->grabmutex);
temps = ms_time();
jpegsize= convertframe(vd->ptframe[vd->frame_cour]+ sizeof(struct frame_t),
vd->pFramebuffer ,
vd->hdrwidth,vd->hdrheight,vd->formatIn,vd->framesizeIn);
headerframe=(struct frame_t*)vd->ptframe[vd->frame_cour];
snprintf(headerframe->header,5,"%s","SPCA");
headerframe->seqtimes = ms_time();
headerframe->deltatimes=(int)(headerframe->seqtimes-timecourant);
headerframe->w = vd->hdrwidth;
headerframe->h = vd->hdrheight;
headerframe->size = (( jpegsize < 0)?0:jpegsize);
headerframe->format = vd->formatIn;
headerframe->nbframe = frame++;
// if(debug) printf("compress frame %d times %f\n",frame, headerframe->seqtimes-temps);
vd->frame_cour = (vd->frame_cour +1) % OUTFRMNUMB;
pthread_mutex_unlock (&vd->grabmutex);
/************************************/
}
return erreur;
}
2、数据通过socket通信方式发送
for (;;)
{
memset(&message,0,sizeof(struct client_t));
/*接受网络数据,保存在message 结构体中*/
ret = read(sock,(unsigned char*)&message,sizeof(struct client_t));
/*根据接受到的控制信息进行控制*/
/*大小调节*/
else if (message.updosize){ //compatibility FIX chg quality factor ATM
switch (message.updosize){
case 1: qualityUp(&videoIn);
break;
case 2: qualityDown(&videoIn);
break;
}
ack = 1;
}
/*帧数调节*/
else if (message.fps){
switch (message.fps){
case 1: timeDown(&videoIn);
break;
case 2: timeUp(&videoIn);
break;
}
ack = 1;
}
/*睡眠控制*/
else if (message.sleepon){
ack = 1;
}
else ack =0;
while ((frameout == videoIn.frame_cour) && videoIn.signalquit) usleep(1000);
if (videoIn.signalquit){
videoIn.framelock[frameout]++;
headerframe = (struct frame_t *) videoIn.ptframe[frameout];
headerframe->acknowledge = ack;
headerframe->bright = bright;
headerframe->contrast = contrast;
headerframe->wakeup = wakeup;
/*发送数据帧头信息*/
ret = write_sock(sock, (unsigned char *)headerframe, sizeof(struct frame_t)) ;
if(!wakeup)
/*发送数据帧信息*/
ret = write_sock(sock,(unsigned char*)(videoIn.ptframe[frameout]+sizeof(struct frame_t)),headerframe->size);
videoIn.framelock[frameout]--;
frameout = (frameout+1)%4;
} else {
if(debug) printf("reader %d going out \n",*id);
break;
}
}
close_sock(sock);
pthread_exit(NULL);
}
二、接受与显示程序
1、JPEG图片压缩原理
实际上,一个平面的图像,可以理解为除了水平 X 和垂直 Y 以外,还有一个色彩值的 Z 的三维的系统。Z 代表了三元色中各个分支 R/G/B 的混合时所占的具体数值大小,每个像素的 RGB 的混合值可能都有所不同,各个值有大有小,但临近的两个点的 R/G/B 三个值会比较接近。两个相邻的点,会有很多的色彩是很接近的,那么如何能在最后得到的图片中,尽量少得记录这些不需要的数据, 也即达到了压缩的效果。