Leo手把手教你C语言使用libuvc对USB摄像头进行开发

该文详细介绍了如何利用开源库libuvc和libusb在C语言环境中安装、配置,并进行跨平台的USB摄像头开发。通过编写Makefile和封装libuvc接口,可以实现与摄像头的通讯,包括初始化、释放、启动设备,以及YUYV到RGB的帧格式转换。文中还提供了示例代码展示如何同时操作两个摄像头。
摘要由CSDN通过智能技术生成

市面上的所谓免驱USB摄像头实际就是服从了统一输出流协议(UVC)的设备。所以只要掌握如何使用UVC协议和USB摄像头进行通讯,就能对USB摄像头进行开发了。著名的开源项目LIBUVC就是分装了C语言接口方便跨平台调用libuvc的库来和USB设备进行通讯。

1. 安装libuvc以及依赖库libusb

git clone https://github.com/libusb/libusb.git
cd libusb
./configure  --disable-udev 
make
make install

 

git clone https://github.com/libuvc/libuvc.git
cd libuvc
mkdir -p build/
cd build
cmake ..
make 
make install

 2. (可选)将库编译出并放置在一个文件夹中用以区分版本

THIRDPARTY_FOLDER=${PWD}
sudo apt-get install libudev-dev -y
cd ${THIRDPARTY_FOLDER}/libusb
sh bootstrap.sh
./configure  --disable-udev 
make


cd ${THIRDPARTY_FOLDER}/libuvc
mkdir -p build/
cd build
cmake ..
make 

mkdir -p ${THIRDPARTY_FOLDER}/libs/
mkdir -p ${THIRDPARTY_FOLDER}/libs/linux/
cp -f ${THIRDPARTY_FOLDER}/libusb/libusb/.libs/libusb-1.0.a ${THIRDPARTY_FOLDER}/libs/linux/
cp -f ${THIRDPARTY_FOLDER}/libuvc/build/libuvc.a ${THIRDPARTY_FOLDER}/libs/linux/
cp -r ${THIRDPARTY_FOLDER}/libuvc/include/libuvc  ${THIRDPARTY_FOLDER}/libs/linux/
cp -r ${THIRDPARTY_FOLDER}/libuvc/build/include/libuvc/libuvc_config.h  ${THIRDPARTY_FOLDER}/libs/linux/libuvc/

3. 写Makefile调用libuvc和libusb-1.0

cc:=g++
THIRD_PATY_LIBS_PATH:=$(PWD)/../../thirdParty/libs/linux
ccflag:=-w -O3 -fpermissive -luvc -lusb-1.0 -L$(THIRD_PATY_LIBS_PATH)/. -I$(THIRD_PATY_LIBS_PATH)/
ccflag+=-lGL -lGLU -lglut -w -O3
# src:=./leouvc.c
src_demo:=./leouvc.c ./leouvcDemo.c
src_demo_gl:=./leouvc.c ./leouvcDemoGL.c
exe_demo:=./leouvcDemo
exe_demoGL:=./leouvcDemoGL
build:
		$(cc) $(src_demo) $(ccflag) -o $(exe_demo)
		$(cc) $(src_demo_gl) $(ccflag) -o $(exe_demoGL)
clean:
		rm -rf $(exe_demo)
		rm -rf $(exe_demoGL)
run:
		./$(exe_demo)
run_gl:
		./$(exe_demoGL)

4. 分装libuvc接口进leouvc.c & leouvc.h

#ifndef __LEOUVC_H__
#define __LEOUVC_H__
#include "libuvc/libuvc.h"
typedef void (*uvc_utils_device_cb)(uvc_frame_t *frame, void *ptr);
typedef struct UVC_UTILS_DEVICE_t
{
    int pid;
    int vid;
    int format;
    int targetFps;
    int frameWidth;
    int frameHeight;
    uvc_utils_device_cb    cb;
    uvc_context_t          *ctx;
    uvc_error_t            res;
    uvc_device_t           *dev;
    uvc_device_handle_t    *devh;
    uvc_stream_ctrl_t      ctrl;
}UVC_UTILS_DEVICE;
void init_uvc_camera_device(UVC_UTILS_DEVICE * dev);
void free_uvc_camera_device(UVC_UTILS_DEVICE * dev);
void start_uvc_camera_device(UVC_UTILS_DEVICE * dev);
void log_uvc_frame_format(int uvc_f);
void cvt_yuyv2rgb(uint8_t * yuyv,uint8_t * gl_rgb_buffer,uint32_t w,uint32_t h);
#endif //__LEOUVC_H__
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include "leouvc.h"
#define CHECK_0_255(V) ( (V>255) ? (255) : (V<0 ? 0 : V ) )
void init_uvc_camera_device(UVC_UTILS_DEVICE * dev)
{
    dev->res = uvc_init(&dev->ctx, NULL); 
    if(dev->res<0) printf("uvc_init failed!\n");
    dev->res = uvc_find_device(dev->ctx, &dev->dev, dev->pid, dev->vid, NULL);
    if(dev->res<0) printf("uvc_find_device failed!\n");
    dev->res = uvc_open(dev->dev, &dev->devh);
    if(dev->res<0) printf("uvc_open failed!\n");
    dev->res = uvc_get_stream_ctrl_format_size(dev->devh, &dev->ctrl, dev->format, dev->frameWidth, dev->frameHeight, dev->targetFps );
    if(dev->res<0) printf("uvc_get_stream_ctrl_format_size failed!\n");
    if(dev->res>=0) printf("init_uvc_camera_device ok!\n");
}
void free_uvc_camera_device(UVC_UTILS_DEVICE * dev)
{
    uvc_stop_streaming(dev->devh);
    uvc_close(dev->devh);
    uvc_unref_device(dev->dev);
    uvc_exit(dev->ctx);
    printf("free_uvc_camera_device ok!\n");
}
void start_uvc_camera_device(UVC_UTILS_DEVICE * dev)
{
    dev->res = uvc_start_streaming(dev->devh, &dev->ctrl, dev->cb, 0, 0);
    if(dev->res>=0)
    {
        printf("start_uvc_camera_device ok!\n");
    }
}
void log_uvc_frame_format(int uvc_f)
{
    switch(uvc_f)
    {
        case UVC_FRAME_FORMAT_ANY:         printf("UVC_FORMAT=UVC_FRAME_FORMAT_ANY\n");         break;
        case UVC_FRAME_FORMAT_UNCOMPRESSED:printf("UVC_FORMAT=UVC_FRAME_FORMAT_UNCOMPRESSED\n");break;
        case UVC_FRAME_FORMAT_COMPRESSED:  printf("UVC_FORMAT=UVC_FRAME_FORMAT_COMPRESSED\n");  break;
        case UVC_FRAME_FORMAT_YUYV:        printf("UVC_FORMAT=UVC_FRAME_FORMAT_YUYV\n");        break;
        case UVC_FRAME_FORMAT_UYVY:        printf("UVC_FORMAT=UVC_FRAME_FORMAT_UYVY\n");        break;
        case UVC_FRAME_FORMAT_RGB:         printf("UVC_FORMAT=UVC_FRAME_FORMAT_RGB\n");         break;
        case UVC_FRAME_FORMAT_BGR:         printf("UVC_FORMAT=UVC_FRAME_FORMAT_BGR\n");         break;
        case UVC_FRAME_FORMAT_MJPEG:       printf("UVC_FORMAT=UVC_FRAME_FORMAT_MJPEG\n");       break;
        case UVC_FRAME_FORMAT_H264:        printf("UVC_FORMAT=UVC_FRAME_FORMAT_H264\n");        break;
        case UVC_FRAME_FORMAT_GRAY8:       printf("UVC_FORMAT=UVC_FRAME_FORMAT_GRAY8\n");       break;
        case UVC_FRAME_FORMAT_GRAY16:      printf("UVC_FORMAT=UVC_FRAME_FORMAT_GRAY16\n");      break;
        case UVC_FRAME_FORMAT_BY8:         printf("UVC_FORMAT=UVC_FRAME_FORMAT_BY8\n");         break;
        case UVC_FRAME_FORMAT_BA81:        printf("UVC_FORMAT=UVC_FRAME_FORMAT_BA81\n");        break;
        case UVC_FRAME_FORMAT_SGRBG8:      printf("UVC_FORMAT=UVC_FRAME_FORMAT_SGRBG8\n");      break;
        case UVC_FRAME_FORMAT_SGBRG8:      printf("UVC_FORMAT=UVC_FRAME_FORMAT_SGBRG8\n");      break;
        case UVC_FRAME_FORMAT_SRGGB8:      printf("UVC_FORMAT=UVC_FRAME_FORMAT_SRGGB8\n");      break;
        case UVC_FRAME_FORMAT_SBGGR8:      printf("UVC_FORMAT=UVC_FRAME_FORMAT_SBGGR8\n");      break;
        case UVC_FRAME_FORMAT_NV12:        printf("UVC_FORMAT=UVC_FRAME_FORMAT_NV12\n");        break;
        case UVC_FRAME_FORMAT_P010:        printf("UVC_FORMAT=UVC_FRAME_FORMAT_P010\n");        break;
        case UVC_FRAME_FORMAT_COUNT:       printf("UVC_FORMAT=UVC_FRAME_FORMAT_COUNT\n");       break;

    }
}
void cvt_yuyv2rgb(uint8_t * yuyv,uint8_t * gl_rgb_buffer,uint32_t w,uint32_t h)
{

  for(uint32_t i=0;i<h;i++)
  {
    for(uint32_t j=0;j<(w/2);j++)
    {
        float Y1 = (float)(yuyv[i*2*w+j*4+0]);
        float U  = (float)(yuyv[i*2*w+j*4+1])-128;
        float Y2 = (float)(yuyv[i*2*w+j*4+2]);
        float V  = (float)(yuyv[i*2*w+j*4+3])-128;
        uint8_t r1 = (uint8_t)CHECK_0_255((float)Y1 + 1.4075*(float)V);
        uint8_t g1 = (uint8_t)CHECK_0_255((float)Y1 - 0.3455*(float)U - 0.7169*(float)V);
        uint8_t b1 = (uint8_t)CHECK_0_255((float)Y1 + 1.779* (float)U);
        uint8_t r2 = (uint8_t)CHECK_0_255((float)Y2 + 1.4075*(float)V);
        uint8_t g2 = (uint8_t)CHECK_0_255((float)Y2 - 0.3455*(float)U - 0.7169*(float)V);
        uint8_t b2 = (uint8_t)CHECK_0_255((float)Y2 + 1.779* (float)U);
  
        gl_rgb_buffer[i*3*w+j*6+0]=r1;
        gl_rgb_buffer[i*3*w+j*6+1]=g1;
        gl_rgb_buffer[i*3*w+j*6+2]=b1;
        gl_rgb_buffer[i*3*w+j*6+3]=r2;
        gl_rgb_buffer[i*3*w+j*6+4]=g2;
        gl_rgb_buffer[i*3*w+j*6+5]=b2;
    }
  }
}

5. 同时使用两个leouvc的结构体调用两个usb摄像头案例

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/time.h>
#include "leouvc.h"
void cam1_callback(uvc_frame_t *frame, void *ptr)
{
    struct timeval ts_cur;
    gettimeofday(&ts_cur,NULL);
    printf("[cam1_callback]: %lf ms ",(double)(ts_cur.tv_sec*100000+ts_cur.tv_usec)/1000);
    log_uvc_frame_format(frame->frame_format);
}
void cam2_callback(uvc_frame_t *frame, void *ptr)
{
    struct timeval ts_cur;
    gettimeofday(&ts_cur,NULL);
    printf("[cam2_callback]: %lf ms ",(double)(ts_cur.tv_sec*100000+ts_cur.tv_usec)/1000);
    log_uvc_frame_format(frame->frame_format);
}
int main(int argc , char * argv[])
{
    UVC_UTILS_DEVICE cam1;
    cam1.format      = UVC_FRAME_FORMAT_YUYV;
    cam1.frameWidth  = 640;
    cam1.frameHeight = 480;
    cam1.targetFps   = 30;
    cam1.pid         = 0x0120;
    cam1.vid         = 0x1234;
    cam1.cb          = cam1_callback;
    UVC_UTILS_DEVICE cam2;
    cam2.format      = UVC_FRAME_FORMAT_YUYV;
    cam2.frameWidth  = 1280;
    cam2.frameHeight = 480;
    cam2.targetFps   = 100;
    cam2.pid         = 0x15aa;
    cam2.vid         = 0x1555;
    cam2.cb          = cam2_callback;
    init_uvc_camera_device(&cam1);
    init_uvc_camera_device(&cam2);
    start_uvc_camera_device(&cam1);
    start_uvc_camera_device(&cam2);
    sleep(10);
    free_uvc_camera_device(&cam1);
    free_uvc_camera_device(&cam2);
    
}

6. 工程下载地址和demo演示视频地址

https://github.com/leonard73/LeoCPorintg.git

B站视频:

【纯C语言手撸UVC摄像头开发】

https://www.bilibili.com/video/BV1Vj411S74i/?share_source=copy_web&vd_source=0673d40f3e253d0787bd1c78fef7873d

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PyCharm是一款功能强大的集成开发环境(IDE),它提供了直接与Git进行交互的功能。下面是PyCharm中使用Git的简单程: 1. 安装Git:首先,确保你已经在你的计算机上安装了Git版本控制系统。你可以从Git官方网站(https://git-scm.com/downloads)下载并安装适合你操作系统的版本。 2. 配置Git:在使用Git之前,你需要配置你的用户名和电子邮件地址。你可以通过以下命令在终端或命令提示符中执行此操作: ``` git config --global user.name "Your Name" git config --global user.email "your_email@example.com" ``` 3. 在PyCharm中打开项目:在PyCharm中打开你的项目文件夹。 4. 初始化Git仓库:要将项目与Git进行管理,你需要在项目文件夹中初始化一个Git仓库。在PyCharm的底部工具栏上,点击"Version Control"按钮,然后选择"Git"。接下来,点击"Enable Version Control Integration"并选择你的项目文件夹。 5. 将文件添加到Git仓库:右键单击要添加到仓库的文件或文件夹,在上下文菜单中选择"Git",然后选择"Add"。这将把文件添加到暂存区。 6. 提交更改:在PyCharm的底部工具栏上,点击"Commit"按钮。这将打开一个窗口,显示你要提交的更改的文件列表。选择要提交的文件,填写提交消息,并点击"Commit"按钮。 7. 推送到远程仓库:如果你想将你的更改推送到远程仓库(例如GitHub),点击PyCharm顶部菜单栏的"VCS"->"Git"->"Push"。这将把你的更改推送到远程仓库。 8. 更新和拉取:要更新你的项目并拉取其他人的更改,点击PyCharm顶部菜单栏的"VCS"->"Git"->"Update Project",然后选择你要拉取的分支。 这只是一个基本的程,帮助你开始使用PyCharm和Git。如果你想深入了解更多Git命令和功能,可以参考Git的官方文档或其他在线程。希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值