这篇文章主要介绍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;// 1
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; } //获取秒单位时间 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系统技术及数据的可靠传输