2008-11-10 37 views

Trả lời

6

Đặt cược tốt nhất của bạn có thể là: video4linux (V4L)

Thật dễ sử dụng và mạnh mẽ.

13

Rất nhiều người trong chúng ta sử dụng OpenCV (cross-platform thư viện Computer Vision, hiện trên v2.1)

Đoạn sau lấy khung hình từ máy ảnh, chuyển đổi chúng sang dạng grayscale và hiển thị chúng trên màn hình:

#include <stdio.h> 
#include "cv.h" 
#include "highgui.h" 


typedef IplImage* (*callback_prototype)(IplImage*); 


/* 
* make_it_gray: custom callback to convert a colored frame to its grayscale version. 
* Remember that you must deallocate the returned IplImage* yourself after calling this function. 
*/ 
IplImage* make_it_gray(IplImage* frame) 
{ 
    // Allocate space for a new image 
    IplImage* gray_frame = 0; 
    gray_frame = cvCreateImage(cvSize(frame->width, frame->height), frame->depth, 1); 
    if (!gray_frame) 
    { 
     fprintf(stderr, "!!! cvCreateImage failed!\n"); 
     return NULL; 
    } 

    cvCvtColor(frame, gray_frame, CV_RGB2GRAY); 
    return gray_frame; 
} 

/* 
* process_video: retrieves frames from camera and executes a callback to do individual frame processing. 
* Keep in mind that if your callback takes too much time to execute, you might loose a few frames from 
* the camera. 
*/ 
void process_video(callback_prototype custom_cb) 
{   
    // Initialize camera 
    CvCapture *capture = 0; 
    capture = cvCaptureFromCAM(-1); 
    if (!capture) 
    { 
     fprintf(stderr, "!!! Cannot open initialize webcam!\n"); 
     return; 
    } 

    // Create a window for the video 
    cvNamedWindow("result", CV_WINDOW_AUTOSIZE); 

    IplImage* frame = 0; 
    char key = 0; 
    while (key != 27) // ESC 
    {  
     frame = cvQueryFrame(capture); 
     if(!frame) 
     { 
      fprintf(stderr, "!!! cvQueryFrame failed!\n"); 
      break; 
     } 

     // Execute callback on each frame 
     IplImage* processed_frame = (*custom_cb)(frame); 

     // Display processed frame 
     cvShowImage("result", processed_frame); 

     // Release resources 
     cvReleaseImage(&processed_frame); 

     // Exit when user press ESC 
     key = cvWaitKey(10); 
    } 

    // Free memory 
    cvDestroyWindow("result"); 
    cvReleaseCapture(&capture); 
} 

int main(int argc, char **argv) 
{ 
    process_video(make_it_gray); 

    return 0; 
} 
+1

Liên kết mới http://opencv.org/ – GramThanos

4

v4l2 ví dụ chính thức

gì bạn nhận được:

  • ./v4l2grab: chụp một vài bức ảnh chụp các tập tin outNNN.ppm
  • ./v4l2gl: hiển thị video trực tiếp trên cửa sổ sử dụng một kết cấu OpenGL và thô X11 cửa sổ (cộng với thị trường bất động của gluLookAt cho biện pháp tốt) (vẽ mắt, hey!).

Làm thế nào để có được nó trên Ubuntu 16.04:

sudo apt-get install libv4l-dev 
sudo apt-get build-dep libv4l-dev 
git clone git://linuxtv.org/v4l-utils.git 
cd v4l-utils 
# Matching the installed version of dpkg -s libv4l-dev 
git checkout v4l-utils-1.10.0 
./bootstrap.sh 
./configure 
make 
# TODO: fails halfway, but it does not matter for us now. 
cd contrib/tests 
make 

Nó cũng rất dễ dàng để sử dụng những ví dụ bên ngoài của cây Git, chỉ cần sao chép chúng ra, làm tương đối bao gồm "" tuyệt đối <>, và loại bỏ config.h . Tôi đã làm điều đó cho bạn tại địa chỉ: https://github.com/cirosantilli/cpp-cheat/tree/09fe73d248f7da2e9c9f3eff2520a143c259f4a6/v4l2

dụ tối thiểu từ tài liệu

Các tài liệu 4.9.0 chứa những gì dường như là một phiên bản tối thiểu của ./v4l2grab tại https://linuxtv.org/downloads/v4l-dvb-apis-new/uapi/v4l/v4l2grab-example.html. Tôi cần phải vá nó một cách tối thiểu và tôi đã gửi bản vá đến http://www.spinics.net/lists/linux-media/ (tài liệu của họ sống trong cây hạt nhân Linux như đầu tiên, gọn gàng), nơi mà nó bị bỏ qua.

Cách sử dụng:

gcc v4l2grab.c -lv4l2 
./a.out 

đang Patched:

/* V4L2 video picture grabber 
Copyright (C) 2009 Mauro Carvalho Chehab <[email protected]> 

This program is free software; you can redistribute it and/or modify 
it under the terms of the GNU General Public License as published by 
the Free Software Foundation version 2 of the License. 

This program is distributed in the hope that it will be useful, 
but WITHOUT ANY WARRANTY; without even the implied warranty of 
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
GNU General Public License for more details. 
*/ 

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <fcntl.h> 
#include <errno.h> 
#include <sys/ioctl.h> 
#include <sys/types.h> 
#include <sys/time.h> 
#include <sys/mman.h> 
#include <linux/videodev2.h> 
#include <libv4l2.h> 

#define CLEAR(x) memset(&(x), 0, sizeof(x)) 

struct buffer { 
     void *start; 
     size_t length; 
}; 

static void xioctl(int fh, int request, void *arg) 
{ 
     int r; 

     do { 
       r = v4l2_ioctl(fh, request, arg); 
     } while (r == -1 && ((errno == EINTR) || (errno == EAGAIN))); 

     if (r == -1) { 
       fprintf(stderr, "error %d, %s\\n", errno, strerror(errno)); 
       exit(EXIT_FAILURE); 
     } 
} 

int main(int argc, char **argv) 
{ 
     struct v4l2_format    fmt; 
     struct v4l2_buffer    buf; 
     struct v4l2_requestbuffers  req; 
     enum v4l2_buf_type    type; 
     fd_set       fds; 
     struct timeval     tv; 
     int        r, fd = -1; 
     unsigned int     i, n_buffers; 
     char       *dev_name = "/dev/video0"; 
     char       out_name[256]; 
     FILE       *fout; 
     struct buffer     *buffers; 

     fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0); 
     if (fd < 0) { 
       perror("Cannot open device"); 
       exit(EXIT_FAILURE); 
     } 

     CLEAR(fmt); 
     fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
     fmt.fmt.pix.width  = 640; 
     fmt.fmt.pix.height  = 480; 
     fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; 
     fmt.fmt.pix.field  = V4L2_FIELD_INTERLACED; 
     xioctl(fd, VIDIOC_S_FMT, &fmt); 
     if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_RGB24) { 
       printf("Libv4l didn't accept RGB24 format. Can't proceed.\\n"); 
       exit(EXIT_FAILURE); 
     } 
     if ((fmt.fmt.pix.width != 640) || (fmt.fmt.pix.height != 480)) 
       printf("Warning: driver is sending image at %dx%d\\n", 
         fmt.fmt.pix.width, fmt.fmt.pix.height); 

     CLEAR(req); 
     req.count = 2; 
     req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
     req.memory = V4L2_MEMORY_MMAP; 
     xioctl(fd, VIDIOC_REQBUFS, &req); 

     buffers = calloc(req.count, sizeof(*buffers)); 
     for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { 
       CLEAR(buf); 

       buf.type  = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
       buf.memory  = V4L2_MEMORY_MMAP; 
       buf.index  = n_buffers; 

       xioctl(fd, VIDIOC_QUERYBUF, &buf); 

       buffers[n_buffers].length = buf.length; 
       buffers[n_buffers].start = v4l2_mmap(NULL, buf.length, 
          PROT_READ | PROT_WRITE, MAP_SHARED, 
          fd, buf.m.offset); 

       if (MAP_FAILED == buffers[n_buffers].start) { 
         perror("mmap"); 
         exit(EXIT_FAILURE); 
       } 
     } 

     for (i = 0; i < n_buffers; ++i) { 
       CLEAR(buf); 
       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
       buf.memory = V4L2_MEMORY_MMAP; 
       buf.index = i; 
       xioctl(fd, VIDIOC_QBUF, &buf); 
     } 
     type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 

     xioctl(fd, VIDIOC_STREAMON, &type); 
     for (i = 0; i < 20; i++) { 
       do { 
         FD_ZERO(&fds); 
         FD_SET(fd, &fds); 

         /* Timeout. */ 
         tv.tv_sec = 2; 
         tv.tv_usec = 0; 

         r = select(fd + 1, &fds, NULL, NULL, &tv); 
       } while ((r == -1 && (errno = EINTR))); 
       if (r == -1) { 
         perror("select"); 
         return errno; 
       } 

       CLEAR(buf); 
       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
       buf.memory = V4L2_MEMORY_MMAP; 
       xioctl(fd, VIDIOC_DQBUF, &buf); 

       sprintf(out_name, "out%03d.ppm", i); 
       fout = fopen(out_name, "w"); 
       if (!fout) { 
         perror("Cannot open image"); 
         exit(EXIT_FAILURE); 
       } 
       fprintf(fout, "P6\n%d %d 255\n", 
         fmt.fmt.pix.width, fmt.fmt.pix.height); 
       fwrite(buffers[buf.index].start, buf.bytesused, 1, fout); 
       fclose(fout); 

       xioctl(fd, VIDIOC_QBUF, &buf); 
     } 

     type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
     xioctl(fd, VIDIOC_STREAMOFF, &type); 
     for (i = 0; i < n_buffers; ++i) 
       v4l2_munmap(buffers[i].start, buffers[i].length); 
     v4l2_close(fd); 

     return 0; 
} 

header chỉ đối tượng phiên bản định hướng để tái sử dụng

Trích từ ví dụ trong tài liệu, nhưng trong một hình thức mà làm nó siêu dễ dàng để tái sử dụng.

common_v4l2.h:

#ifndef COMMON_V4L2_H 
#define COMMON_V4L2_H 

#include <errno.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/ioctl.h> 
#include <sys/mman.h> 
#include <sys/time.h> 
#include <sys/types.h> 

#include <libv4l2.h> 
#include <linux/videodev2.h> 

#define COMMON_V4L2_CLEAR(x) memset(&(x), 0, sizeof(x)) 

typedef struct { 
    void *start; 
    size_t length; 
} CommonV4l2_Buffer; 

typedef struct { 
    int fd; 
    CommonV4l2_Buffer *buffers; 
    struct v4l2_buffer buf; 
    unsigned int n_buffers; 
} CommonV4l2; 

void CommonV4l2_xioctl(int fh, unsigned long int request, void *arg) 
{ 
    int r; 
    do { 
     r = v4l2_ioctl(fh, request, arg); 
    } while (r == -1 && ((errno == EINTR) || (errno == EAGAIN))); 
    if (r == -1) { 
     fprintf(stderr, "error %d, %s\n", errno, strerror(errno)); 
     exit(EXIT_FAILURE); 
    } 
} 

void CommonV4l2_init(CommonV4l2 *this, char *dev_name, unsigned int x_res, unsigned int y_res) { 
    enum v4l2_buf_type type; 
    struct v4l2_format fmt; 
    struct v4l2_requestbuffers req; 
    unsigned int i; 

    this->fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0); 
    if (this->fd < 0) { 
     perror("Cannot open device"); 
     exit(EXIT_FAILURE); 
    } 
    COMMON_V4L2_CLEAR(fmt); 
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
    fmt.fmt.pix.width  = x_res; 
    fmt.fmt.pix.height  = y_res; 
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; 
    fmt.fmt.pix.field  = V4L2_FIELD_INTERLACED; 
    CommonV4l2_xioctl(this->fd, VIDIOC_S_FMT, &fmt); 
    if ((fmt.fmt.pix.width != x_res) || (fmt.fmt.pix.height != y_res)) 
     printf("Warning: driver is sending image at %dx%d\n", 
      fmt.fmt.pix.width, fmt.fmt.pix.height); 
    COMMON_V4L2_CLEAR(req); 
    req.count = 2; 
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
    req.memory = V4L2_MEMORY_MMAP; 
    CommonV4l2_xioctl(this->fd, VIDIOC_REQBUFS, &req); 
    this->buffers = calloc(req.count, sizeof(*this->buffers)); 
    for (this->n_buffers = 0; this->n_buffers < req.count; ++this->n_buffers) { 
     COMMON_V4L2_CLEAR(this->buf); 
     this->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
     this->buf.memory = V4L2_MEMORY_MMAP; 
     this->buf.index = this->n_buffers; 
     CommonV4l2_xioctl(this->fd, VIDIOC_QUERYBUF, &this->buf); 
     this->buffers[this->n_buffers].length = this->buf.length; 
     this->buffers[this->n_buffers].start = v4l2_mmap(NULL, this->buf.length, 
      PROT_READ | PROT_WRITE, MAP_SHARED, this->fd, this->buf.m.offset); 
     if (MAP_FAILED == this->buffers[this->n_buffers].start) { 
      perror("mmap"); 
      exit(EXIT_FAILURE); 
     } 
    } 
    for (i = 0; i < this->n_buffers; ++i) { 
     COMMON_V4L2_CLEAR(this->buf); 
     this->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
     this->buf.memory = V4L2_MEMORY_MMAP; 
     this->buf.index = i; 
     CommonV4l2_xioctl(this->fd, VIDIOC_QBUF, &this->buf); 
    } 
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
    CommonV4l2_xioctl(this->fd, VIDIOC_STREAMON, &type); 
} 

void CommonV4l2_update_image(CommonV4l2 *this) { 
    fd_set fds; 
    int r; 
    struct timeval tv; 

    do { 
     FD_ZERO(&fds); 
     FD_SET(this->fd, &fds); 

     /* Timeout. */ 
     tv.tv_sec = 2; 
     tv.tv_usec = 0; 

     r = select(this->fd + 1, &fds, NULL, NULL, &tv); 
    } while ((r == -1 && (errno == EINTR))); 
    if (r == -1) { 
     perror("select"); 
     exit(EXIT_FAILURE); 
    } 
    COMMON_V4L2_CLEAR(this->buf); 
    this->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
    this->buf.memory = V4L2_MEMORY_MMAP; 
    CommonV4l2_xioctl(this->fd, VIDIOC_DQBUF, &this->buf); 
    CommonV4l2_xioctl(this->fd, VIDIOC_QBUF, &this->buf); 
} 

char * CommonV4l2_get_image(CommonV4l2 *this) { 
    return ((char *)this->buffers[this->buf.index].start); 
} 

size_t CommonV4l2_get_image_size(CommonV4l2 *this) { 
    return this->buffers[this->buf.index].length; 
} 

void CommonV4l2_deinit(CommonV4l2 *this) { 
    unsigned int i; 
    enum v4l2_buf_type type; 

    type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
    CommonV4l2_xioctl(this->fd, VIDIOC_STREAMOFF, &type); 
    for (i = 0; i < this->n_buffers; ++i) 
     v4l2_munmap(this->buffers[i].start, this->buffers[i].length); 
    v4l2_close(this->fd); 
    free(this->buffers); 
} 

#endif 

main.c:

#include <stdio.h> 
#include <stdlib.h> 

#include "common_v4l2.h" 

static void save_ppm(
    unsigned int i, 
    unsigned int x_res, 
    unsigned int y_res, 
    size_t data_lenght, 
    char *data 
) { 
    FILE *fout; 
    char out_name[256]; 

    sprintf(out_name, "out%03d.ppm", i); 
    fout = fopen(out_name, "w"); 
    if (!fout) { 
     perror("error: fopen"); 
     exit(EXIT_FAILURE); 
    } 
    fprintf(fout, "P6\n%d %d 255\n", x_res, y_res); 
    fwrite(data, data_lenght, 1, fout); 
    fclose(fout); 
} 

int main(void) { 
    CommonV4l2 common_v4l2; 
    char *dev_name = "/dev/video0"; 
    struct buffer *buffers; 
    unsigned int 
     i, 
     x_res = 640, 
     y_res = 480 
    ; 

    CommonV4l2_init(&common_v4l2, dev_name, x_res, y_res); 
    for (i = 0; i < 20; i++) { 
     CommonV4l2_update_image(&common_v4l2); 
     save_ppm(
      i, 
      x_res, 
      y_res, 
      CommonV4l2_get_image_size(&common_v4l2), 
      CommonV4l2_get_image(&common_v4l2) 
     ); 
    } 
    CommonV4l2_deinit(&common_v4l2); 
    return EXIT_SUCCESS; 
} 

Upstream: https://github.com/cirosantilli/cpp-cheat/blob/be5d6444bddab93e95949b3388d92007b5ca916f/v4l2/common_v4l2.h

SDL

Quay video là trong roadma của họ p: https://wiki.libsdl.org/Roadmap và tôi đặt cược nó sẽ bọc v4l trên Linux.

Sẽ thật ngọt ngào khi chúng tôi nhận được lớp di động đó, ít bị sưng hơn so với OpenCV.