0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

DS小龙哥-嵌入式技术 2022-09-17 15:34 2127次阅读

这篇文章主要介绍Linux下UVC免驱摄像头操作流程,介绍V4L2框架、完成摄像头拍照保存为BMP图像到本地,最后贴出了利用CJSON库解析天气预报、北京时间接口返回的数据例子代码(上篇文章的案例补充)。

任务1:摄像头操作方式

(1)摄像头框架介绍

Linux、windows这些系统下很多摄像头都是免驱(UVC)。

v4l2 :免驱摄像头框架----一堆结构体。

Linux下开发摄像头的不同角度问题:(嵌入式开发)

【1】上层软件系统开发(系统编程),控制驱动提供的接口使用摄像头。

【2】底层硬件系统开发(驱动编程),直接控制摄像头采集数据。

摄像头功能:将采集到的图像数据转为二进制数据返回。

驱动的代码集成在操作系统里。

在操作系统里使用摄像头步骤:学习接口函数的调用。

fread(); read();

Linux下是一切设备皆文件: 摄像头、网卡、声卡、鼠标、键盘………………….

Linux下设备文件存放的位置: /dev目录下。

在虚拟机跑Linux,使用外设设备都需要单独挂载才可以使用。

挂载摄像头:

img

查看摄像头的设备节点:

[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 安装源码。(会将编译好的文件拷贝到指定的目录下)

img
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 < tV4l2ReqBuffs.count; i++) 
     {
         memset(&tV4l2Buf, 0, sizeof(struct v4l2_buffer));
         tV4l2Buf.index = i;
         tV4l2Buf.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
         tV4l2Buf.memory = V4L2_MEMORY_MMAP;
 ​
         /* 6、VIDIOC_QUERYBUF 确定每一个buffer的信息 并且 mmap */
         ioctl(iFd, VIDIOC_QUERYBUF, &tV4l2Buf);
         //映射空间地址
         pucVideBuf[i] = mmap(0 /* start anywhere */ ,
                   tV4l2Buf.length, PROT_READ, MAP_SHARED, iFd,
                   tV4l2Buf.m.offset);
         printf("mmap %d addr:%p\n",i,pucVideBuf[i]);
     }
 ​
     /* 4、VIDIOC_QBUF  放入队列*/
     for (i = 0; i 在LCD上显示:rgb888 */
     initLut();
     printf("开始采集数据.......\n");
     FD_ZERO(&readfds);
     FD_SET(iFd,&readfds);
     select(iFd+1,&readfds,NULL,NULL,NULL);
   
     memset(&tV4l2Buf, 0, sizeof(struct v4l2_buffer));
     tV4l2Buf.type    = V4L2_BUF_TYPE_VIDEO_CAPTURE; //类型
     tV4l2Buf.memory  = V4L2_MEMORY_MMAP; //存储空间类型
 ​
     /* 9、VIDIOC_DQBUF    从队列中取出 */
     error = ioctl(iFd, VIDIOC_DQBUF, &tV4l2Buf); //取出一帧数据
     ListNum = tV4l2Buf.index; //索引编号
     
     //将YUV转换为RGB
     Pyuv422torgb32(pucVideBuf[ListNum],Pixedata.iWidth,Pixedata.iHeight);
     
     //保存BMP
     save_bmp(Pixedata.VideoBuf); 
     memset(&tV4l2Buf, 0, sizeof(struct v4l2_buffer));
     tV4l2Buf.index  = ListNum;
     tV4l2Buf.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
     tV4l2Buf.memory = V4L2_MEMORY_MMAP;
     error = ioctl(iFd, VIDIOC_QBUF, &tV4l2Buf);
 }
 ​
 ​
 /*-----------------保存为BMP格式的图片------------------*/
 typedef unsigned char  BYTE;
 typedef unsigned short  WORD;
 typedef unsigned long  DWORD;
 ​
 #pragma pack(1)
 typedef struct tagBITMAPFILEHEADER{
      WORD     bfType;                // the flag of bmp, value is "BM"
      DWORD    bfSize;                // size BMP file ,unit is bytes
      DWORD    bfReserved;            // 0
      DWORD    bfOffBits;             // must be 54  RGB数据存放位置
 }BITMAPFILEHEADER;
 ​
 typedef struct tagBITMAPINFOHEADER{
      DWORD    biSize;            // must be 0x28
      DWORD    biWidth;           // 宽度
      DWORD    biHeight;          // 高度
      WORD     biPlanes;          // must be 1
      WORD     biBitCount;            // 像素位数
      DWORD    biCompression;         //
      DWORD    biSizeImage;       //
      DWORD    biXPelsPerMeter;   //
      DWORD    biYPelsPerMeter;   //
      DWORD    biClrUsed;             //
      DWORD    biClrImportant;        //
 }BITMAPINFOHEADER;
 ​
 ​
 //保存为BMP格式的文件
 void save_bmp(char *src)
 {
     /*-----------------------------------------------------------
                     获取时间参数,用来给图片命名
     -------------------------------------------------------------*/
     time_t t;
     struct tm *tmp;
     char buffer[1024] = {0};
     t = time(NULL);
     tmp=localtime(&t);
     if(strftime(buffer, sizeof(buffer), "%Y%m%d%H%M%S_", tmp) == 0) 
     {
         printf("timer error\n");
     }
     
     static int cnt=0;      //静态变量存放总数量
     cnt++;
     if(cnt>=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<<(bi.biBitCount)
     bi.biClrImportant = 0;
 ​
     //Set BITMAPFILEHEADER
     bf.bfType = 0x4d42; //'B''M'
     bf.bfSize = 54 + bi.biSizeImage;// sizeof(BITMAPFILEHEADER);    
     bf.bfReserved = 0;
     bf.bfOffBits = 54;
        
     fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, fp);
     fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, fp);    
     fwrite(src, Pixedata.iWidth*Pixedata.iHeight*3,1,fp);
     fclose(fp);
 }
 ​
 /*----------------------YUV转RGB算法-------------------*/
 ​
 static int *LutYr = NULL;
 static int *LutYg = NULL;;
 static int *LutYb = NULL;;
 static int *LutVr = NULL;;
 static int *LutVrY = NULL;;
 static int *LutUb = NULL;;
 static int *LutUbY = NULL;;
 static int *LutRv = NULL;
 static int *LutGu = NULL;
 static int *LutGv = NULL;
 static int *LutBu = NULL;
 ​
 ​
 unsigned char RGB24_TO_Y(unsigned char r, unsigned char g, unsigned char b)
 {
     return (LutYr[(r)] + LutYg[(g)] + LutYb[(b)]);
 }
 ​
 unsigned char YR_TO_V(unsigned char r, unsigned char y)
 {
     return (LutVr[(r)] + LutVrY[(y)]);
 }
 ​
 unsigned char YB_TO_U(unsigned char b, unsigned char y)
 {
     return (LutUb[(b)] + LutUbY[(y)]);
 }
 ​
 unsigned char R_FROMYV(unsigned char y, unsigned char v)
 {
     return CLIP((y) + LutRv[(v)]);
 }
 ​
 unsigned char G_FROMYUV(unsigned char y, unsigned char u, unsigned char v)
 {
     return CLIP((y) + LutGu[(u)] + LutGv[(v)]);
 }
 ​
 unsigned char B_FROMYU(unsigned char y, unsigned char u)
 {
     return CLIP((y) + LutBu[(u)]);
 }
 ​
 void initLut(void)
 {
     int i;
     #define Rcoef 299 
     #define Gcoef 587 
     #define Bcoef 114 
     #define Vrcoef 711 //656 //877 
     #define Ubcoef 560 //500 //493 564
     
     #define CoefRv 1402
     #define CoefGu 714 // 344
     #define CoefGv 344 // 714
     #define CoefBu 1772
     
     LutYr = malloc(256*sizeof(int));
     LutYg = malloc(256*sizeof(int));
     LutYb = malloc(256*sizeof(int));
     LutVr = malloc(256*sizeof(int));
     LutVrY = malloc(256*sizeof(int));
     LutUb = malloc(256*sizeof(int));
     LutUbY = malloc(256*sizeof(int));
     
     LutRv = malloc(256*sizeof(int));
     LutGu = malloc(256*sizeof(int));
     LutGv = malloc(256*sizeof(int));
     LutBu = malloc(256*sizeof(int));
     for (i= 0;i < 256;i++)
     {
         LutYr[i] = i*Rcoef/1000 ;
         LutYg[i] = i*Gcoef/1000 ;
         LutYb[i] = i*Bcoef/1000 ;
         LutVr[i] = i*Vrcoef/1000;
         LutUb[i] = i*Ubcoef/1000;
         LutVrY[i] = 128 -(i*Vrcoef/1000);
         LutUbY[i] = 128 -(i*Ubcoef/1000);
         LutRv[i] = (i-128)*CoefRv/1000;
         LutBu[i] = (i-128)*CoefBu/1000;
         LutGu[i] = (128-i)*CoefGu/1000;
         LutGv[i] = (128-i)*CoefGv/1000;
     }   
 }
 ​
 ​
 void freeLut(void)
 {
     free(LutYr);
     free(LutYg);
     free(LutYb);
     free(LutVr);
     free(LutVrY);
     free(LutUb);
     free(LutUbY);
     
     free(LutRv);
     free(LutGu);
     free(LutGv);
     free(LutBu);
 }
复制代码;>

(4)解析北京时间

#include 
#include 
#include 
#include "cJSON.h"
#include 
#include 
#include 
​
/*
标准时间运行格式: ./app
*/
int GetData(char *src);
int main(int argc,char **argv)
{   
    /*1. 拼接访问的链接路径*/
    char src[200];
    char str[]="http://api.k780.com:88/?app=life.time'&'appkey=10003'&'sign=b59bc3ef6191eb9f747dd4e83c99f2a4'&'format=json >data.txt";
    
    strcpy(src,"curl ");
    strcat(src,str);
    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;
    }
    
    //获取秒单位时间
    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);
}

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    11385

    浏览量

    211696
  • 摄像头
    +关注

    关注

    60

    文章

    4897

    浏览量

    96990
  • 编程
    +关注

    关注

    88

    文章

    3659

    浏览量

    94461
收藏 人收藏

    相关推荐

    迅为RK3588开发板实时系统编译-Preemption系统/ Xenomai系统编译-选择摄像头配置

    上的接口如下所示。如果想要单独使用哪个接口开启对应的宏定义即可,注意只能单独使能单个摄像头。如果想要使用多个摄像头,请参考《【北京迅为】itop-3588开发摄像头使用手册》。 更
    发表于 01-18 10:15

    米尔瑞芯微RK3576实测轻松搞定三屏八摄像头

    屏异显: LVDS实现接10寸触摸屏:输出内容为是通过开启浏览器引擎访问米尔网页 MINI DP接27寸显示器:输出内容为8路摄像头捕捉图像预览 HDMI接15寸HDMI显示器:输出以基于QT开发
    发表于 01-17 11:33

    车载摄像头的EMC问题案例

    一前言 如今,车载摄像头已经不再仅仅是一个辅助设备,而是逐渐成为了智能驾驶系统中不可或缺的一部分。360度全景监控、行车记录仪以及自动驾驶辅助功能,车载摄像头的应用范围不断拓展,技术也在不断创新
    的头像 发表于 12-18 11:11 979次阅读
    车载<b class='flag-5'>摄像头</b>的EMC问题案例

    安防监控摄像头气密性测试案例-连拓精密#摄像头气密检测设备

    摄像头
    连拓精密科技
    发布于 :2024年12月11日 15:00:21

    摄像头及红外成像的基本工作原理

    本文介绍了摄像头及红外成像的基本工作原理,摄像头可以将看到的图像真实的呈现出来,所见即所得! 摄像头如何工作? 摄像头可以将看到的图像真实的呈现出来,所见即所得。   比如人眼看到的一
    的头像 发表于 11-25 09:28 1457次阅读
    <b class='flag-5'>摄像头</b>及红外成像的基本工作原理

    用于环视和CMS摄像头系统的四通道摄像头应用程序

    电子发烧友网站提供《用于环视和CMS摄像头系统的四通道摄像头应用程序.pdf》资料免费下载
    发表于 10-11 10:02 0次下载
    用于环视和CMS<b class='flag-5'>摄像头</b>系统的四通道<b class='flag-5'>摄像头</b>应用程序

    【飞凌嵌入式OK3576-C开发板体验】 USB摄像头拍照测试

    USB摄像头拍照 将 USB 摄像头插入开发板,将自动安装 uvc 驱动 使用命令查看usb摄像头,已经将USB
    发表于 10-10 09:24

    NVIDIA多摄像头追踪工作流的应用架构

    为提高安全性并优化运营,仓库、工厂、体育场、机场等大型区域通常会有数百个摄像头进行监控。多摄像头追踪指的是通过这些摄像头追踪对象,并精确测量其活动,以此实现对空间的有效监控和管理。
    的头像 发表于 09-06 14:23 552次阅读
    NVIDIA多<b class='flag-5'>摄像头</b>追踪工作流的应用架构

    CANape Option DA中参考摄像头的标定演示#CANape

    摄像头
    北汇信息POLELINK
    发布于 :2024年07月30日 12:37:29

    基于FPGA的摄像头心率检测装置设计

    的 OpenCV 等开源库,可以使众多图像处理步骤得到简化,有利于实现更复杂的功能。 2.4 各模块介绍2.4.1.数据采集模块 使用摄像头拍摄人脸画面,通过 usb 接口与 fpga
    发表于 07-01 17:58

    esp32是如何与摄像头连接的呢?

    新手。看了esp32的模组中没有摄像头的硬件接口,请问它是如何与摄像头连接的呢
    发表于 06-28 15:01

    esp32-s2-soala-v1.2如何获取摄像头描述符?

    开发板:esp32-s2-soala-v1.2 开发环境:WIN10 + IDF4.4 我想使用uvc摄像头的例程,啥都没改测试初始化是成功的,但是获取图片后就会卡死 应该是摄像头没有
    发表于 06-27 06:48

    替换SiTime,汽车摄像头可使用国产可编程振荡

    替换SiTime,汽车摄像头可使用国产可编程振荡
    的头像 发表于 06-18 09:34 410次阅读
    替换SiTime,汽车<b class='flag-5'>摄像头</b>可使用国产可<b class='flag-5'>编程</b>振荡

    智能摄像头抄表器是什么?

    进行图像识别,实现无接触、无误差的远程抄表,极大地提高了抄表效率和准确性。2.技术原理与优势2.1AI图像识别:智能摄像头抄表器的核心在于其内置的AI算法,能够准
    的头像 发表于 04-24 14:14 876次阅读
    智能<b class='flag-5'>摄像头</b>抄表器是什么?