영상 캡쳐하는 프로그래밍 질문입니다

curajc의 이미지

로지텍 퀵캠으로 영상처리를 하고 있는 학생입니다.
이미지 캡쳐하고 window하나 만들어서 보여주는 프로그램인데

return_value = ioctl(fd, VIDIOCSPICT, &pic);
if ( return_value < 0 )
{
fprintf(stderr,"Failed to set the image properties\n");
exit(1);
}

이 부분에서 자꾸 오류가 나면서 창이 그냥 닫힙니다. ㅠㅠ
(VIDIOCGPICT로 미리 pic도 얻었습니다)
나름대로 요것조것 해본결과 palette부분 설정이 바뀌지 않는것 같은데...

혹시해서 원래 설정대로 palette =VIDEO_PALETTE_YUV420P
로 하면 이 오류는 나지 않는데, 대신에
XIO: fatal IO error 14(Bad address) on X server ":0.0"
after 13 requests (6 known processed) with 0 events rremaining.
이라는 메시지가 나면서 창이 그냥 닫힙니다.
설마 x-window에서는 yuv포맷으론 display가 안되나요??

영상 처리 첨이라 힘드네요ㅠㅠ 도와주세요~~~

소스 첨부 합니다-------------------------

#include <X11/Xlib.h>
#include <unistd.h>
#include <stdio.h>
#include <linux/videodev.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

char *v4l_init();
char *v4l_capture();
int fd;
unsigned char *map;
struct video_mmap v_map;
struct video_mbuf m_buf;

int main( int argc, char * argv[] )
{
  Display *display;
  Window window;
  GC gc;
  Visual *visual;
  XImage *display_image;
  unsigned char *buffer;
  int window_width,window_height;

  display = XOpenDisplay("localhost:0.0");

/* window size 768*480 */
  window_width = 768; window_height = 480;
  window = XCreateSimpleWindow(display, RootWindow(display,0),
			       50, 50, window_width, window_height, 3,
			       BlackPixel(display,0), WhitePixel(display,0));
  gc = XCreateGC(display, window, 0L, (XGCValues *) NULL);

  XMapWindow(display, window);
  XFlush(display);

  buffer = v4l_init(); /* video capture device initialize */

  while ( 1 )
  {
    buffer = v4l_capture(); /* video capture */

/*
 * image create - depth = default(window depth)
 *                size = 768 * 480
 *                RGB color 32bit (blue, green, red, alpha)
 */
    display_image = XCreateImage(display, DefaultVisual(display, 0), 
				 DefaultDepth(display, 0), ZPixmap, 0,
				 buffer, 768, 480, 32, 0);
    display_image->byte_order = LSBFirst;
/* display image */
    XPutImage(display, window, gc, display_image, 0, 0, 0, 0, 768, 480);
  }

  return 0;
  
}



char *v4l_init()
{
  int width, height;
  int depth, palette;
  int return_value;
  char *device;

  struct video_capability cap;
  struct video_channel chan;
  struct video_window win;
  struct video_picture pic;

/* capture device is video0 */
  device = "/dev/video0";

  if ( (fd = open(device, O_RDONLY)) < 0 )
  {
    fprintf(stderr, "video device %s could not be opened\n", device);
    exit(1);
  }

  return_value = ioctl(fd , VIDIOCGCAP, &cap);
  if ( return_value < 0 )
  {
    fprintf(stderr, "ioctl on VIDIOCGCAP failled\n");
    exit(1);
  }

/* capture channel is 0 */
  chan.channel = 0;
 // chan.flags = 0;
  chan.type = VIDEO_TYPE_CAMERA;
  chan.norm = VIDEO_MODE_NTSC;
  return_value = ioctl(fd, VIDIOCSCHAN, &chan);
  if ( return_value < 0 )
  {
    fprintf(stderr, "ioctl on VIDIOCSCHAN failed\n");
    exit(1);
  }

  return_value = ioctl(fd, VIDIOCGWIN, &win);

/* capture image depth is 32 and palette is rgb32 */
  depth = 32;
  palette = VIDEO_PALETTE_RGB32;

  width = win.width = cap.maxwidth;
  height = win.height = cap.maxheight;
  win.x = win.y = win.chromakey = win.flags = 0;
  return_value = ioctl(fd, VIDIOCSWIN, &win);
  if ( return_value < 0 )
  {
    fprintf(stderr,"ioctl on VIDIOCSWIN failed\n");
    exit(1);
  }

  return_value = ioctl(fd, VIDIOCGPICT, &pic);
  if ( return_value < 0 )
  { 
    fprintf(stderr,"Failed to get the image properties\n");
    exit(1);
  }

  printf("depth = %d\n", pic.depth);
 if(pic.palette == VIDEO_PALETTE_YUV420P)
	  printf("2\n");
//  printf("palette = %d\n", pic.palette);
  
  pic.depth = depth;
  pic.palette = palette;

  return_value = ioctl(fd, VIDIOCSPICT, &pic);
  if ( return_value < 0 )
  {
    fprintf(stderr,"Failed to set the image properties\n");
    exit(1);
  }

  return_value = ioctl(fd, VIDIOCGMBUF, &m_buf);
  if ( return_value < 0 )
  {
    fprintf(stderr, "Failed to get information of capture memory space.\n");
    exit(1);
  }

  map = (char*) mmap(0, m_buf.size, PROT_READ, MAP_SHARED, fd, 0);
  if ( map == MAP_FAILED )
  {
    fprintf(stderr,"Failed to get pointer to memory mapped area.\n");
    exit(1);
  }

  v_map.height = height;
  v_map.width = width;

  v_map.format = palette;

/* 4 frame use */
  v_map.frame = 0;
  return_value = ioctl(fd, VIDIOCMCAPTURE, &v_map);
  v_map.frame = 1;
  return_value = ioctl(fd, VIDIOCMCAPTURE, &v_map);
  v_map.frame = 2;
  return_value = ioctl(fd, VIDIOCMCAPTURE, &v_map);
  v_map.frame = 3;
  return_value = ioctl(fd, VIDIOCMCAPTURE, &v_map);

  return map;
}


char *v4l_capture()
{
/* capture frame with 4 frame buffer */
  ioctl(fd, VIDIOCSYNC, &v_map);
  v_map.frame++;
  if ( v_map.frame == 4 )
    v_map.frame = 0;
  ioctl(fd, VIDIOCMCAPTURE, &v_map);

  return map+m_buf.offsets[v_map.frame];
}
assasasa의 이미지

저도 이번에 프레임그래버로, 캡쳐해서 화면뿌려주는 프로그램을 했었습니다. Qt쓰레드는 캡쳐받는 무한루프로 돌려서, 캡쳐후 GUI로 이미지 주는 방식을 택했습니다.

curajc wrote:

return_value = ioctl(fd, VIDIOCSPICT, &pic);
if ( return_value < 0 )
{
fprintf(stderr,"Failed to set the image properties\n");
exit(1);
}

이 부분에서 자꾸 오류가 나면서 창이 그냥 닫힙니다. ㅠㅠ


받아 올려고 하는 이미지 타입이 적절하지 못하기 때문에,
생기는 현상이라 생각됩니다. 이미지 크기를 말도안되게
크게 해보니, 위와같은 에러가 생기더라고요.

curajc wrote:

혹시해서 원래 설정대로 palette =VIDEO_PALETTE_YUV420P
로 하면 이 오류는 나지 않는데, 대신에
XIO: fatal IO error 14(Bad address) on X server ":0.0"
after 13 requests (6 known processed) with 0 events rremaining.
이라는 메시지가 나면서 창이 그냥 닫힙니다.
설마 x-window에서는 yuv포맷으론 display가 안되나요??

저도 님의 생각에 동의 합니다. yuv 포멧을 바로 Xwindow 에 쓸수 없을거 같습니다. xwindow 에 맞도록 바꾸는 부분을 본 기억이 있습니다. 아니면 캡쳐해서 바로 뿌리지 마시고, 한 장 정도만 캡쳐해서 파일 출력을 해보시는 것도 한가지 방법이 되지 않을까요?
저는 pci 카드에서 받아오게 되어서, 바로 ppm 파일을 사용했었습니다.

님의 가려운 곳을 긁어주지는 못하겠는데, 참고하시라는
생각에 덧 글 달아봅니다. 행운을 빌겠습니다.

"마무리가 반이다" -- woox

curajc의 이미지

어디에 저장이 되는 건가요???

포맷을 바꾸는 것은 찾았는데.....ppm파일을 xwindow에서 보는것은 어찌해야 좋을지 모르겠습니다. ;;;;;;;;;;;;;

익명 사용자의 이미지

저는 YUV 포멧으로 받아서 Xwindow에 쓴것은 아니기 때문에, 그 부분은 논외로 하시고.

ppm 파일 종류가 두(?)가지 일겁니다.
p3, p6 이렇게요.

각 파일을 에디터로 열어보시면, 헤더에

P6
640 480
255    

이렇게 되어있으면 P6 입니다. P3는 당연히 P6 대신 P3가 되어있겠죠. 두 파일의 차이점은 P3는 640,480 크기의 파레트 의 한 점에 대하여 각각 RGB 값으로 표현되어 있습니다. 즉, 아스키 값이죠. 그러나, P6는 바이너리 포멧입니다.

그러면, Sync까지 끝낸 상황이라고 가정하면 ,

P3 포멧으로 PPM 파일을 만들어 내려면,

main(){
FILE *fPic[2];
...
   if((map=(char *)mmap(0, v_buf.size, PROT_READ|PROT_WRITE  , MAP_SHARED, fd, 0))==(char *)-1) {
                printf("map:%p\n",map);
                perror("mmap");
                return -1;
        }
...
fPic[0] = fopen("./p3out1.ppm", "w");
//fPic[1] = fopen("./p6out1.ppm", "w");

...
p_map = map ;
P3_RGBData(p_map , v_mmap.width , v_mmap.height, fPic);
..


}


char*  P3_RGBData(char* map_, int width_, int height_ , FILE *out){
        int i_height = 0 ;
        int i_width  = 0 ;
        int R = 0 , G = 0, B = 0 ;
        char *p_map = map_ ;
        char tmp_         ;
        int n = 0 ;
        long ppm_size = 0;

        fprintf(out,"P3\n%d %d\n255",width_,height_);
        //BGR->RGB
        for(i_height = 0 ; i_height < height_ ; ++i_height){
                for( i_width = 0 ; i_width < width_ ;  ++i_width){
                        if( ( 3*i_width%15) == 0 ){ fprintf(out,"\n"); } //mendatory!

                        R = (int) *(p_map +2 ) < 0 ? 0 : *( p_map+2 )   ;
                        G = (int) *(p_map +1 ) < 0 ? 0 : *( p_map+1 )   ;
                        B = (int) *(p_map )    < 0 ? 0 : *( p_map )     ;

                        if( R > 255){ R = 255 ; }
                        if( G > 255){ G = 255 ; }
                        if( B > 255){ B = 255 ; }

                        fprintf(out,"%d %d %d ",R, G, B);
                        p_map +=3 ;
                }
                fprintf(out,"\n");
        }

        return map_ ;
}

파일을 열어보시면 아스키 값이 저장됩니다. 메모리에는 BGR 형태로 저장되어있으므로, 파일 출력시에 RGB로바꾸어서 저장시킵니다.

그리고 P6의 경우의 함수는 메모리의 내용을 그대로 쓰면됩니다.

char*  P6_RGBData(char* map_, int width_, int height_, FILE *out ){

        /*
        "P6\n%d %d\n255\n"
        BGR format
        faster than P3_RGBData
        */

        fprintf(out,"P6\n%d %d\n255\n", width_,height_);
        //size_t fwrite( const void *ptr, size_t size, size_t nmemb, FILE *stream);
        fwrite(map_, height_, 3*(width_),out);

}

파일이 생성되면
xview p3out.ppm or xview p6out.ppm 혹은 gqview로 보시면, 됩니다.

이상은 제 경험이고요. USB카메라는 캡처시 팰레트를 YUV 이던데, 이 부분은 다른 경험있으신 분들이 답글 달아 주지 않겠나 합니다.

curajc의 이미지

아직 화면으로 보진 못했지만ㅠㅠ

알려주신 방법대로 해보았는데, xview는 ppm파일을 지원하지 않

더라구여;;;

어쨌든 ppm으로 변환하여 저장되는 것까진 확인했습니다~~
감사합니다~~*

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.