2008-11-10 2 views

답변

6

가장 좋은 방법은 아마도 : video4linux (V4L)

그것은 사용하기 쉽고, 강력한입니다.

13

우리의 많은 (현재 2.1에, 크로스 플랫폼 컴퓨터 비전 라이브러리) OpenCV를 사용

다음 코드는 카메라의 프레임을 잡고 그레이 스케일로 변환하여 화면에 표시합니다 :

당신이 얻을 무엇
#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

새 링크 http://opencv.org/ – GramThanos

4

v4l2 공식 예

:

  • ./v4l2grab : 파일 outNNN.ppm
  • ./v4l2gl에 몇 스냅 샷을 캡처 : 쇼 비디오는 OpenGL 텍스처를 사용하여 창에 살고있는 원시 X11 윈도우 (플러스 GLUT의 gluLookAt 좋은 측정을위한) (즉시 렌더링, 헤이!).

우분투 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 

그냥, 그들을 밖으로 복사 상대가 "" 절대 <> 포함하기 위해선, 힘내 트리의 외부에 그 예를 사용하고 config.h을 제거하는 것이 용이하다 . 문서

4.9.0이 https://linuxtv.org/downloads/v4l-dvb-apis-new/uapi/v4l/v4l2grab-example.html에서 ./v4l2grab의 최소 버전으로 보이는이 포함 된 문서에서 https://github.com/cirosantilli/cpp-cheat/tree/09fe73d248f7da2e9c9f3eff2520a143c259f4a6/v4l2

최소 예 : 나는 당신을 위해 그 일을했습니다. 필자는 패치를 최소한으로 할 필 요가 있었고 패치를 http://www.spinics.net/lists/linux-media/ (Linux 커널 트리에서 처음으로 살고 있습니다.)으로 보내 었습니다.

는 사용법 :

gcc v4l2grab.c -lv4l2 
./a.out 

패치 된 코드 :

/* 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; 
} 

헤더는 형태로 만드는 문서의 예에서 추출 재사용

에 대한 지향 버전을 객체 있지만, 재사용하기 쉽습니다.

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; 
} 

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

SDL은

비디오 캡처는 roadma에 p : https://wiki.libsdl.org/Roadmap 그리고 리눅스에서 v4l을 감쌀 것입니다.

우리는 OpenCV보다 덜 팽창하면서 이식성 계층을 얻을 때 달콤 할 것입니다.