后面加了斜杠部分和两段斜杠中间的部分是添加的代码,摄像头原始yuv数据在pcontext->videoIn->framebuffer缓冲区内。一颗像素的yuv数据由四个字节组成,而不是两个字节,关于yuv和rgb的区别可以从百度学习。本代码将摄像头采集的1280*720图像转换为了320*180的图像,只需要每隔四列删掉三列,每隔四行删掉三行即可。然后通过compress_yuv_to_jpeg函数,将yuv图像转换为jpeg图像,通过以太网发送数据包进行显示。
#define WID 320///
#define HEI 180///
#define N1 4////
#define N2 16////
void*cam_thread(void *arg)
{
unsigned int i=0,j=0;///////////
unsigned char*yuv,*low_yuv,*my_buf;//////////////
context*pcontext = arg;
pglobal =pcontext->pglobal;
pthread_cleanup_push(cam_cleanup, pcontext);
while(!pglobal->stop) {
while(pcontext->videoIn->streamingState ==STREAMING_PAUSED) {
usleep(1);
}
if(uvcGrab(pcontext->videoIn) < 0) {
IPRINT("Error grabbing framesn");
exit(EXIT_FAILURE);
}
DBG("received frame of size: %d from plugin: %dn",pcontext->videoIn->buf.bytesused, pcontext->id);
if(pcontext->videoIn->buf.bytesused
DBG("dropping too small frame, assuming it a***rokenn");
}
pthread_mutex_lock(&pglobal->in[pcontext->id].db);
/////////////////////////////////////////////////////////////////////////////////////////////
yuv=pcontext->videoIn->framebuffer;
my_buf=calloc(WID*2*HEI, 1);
low_yuv=my_buf;
for(j=0;j<720;j++)
{
for(i=0;i<1280*2;i++)
{
if((i%N2==0 || i%N2==1 || i%N2==2 || i%N2==3)&& j%N1==0) {*low_yuv=*yuv;low_yuv++;}
*yuv=0;
yuv++;
}
}
low_yuv=my_buf;
yuv=pcontext->videoIn->framebuffer;
my_buf=calloc(WID*2*HEI, 1);
low_yuv=my_buf;
for(j=0;j<720;j++)
{
for(i=0;i<1280*2;i++)
{
if((i%N2==0 || i%N2==1 || i%N2==2 || i%N2==3)&& j%N1==0) {*low_yuv=*yuv;low_yuv++;}
*yuv=0;
yuv++;
}
}
low_yuv=my_buf;
yuv=pcontext->videoIn->framebuffer;
for(j=0;j
{
for(i=0;i
{
*yuv=*low_yuv;
yuv++;
low_yuv++;
}
}
pcontext->videoIn->width=WID;
pcontext->videoIn->height=HEI;
/////////////////////////////////////////////////////////////////////////////////////////////
if(pcontext->videoIn->formatIn !=V4L2_PIX_FMT_MJPEG) {
DBG("compressing frame from input: %dn", (int)pcontext->id);
pglobal->in[pcontext->id].size =compress_yuv_to_jpeg(pcontext->videoIn,pglobal->in[pcontext->id].buf,WID*2*HEI/*pcontext->videoIn->framesizeIn*/,gquality, pcontext->videoIn->formatIn);
} else {
DBG("copying frame from input: %dn", (int)pcontext->id);
pglobal->in[pcontext->id].size =memcpy_picture(pglobal->in[pcontext->id].buf,pcontext->videoIn->tmpbuffer, pcontext->videoIn->buf.bytesused);
}
free(my_buf);///////
...
}
最后在mjpg_streamer目录下,vim start.sh,将分辨率改小成320x180,帧率和图像质量可以看情况更改:
因为此处的分辨率改小了,但是实际上摄像头发出的数据还是1280*720的,因此在input_uvc.c的input_init函数中,将参数需要改为原始分辨率的大小,否则摄像头数据的采集可能会出错。
if(init_videoIn(cams[id].videoIn, dev,1280,720,/*width, height,*/ fps, format, 1, cams[id].pglobal, id) < 0) { IPRINT("init_VideoIn failedn"); closelog(); exit(EXIT_FAILURE);}
这是最终的实验效果,此界面的图像预览显示尺寸可以通过修改www目录下的stram_simple.html和style.css进行修改。可以观察到虽然画面变模糊了,但是流畅度有了大大提高。
最后,展示炫酷无敌的实物图,想不到nanopi简直是个无线图传利器呢。既然都知道图像数据保存的位置了,那么图像算法还会远吗?