社区导航

 

搜索
查看: 489|回复: 2

[经验] 【树莓派3B+测评】安装libjpeg库&驱动USB摄像头

[复制链接]

109

TA的帖子

0

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2018-12-24 09:15 | 显示全部楼层 |阅读模式
本帖最后由 donatello1996 于 2018-12-24 09:21 编辑

    Linux系统中操作图像的相关函数均可直接通过libjpeg库实现,通过此库可实现BMP转JPG,BMP转FrameBuffer显示,或是FrameBuffer转BMP/JPG保存,在此次实验中,我用libjpeg库实现FrameBuffer直接转为JPG图片。


准备工作,首先下载安装libjpeg库的支持:
apt-get install libjpeg8-dev
55.jpg
然后插上USB免驱摄像头,如果能正常驱动的话会在/dev目录下生成video开头的外设:
IMG_20181224_091036.jpg 61.jpg
使用VL42库的相关函数抓取摄像头图片并保存到本地:


        if(V4L2_Init((char*)"/dev/video0")!=0)
        {
            printf("摄像头初始化失败\n");
            return 0;
        }


        V4l2_Grab();
        Yuyv_2_RGB888(buffers,frame_buffer);
        Encode_Jpeg(frame_buffer,IMAGEWIDTH,IMAGEHEIGHT,(char*)"1.jpg");


V4L2的操作头文件:
#ifndef CAMERA_H
#define CAMERA_H


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <linux/types.h>
#include <linux/videodev2.h>
#include <setjmp.h>
#include "jpeglib.h"
#include "lcd.h"


static int fd_video;
static struct  v4l2_capability  cap;
//V4L2设备信息读结构体对象
struct v4l2_fmtdesc fmtdesc;
struct v4l2_format fmt;
//V4L2设置捕获信息读写结构体对象
struct v4l2_streamparm setfps;
//V4L2设置帧数相关读写结构体对象
struct v4l2_requestbuffers req;
//V4L2申请帧缓冲结构体对象
struct v4l2_buffer buf;
//V4L2缓存数据结构体对象
enum v4l2_buf_type type;
//V4L2采集类型结构体对象


#define  IMAGEWIDTH    640
#define  IMAGEHEIGHT   480
unsigned char frame_buffer[IMAGEWIDTH*IMAGEHEIGHT*3];




typedef struct
{
    void *start;
    unsigned int length;
} buffer;


buffer *buffers;


int V4L2_Init(char * filename)
{
    int i,ret = 0;


    if ((fd_video=open(filename,O_RDWR))==-1)
    {
        printf("Error opening V4L interface\n");
        return (0);
    }


    if (ioctl(fd_video,VIDIOC_QUERYCAP,&cap) == -1)
    {
        printf("Error opening device %s: unable to query device.\n",filename);
        return (0);
    }
    else
    {
         printf("driver:\t\t%s\n",cap.driver);
         printf("card:\t\t%s\n",cap.card);
         printf("bus_info:\t%s\n",cap.bus_info);
         printf("version:\t%d\n",cap.version);
         printf("capabilities:\t%x\n",cap.capabilities);


         if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == V4L2_CAP_VIDEO_CAPTURE)
         {
            printf("Device %s: supports capture.\n",filename);
        }


        if ((cap.capabilities & V4L2_CAP_STREAMING) == V4L2_CAP_STREAMING)
        {
            printf("Device %s: supports streaming.\n",filename);
        }
    }


    fmtdesc.index=0;
    fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
    printf("Support format:\n");
    while(ioctl(fd_video,VIDIOC_ENUM_FMT,&fmtdesc)!=-1)
    {
        printf("\t%d.%s\n",fmtdesc.index+1,fmtdesc.description);
        fmtdesc.index++;
    }


    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
    fmt.fmt.pix.height = IMAGEHEIGHT;
    fmt.fmt.pix.width =  IMAGEWIDTH;
    fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;


    if(ioctl(fd_video,VIDIOC_S_FMT, &fmt) == -1)
    {
        printf("Unable to set format\n");
        return 1;
    }
    if(ioctl(fd_video,VIDIOC_G_FMT, &fmt) == -1)
    {
        printf("Unable to get format\n");
        return 2;
    }
    {
         printf("fmt.type:\t\t%d\n",fmt.type);
         printf("pix.pixelformat:\t%c%c%c%c\n",fmt.fmt.pix.pixelformat & 0xFF, (fmt.fmt.pix.pixelformat >> 8) & 0xFF,


(fmt.fmt.pix.pixelformat >> 16) & 0xFF, (fmt.fmt.pix.pixelformat >> 24) & 0xFF);
         printf("pix.height:\t\t%d\n",fmt.fmt.pix.height);
         printf("pix.width:\t\t%d\n",fmt.fmt.pix.width);
         printf("pix.field:\t\t%d\n",fmt.fmt.pix.field);
    }
    //set fps
    ioctl(fd_video, VIDIOC_G_PARM, &setfps);
    //setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    //setfps.parm.capture.timeperframe.numerator = 30;
    //setfps.parm.capture.timeperframe.denominator = 30;




    req.count=4;
    req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory=V4L2_MEMORY_MMAP;
    if(ioctl(fd_video,VIDIOC_REQBUFS,&req)==-1)
    {
        printf("request for buffers error\n");
        return 3;
    }


    printf("init %s \t[OK]\n",filename);


    return 0;
}


int V4l2_Grab()
{
    unsigned int n_buffers;


    buffers =(buffer*)malloc(req.count*sizeof (*buffers));
    if (!buffers)
    {
        printf ("Out of memory\n");
        return 0;
    }


    for (n_buffers = 0; n_buffers < req.count; n_buffers++)
    {
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_MMAP;
        buf.index = n_buffers;
        //query buffers
        if (ioctl (fd_video,VIDIOC_QUERYBUF, &buf) == -1)
        {
            printf("query buffer error\n");
            return(0);
        }


        buffers[n_buffers].length = buf.length;
        buffers[n_buffers].start = mmap(NULL,buf.length,PROT_READ |PROT_WRITE, MAP_SHARED,
        fd_video, buf.m.offset);
        if (buffers[n_buffers].start == MAP_FAILED)
        {
            printf("buffer map error\n");
            return 0;
        }
    }


    for (n_buffers = 0; n_buffers < req.count; n_buffers++)
    {
        buf.index = n_buffers;
        ioctl(fd_video, VIDIOC_QBUF, &buf);
    }


    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ioctl (fd_video, VIDIOC_STREAMON, &type);


    ioctl(fd_video, VIDIOC_DQBUF, &buf);


    printf("grab yuyv OK\n");
    return 1;
}


int Yuyv_2_RGB888(buffer* input_buffers,unsigned char *output_buffer)
{
    int i,j,r1,g1,b1,r2,g2,b2;
    unsigned char y1,y2,u,v;
    unsigned char *pointer;


    pointer =(unsigned char*)input_buffers[0].start;


    for(i=0;i<IMAGEHEIGHT;i++)
    {
    for(j=0;j<IMAGEWIDTH/2;j++)
    //每次取4个字节,也就是两个像素点,转换rgb,6个字节,还是两个像素点
    {
    y1 = *( pointer + (i*IMAGEWIDTH/2+j)*4);
    u  = *( pointer + (i*IMAGEWIDTH/2+j)*4 + 1);
    y2 = *( pointer + (i*IMAGEWIDTH/2+j)*4 + 2);
    v  = *( pointer + (i*IMAGEWIDTH/2+j)*4 + 3);


    r1 = y1 + 1.042*(v-128);
    g1 = y1 - 0.34414*(u-128) - 0.71414*(v-128);
    b1 = y1 + 1.772*(u-128);


    r2 = y2 + 1.042*(v-128);
    g2 = y2 - 0.34414*(u-128) - 0.71414*(v-128);
    b2 = y2 + 1.772*(u-128);


    if(r1>255)
    r1 = 255;
    else if(r1<0)
    r1 = 0;


    if(b1>255)
    b1 = 255;
    else if(b1<0)
    b1 = 0;


    if(g1>255)
    g1 = 255;
    else if(g1<0)
    g1 = 0;


    if(r2>255)
    r2 = 255;
    else if(r2<0)
    r2 = 0;


    if(b2>255)
    b2 = 255;
    else if(b2<0)
    b2 = 0;


    if(g2>255)
    g2 = 255;
    else if(g2<0)
    g2 = 0;


    *(output_buffer + (i*IMAGEWIDTH/2+j)*6    ) = (unsigned char)b1;
    *(output_buffer + (i*IMAGEWIDTH/2+j)*6 + 1) = (unsigned char)g1;
    *(output_buffer + (i*IMAGEWIDTH/2+j)*6 + 2) = (unsigned char)r1;
    *(output_buffer + (i*IMAGEWIDTH/2+j)*6 + 3) = (unsigned char)b2;
    *(output_buffer + (i*IMAGEWIDTH/2+j)*6 + 4) = (unsigned char)g2;
    *(output_buffer + (i*IMAGEWIDTH/2+j)*6 + 5) = (unsigned char)r2;
    }
    }
    printf("change to RGB OK \n");
    free(input_buffers);
}


int Encode_Jpeg(unsigned char *lpbuf,int width,int height,char *output_filename)
{
    struct jpeg_compress_struct cinfo ;
    struct jpeg_error_mgr jerr ;
    JSAMPROW  row_pointer[1] ;
    int row_stride ;
    char *buf=NULL ;
    int x ;


    FILE *fptr_jpg = fopen ((char *)output_filename,"wb");
    if(fptr_jpg==NULL)
    {
    printf("Encoder:open file failed!/n") ;
     return 0;
    }


    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);
    jpeg_stdio_dest(&cinfo, fptr_jpg);


    cinfo.image_width = width;
    cinfo.image_height = height;
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;


    jpeg_set_defaults(&cinfo);




    jpeg_set_quality(&cinfo, 80,1);




    jpeg_start_compress(&cinfo, 1);


    row_stride = width * 3;
    buf=(char*)malloc(row_stride);
    row_pointer[0] =(unsigned char*)buf;
    while (cinfo.next_scanline < height)
    {
     for (x=0;x<row_stride; x+=3)
    {


    buf[x]   = lpbuf[x];
    buf[x+1] = lpbuf[x+1];
    buf[x+2] = lpbuf[x+2];


    }
    jpeg_write_scanlines (&cinfo, row_pointer, 1);
    lpbuf += row_stride;
    }


    jpeg_finish_compress(&cinfo);
    fclose(fptr_jpg);
    jpeg_destroy_compress(&cinfo);
    free(buf);
    printf("save \"JPEG\"OK\n");
    return 0 ;


}


int close_v4l2(void)
{
     if(fd_video!=-1)
     {
         close(fd_video);
         return 1;
     }
     return 0;
}


#endif


由于使用了libjpeg,因此在文件编译后面要加-ljpeg选项:
63.jpg
执行,执行完毕之后会在工程目录下生成1.jpg图片:
62.jpg
64.jpg 1.jpg
此帖出自ARM技术论坛


回复

使用道具 举报

33

TA的帖子

0

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2018-12-28 10:41 | 显示全部楼层


回复

使用道具 举报

62

TA的帖子

0

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2019-1-16 10:31 | 显示全部楼层



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

  • 论坛活动 E手掌握

    扫码关注
    EEWORLD 官方微信

  • EE福利  唾手可得

    扫码关注
    EE福利 唾手可得

Archiver|手机版|小黑屋|电子工程世界 ( 京ICP证 060456 )

GMT+8, 2019-3-22 06:42 , Processed in 0.140539 second(s), 17 queries , Gzip On, MemCache On.

快速回复 返回顶部 返回列表