Linux开发_摄像头编程(实现拍照功能)

这篇文章主要介绍linux下uvc免驱摄像头操作流程,介绍v4l2框架、完成摄像头拍照保存为bmp图像到本地,最后贴出了利用cjson库解析天气预报、北京时间接口返回的数据例子代码(上篇文章的案例补充)。
任务1:摄像头操作方式 (1)摄像头框架介绍 linux、windows这些系统下很多摄像头都是免驱(uvc)。
v4l2 :免驱摄像头框架----一堆结构体。
linux下开发摄像头的不同角度问题:(嵌入式开发)
【1】上层软件系统开发(系统编程),控制驱动提供的接口使用摄像头。
【2】底层硬件系统开发(驱动编程),直接控制摄像头采集数据。
摄像头功能:将采集到的图像数据转为二进制数据返回。
驱动的代码集成在操作系统里。
在操作系统里使用摄像头步骤:学习接口函数的调用。
fread(); read();
linux下是一切设备皆文件: 摄像头、网卡、声卡、鼠标、键盘………………….
linux下设备文件存放的位置: /dev目录下。
在虚拟机跑linux,使用外设设备都需要单独挂载才可以使用。
挂载摄像头:
查看摄像头的设备节点:
[root@wbyq /]# ls /dev/video*
/dev/video0 /dev/video1
(2)运行网页监控项目代码 远程网页视频监控示例
 第一步:编译libjpeg-turbo ​ 1. 解压:libjpeg-turbo-1.2.1.tar.gz ​ 2. 生成makefile(如果报错,就安装报错提示安装包):./configure ​ 3. 编译安装:make && make install ​ 4. 将生成lib和include目录下的文件拷贝到/usr目录下的对应文件夹 ​ 第二步:编译mjpg-streamer-r63 ​ 1.直接make进行编译 ​ 2.运行程序:./mjpg_streamer -i /work/mjpeg/mjpg-streamer-r63/input_uvc.so -f 10 -r 800*480 -y -o /work/mjpeg/mjpg-streamer-r63/output_http.so -w www ​ 注意: 可以使用电脑自带的摄像头。在虚拟机的右下角进行将windows系统的摄像头挂载到linux系统 ​ 3. 在浏览器里输入地址进行查看摄像头: ​ 例如:192.168.11.123:8080复制代码 将远程摄像头监控的代码编译运行实现效果。
(1) 修改端口号,8080不能作为公网的端口访问。
(2) 修改线程数量。
(3) 分析下线程的函数实现原理。
(4) 使用花生壳软件实现公网监控。
花生壳: 将本地ip地址映射为一个域名。
外网想要访问本地电脑ip就直接访问域名。
(3)摄像头编程,实现拍照功能 学习摄像头的使用
(1)摄像头实现拍照源程序流程:(50%程序学过的)
(2)打开摄像头的设备文件 open(“/dev/xxx”);
(3)获取摄像头参数。判断摄像头是否支持一些特有的操作。read
(4)配置摄像头的参数。(1) 输出的源数据格式rgb888 (2) 输出的图像尺寸
rgb888:数字数据格式
其他格式: yuv 模拟数据格式
(5)判断摄像头的参数是否设置成功。
(6)读取摄像头的数据。 队列的形式。
(7)将读取的yuv格式数据转为rgb格式
(8)将rgb格式数据编码为bmp格式的图片存放到电脑上
安装rpm软件包:rpm -ivh xxxxx.rpm
linux下安装软件有两种方式:
【1】rpm软件安装包(已经编译好的二进制文件的集合),使用rpm -ivh xxx.rpm
【2】直接下载源码包自己编译安装。libjpeg-turbo-1.2.1.tar.gz
(1) 没有makefile文件,就有: configure文件,用来生成makefile文件
示例: ./configure
(2) make 编译源码
(3) make install 安装源码。(会将编译好的文件拷贝到指定的目录下)
 void *memset(void *s, int c, size_t count) //给指定地址的空间填入指定大小的数据 参数: *s :起始地址 c :填入的数据 count :填入的数量 rgb888 : 000 fff复制代码 摄像头拍照示例代码:
 #include camera_bmp.h ​ t_pixeldatas pixedata; //存放实际的图像数据 ​ /*  usb摄像头相关参数定义 */ struct v4l2_buffer tv4l2buf; int ifd; int listnum; unsigned char* pucvidebuf[4];  // 视频buff空间地址 ​ int main(int argc ,char *argv[]) {  if(argc!=2)  {   printf(./app /dev/videox\n);   return -1;  }    camera_init(argv[1]);  //摄像头设备初始化 ​  //开始采集摄像头数据,并编码保存为bmp图片  camera_pthread();  return 0; } ​ ​ //yuv转rgb实现 unsigned int pyuv422torgb32(unsigned char * ptr,unsigned int width, unsigned int height) {  unsigned int i, size;  unsigned char y, y1, u, v;  unsigned char *buff = ptr;         //源数据  unsigned char *output_pt=pixedata.videobuf; //存放转换之后的数据  unsigned char r, g, b;  size = width * height /2;  for (i = size; i > 0; i--)   {  y = buff[0];  u = buff[1];  y1= buff[2];  v = buff[3];  buff += 4;  r = r_fromyv(y,v);  g = g_fromyuv(y,u,v); //b  b = b_fromyu(y,u); //v  *output_pt++ = b;  *output_pt++ = g;  *output_pt++ = r;  r = r_fromyv(y1,v);  g = g_fromyuv(y1,u,v); //b  b = b_fromyu(y1,u); //v  *output_pt++ = b;  *output_pt++ = g;  *output_pt++ = r;  }  return 0; }  ​ //摄像头设备的初始化 int camera_init(char *video) {  int i=0;  int cnt=0;  //定义摄像头驱动的buf的功能捕获视频  int itype = v4l2_buf_type_video_capture;    /* 1、打开视频设备 */  ifd = open(video,o_rdwr);  if(ifd < 0)  {  printf(摄像头设备打开失败!\n);  return 0;  }    struct v4l2_format  tv4l2fmt;    /* 2、 vidioc_s_fmt 设置摄像头使用哪种格式 */  memset(&tv4l2fmt, 0, sizeof(struct v4l2_format));  tv4l2fmt.type = v4l2_buf_type_video_capture; //视频捕获 ​  //设置摄像头输出的图像格式     tv4l2fmt.fmt.pix.pixelformat=v4l2_pix_fmt_yuyv; ​  /*设置输出的尺寸*/  tv4l2fmt.fmt.pix.width       = 640;  tv4l2fmt.fmt.pix.height      = 480;  tv4l2fmt.fmt.pix.field       = v4l2_field_any;       //vidioc_s_fmt 设置摄像头的输出参数     ioctl(ifd, vidioc_s_fmt, &tv4l2fmt);  ​  //打印摄像头实际的输出参数  printf(support format:%d\n,tv4l2fmt.fmt.pix.pixelformat);  printf(support width:%d\n,tv4l2fmt.fmt.pix.width);  printf(support height:%d\n,tv4l2fmt.fmt.pix.height); ​  /* 初始化pixedata结构体,为转化做准备 */  pixedata.ibpp =24;   //高度 和宽度的赋值  pixedata.iheight = tv4l2fmt.fmt.pix.height;  pixedata.iwidth = tv4l2fmt.fmt.pix.width; ​  //一行所需要的字节数  pixedata.ilinebytes = pixedata.iwidth*pixedata.ibpp/8;  //一帧图像的字节数  pixedata.itotalbytes = pixedata.ilinebytes * pixedata.iheight;  pixedata.videobuf=malloc(pixedata.itotalbytes); //申请存放图片数据空间 ​  //v412请求命令  struct v4l2_requestbuffers tv4l2reqbuffs;    /* 3、vidioc_reqbufs 申请buffer */  memset(&tv4l2reqbuffs, 0, sizeof(struct v4l2_requestbuffers)); ​  /* 分配4个buffer:实际上由vidioc_reqbufs获取到的信息来决定 */  tv4l2reqbuffs.count   = 4;    /*支持视频捕获功能*/  tv4l2reqbuffs.type    = v4l2_buf_type_video_capture;    /* 表示申请的缓冲是支持mmap */  tv4l2reqbuffs.memory  = v4l2_memory_mmap;    /* 为分配buffer做准备 */  ioctl(ifd, vidioc_reqbufs, &tv4l2reqbuffs);    for (i = 0; i =20)cnt=0;      //清理计数器  char str[10];  sprintf(str,%d,cnt); //整数转为字符串    strcat(buffer,str);  strcat(buffer,.bmp);  printf(%s\n,buffer); //打印图片的名称    /*-----------------------------------------------------------  获取图片数据,用来保存为bmp图片格式  -------------------------------------------------------------*/     file * fp;     int i;     bitmapfileheader   bf;     bitmapinfoheader   bi;         memset(&bf ,0 ,sizeof(bitmapfileheader));     memset(&bi ,0 ,sizeof(bitmapinfoheader)); ​     fp = fopen(buffer, wb);     if(!fp)    {  printf(open %s error\n,buffer);  return ;  } ​  //set bitmapinfoheader 设置bmp信息头  bi.bisize = sizeof(bitmapinfoheader);//40;  bi.biwidth  = pixedata.iwidth;//imagewidth;  bi.biheight = pixedata.iheight;//imageheight;  bi.biplanes = 1;  bi.bibitcount = 24;//8;  bi.bicompression = 0;  bi.bisizeimage =pixedata.iheight*pixedata.iwidth*3; //;0  bi.bixpelspermeter = 0;  bi.biypelspermeter = 0;  bi.biclrused = 0;// 1valuestring,1)!=0)  {  printf(%s文件第%d行,出现错误:时间获取失败!\n,__file__,__line__);  return -1;  }      //获取结果  json=cjson_getobjectitem(root,result);  if(json==null)  {  printf(%s文件第%d行,出现错误:获取json对象失败!\n,__file__,__line__);  return -1;  }    //获取秒单位时间  cjson *data=cjson_getobjectitem(json,timestamp);  if(data==null)  {  printf(%s文件第%d行,出现错误:获取json对象失败!\n,__file__,__line__);  return -1;  }  printf(秒单位的时间:%s\n,data->valuestring);    data=cjson_getobjectitem(json,datetime_1);  if(data==null)  {  printf(%s文件第%d行,出现错误:获取json对象失败!\n,__file__,__line__);  return -1;  }  printf(datetime_1:%s\n,data->valuestring);    data=cjson_getobjectitem(json,datetime_2);  if(data==null)  {  printf(%s文件第%d行,出现错误:获取json对象失败!\n,__file__,__line__);  return -1;  }  printf(datetime_2:%s\n,data->valuestring);      data=cjson_getobjectitem(json,week_1);  if(data==null)  {  printf(%s文件第%d行,出现错误:获取json对象失败!\n,__file__,__line__);  return -1;  }  printf(week_1:%s\n,data->valuestring);      data=cjson_getobjectitem(json,week_2);  if(data==null)  {  printf(%s文件第%d行,出现错误:获取json对象失败!\n,__file__,__line__);  return -1;  }  printf(week_2:%s\n,data->valuestring);    data=cjson_getobjectitem(json,week_3);  if(data==null)  {  printf(%s文件第%d行,出现错误:获取json对象失败!\n,__file__,__line__);  return -1;  }  printf(week_3:%s\n,data->valuestring);    data=cjson_getobjectitem(json,week_4);  if(data==null)  {  printf(%s文件第%d行,出现错误:获取json对象失败!\n,__file__,__line__);  return -1;  }  printf(week_4:%s\n,data->valuestring);  /* */  cjson_delete(root); }复制代码 (5)解析天气预报 #include  #include  #include  #include cjson.h #include  #include  #include  ​ /* 标准时间运行格式: ./app */ int getdata(char *src); int main(int argc,char **argv) {   if(argc!=2)  {  printf(参数格式: ./app \n);  return 0;  }  /*1. 拼接访问的链接路径*/  char src[200];  char str1[]=http://api.k780.com:88/?app=weather.future'&'weaid=;  char str2[]='&&'appkey=10003'&'sign=b59bc3ef6191eb9f747dd4e83c99f2a4'&'format=json >data.txt;    strcpy(src,curl );  strcat(src,str1);  strcat(src,argv[1]);  strcat(src,str2);    system(src);  //执行浏览器数据    /*2. 读取源数据*/  file *file=fopen(data.txt,rb);  if(file==null)  {  printf(文件打开失败!\n);  exit(-1);  }    struct stat file_stat_buf;  stat(data.txt,&file_stat_buf); //获取文件的状态    char *src_data=malloc(file_stat_buf.st_size);  if(src_data==null)  {  printf(%s文件第%d行,出现错误:空间失败!\n,__file__,__line__);  exit(-1);  }    fread(src_data,1,file_stat_buf.st_size,file); //读取源数据到缓冲区    /*3. 数据解析*/  getdata(src_data);    /*4. 释放空间*/  free(src_data);  return 0; } ​ /* 函数功能:获取具体的数据 函数形参:保存json的源数据首地址 */ int getdata(char *src) {  /*1. 载入源数据,获取根对象*/  cjson *root=cjson_parse(src);  if(root==null)  {  printf(%s文件第%d行,出现错误:获取根对象失败!\n,__file__,__line__);  return -1;  }    /*2. 获取对象中的值*/  cjson *json=cjson_getobjectitem(root,success);  if(json==null)  {  printf(%s文件第%d行,出现错误:获取json对象失败!\n,__file__,__line__);  return -1;  }    //判断获取的值是否成功  if(strcmp(json->valuestring,1)!=0)  {  printf(%s文件第%d行,出现错误:时间获取失败!\n,__file__,__line__);  return -1;  }      //获取结果  json=cjson_getobjectitem(root,result);  if(json==null)  {  printf(%s文件第%d行,出现错误:获取json对象失败!\n,__file__,__line__);  return -1;  } ​  //获取数组大小  int cnt=cjson_getarraysize(json);   printf(cnt=%d\n,cnt);  int i;  for(i=0;ivaluestring);    p=cjson_getobjectitem(data,days);  printf(days=%s\n,p->valuestring);    p=cjson_getobjectitem(data,week);  printf(week=%s\n,p->valuestring);    p=cjson_getobjectitem(data,cityno);  printf(cityno=%s\n,p->valuestring);    p=cjson_getobjectitem(data,citynm);  printf(citynm=%s\n,p->valuestring);    p=cjson_getobjectitem(data,cityid);  printf(cityid=%s\n,p->valuestring);    p=cjson_getobjectitem(data,temperature);  printf(temperature=%s\n,p->valuestring);    p=cjson_getobjectitem(data,humidity);  printf(humidity=%s\n,p->valuestring);    p=cjson_getobjectitem(data,weather);  printf(weather=%s\n,p->valuestring);    p=cjson_getobjectitem(data,wind);  printf(wind=%s\n,p->valuestring);    p=cjson_getobjectitem(data,winp);  printf(winp=%s\n,p->valuestring);    p=cjson_getobjectitem(data,winp);  printf(winp=%s\n,p->valuestring);  printf(\n\n);  }  cjson_delete(root); }  

边缘计算vs云计算哪一个的效率更高
什么是bootlood?Bootloader的操作模式
2020年Chromebook的销量将增长到不低于3070万台
鸿蒙系统首批合作伙伴名单
消费电子未来10年前景,消费升级主线下电子板块全面受益
Linux开发_摄像头编程(实现拍照功能)
液胀式温控器的工作原理和安装注意事项
迈动互联获得中国建设银行专精特新专项授信贷款
荣耀MagicBook新一代产品发布 带来全面屏沉浸视野
物联网将如何影响数字证据
I2C总线控制的高性能音频处理电路设计
rs485通信OSI模型网络层
不同种类的损失函数以及它们的作用
本土IC制造业发展:探求特色之路
虹科Pico动态 |【盖世汽车-走进东风商用车技术展】精彩回顾
小米有哪些EMC实验室
一分钟了解降低高性能嵌入式设计门槛的半导体STM32F7微控制器
逆变器电缆需要几米,小于6英尺
2022 CCF国际AIOps挑战赛决赛即将在京举办
有源RFID系统技术及数据的可靠传输