본문 바로가기

programming/Image Processing

OpenCV를 이용한 영상처리::11장~12장 과제

11장 <동영상 처리>  과제

 

과제1. 카메라로부터 들어오는 컬러영상에서 손(hand)영역을 검출하여 검정색으로 표시하고 손영역의 무게중심을 구하여 영상의 우측상단에 출력하고 중심점에 빨간색원을 그려주는 프로그램을 작성하시오. 또한, 명령창에도 중심의 좌표를 실시간으로 출력하라.

 

#include<cv.h>
#include <highgui.h>
#include<stdio.h>
//void on_mouseEvent(int event, int x, int y, int flags, void* param);
int main()
{
 IplImage *frame; // 원본영상
 IplImage *dst;  // 색 검출 영상

 int width, height; // 창의 가로, 세로
 int i, j, index;//반복문 첨자


 unsigned char R, G, B;//각 채널에 해당하는 인덱스
 int nCount; //피부색으로 검출된 픽셀의 갯수
 int DrawX, DrawY; //피부색으로 검출된 픽셀의 각 좌표 합 x,y
 CvFont  font;//폰트 정보를 담고 있는 구조체 변수선언.
 char str[20];//중심좌표를 문자열로 저장할 char형 배열변수 선언

 CvCapture* capture = cvCaptureFromCAM(0);  //캠으로부터 동영상 정보 가져와서 시작주소 저장, 동적할당

 int fps = 30;   //fps값 설정

 frame = cvQueryFrame(capture);    //동영상으로부터 프레임 잡고, IplImage구조체로 변환후 저장.


 width = frame->width;   // frame으로부터 width와 height 정보 저장
 height = frame->height;

 cvNamedWindow("Original", CV_WINDOW_AUTOSIZE); //윈도우 생성을 위한 메모리 동적할당
 cvNamedWindow("Hand Tracking", CV_WINDOW_AUTOSIZE);//윈도우 생성을 위한 메모리 동적할당

 

// frame와 같은 크기를 갖는 3채널 영상 생성
 dst = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 3); //크기,채널,깊이 정보 받아서 결과영상을 저장할 메모리 동적 할당

 while (capture) {//정상작동시 (에러x) 무한루프
  nCount = 0;//0으로 초기화-->에러처리
  DrawX = 0;//초기값 0, 매 프레임마다 0으로 초기화시켜서 값이 누적되지 않도록 한다
  DrawY = 0;
  frame = cvQueryFrame(capture); //캠의 동영상으로부터 프레임을 정지영상으로 받아오기(grab,retrieve 함수 합친함수)


  for (i = 0; i < height; i++) { //행
   for (j = 0; j < (frame->widthStep); j +=(frame->nChannels)) { //열 //3채널이므로 3씩 건너뛴다
    index = i * frame->widthStep + j; //채널3개니까 1차원배열 IplImage 구조체 형식 영상에서는 채널수 곱해줌

    R = frame->imageData[index + 2]; // R영역
    G = frame->imageData[index + 1]; // G영역
    B = frame->imageData[index + 0]; // B영역

             // 피부색으로 예상되는 범위 설정-->검정색으로 변경
    if (R > 100 && R < 240 &&
     G > 70 && G < 200 &&
     B > 50 && B < 170) {
     dst->imageData[index + 0] = 0; //피부색으로 검출된 픽셀값 검정으로 변경
     dst->imageData[index + 1] = 0;
     dst->imageData[index + 2] = 0;

     nCount ++;//검출된 픽셀갯수 카운트
     DrawX += j/3; //j값을 3채널씩 건너뛰었으므로 좌표값도 3으로 나눠준다
     DrawY += i;
    }

    else {
     // 원본영상 픽셀값 그대로 붙이기
     dst->imageData[index + 0] = frame->imageData[index + 0];
     dst->imageData[index + 1] = frame->imageData[index + 1];
     dst->imageData[index + 2] = frame->imageData[index + 2];
    }
   }

  }

  if (nCount != 0) //검출된 픽셀 갯수가 1이상일때 실행
  {
   DrawX /= nCount; //무게중심 x좌표
   DrawY /= nCount; //무게중심 y좌표


   printf("(%d,%d)\n", DrawX, DrawY);//명령창에 출력

   cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.5, 0.5, 0.0, 1, 8);  //폰트 구조체를 초기화한다
   sprintf(str, "(%d,%d)", DrawX, DrawY);  //숫자를 문자열로 버퍼에 저장함
   cvPutText(dst, str, cvPoint(450, 50), &font, CV_RGB(0, 0, 0)); //버퍼에 저장된 문자열 영상의 무게중심에 출력
   cvCircle(dst, cvPoint(DrawX, DrawY), 10, CV_RGB(0, 0, 255), 1, 8, 0); //무게중심 좌표에 파란색 원그리기

  }

 

 


  else //검출된 픽셀갯수가 0일 경우 에러처리 0/0 연산 방지
   printf("해당 픽셀이 없습니다\n");   //에러메세지 출력
  cvShowImage("Original", frame);//원본영상 프레임 출력
  cvShowImage("Hand Tracking", dst);//결과 영상 프레임 출력
  

  if (cvWaitKey(33) >= 0)  break;//30fps,1000msec
 }

 cvReleaseCapture(&capture);//동적할당 메모리 해제
 cvReleaseImage(&dst);//동적할당 메모리 해제
 cvDestroyWindow("Original");//동적할당 메모리 해제
 cvDestroyWindow("Hand Tracking");//동적할당 메모리 해제

 return 0;   //프로그램 종료
}

 

 

 

 

 

과제2. 카메라를 이용하여 찍은 영상을 화면에 표시하고 동영상으로 저장하시오. 사용자가 키보드를 누를때까지 저장하도록 하라.

 

#include<highgui.h>

int main()
{
 IplImage* image = NULL; //영상 정보를 담을 구조체 변수 선언,초기화
 CvCapture* capture = NULL; //동영상 정보를 담을 구조체 변수 선언, 초기화
 CvVideoWriter* VideoOut = NULL; //비디오 저장함수를 사용하기 위한 자료형 변수선언
 int fps = 30; //fps값 설정

 cvNamedWindow("Camera", CV_WINDOW_AUTOSIZE); //윈도우 생성에 필요한 동적할당
 capture = cvCaptureFromCAM(0); //CAM으로 동영상 불러온다.

 while (1)
 {
  cvGrabFrame(capture);//프레임 잡음
  image = cvRetrieveFrame(capture, 0);//잡은 압축된 프레임을 변환하여 이미지 구조체 변수에 저장
  

if (!VideoOut)  VideoOut = cvCreateVideoWriter("CamSave.avi", -1, fps, cvGetSize(image), 1); //최초한번만 실행,초당프레임 30으로 설정.
  cvShowImage("Camera", image); //프레임 출력
  cvWriteFrame(VideoOut, image); //비디오 파일을 열 프레임을 쓴다. 출력할 때 사용

 

  if (cvWaitKey(10) >= 0) break; //키입력 10msec 무한대기, 입력시 프로그램종료
 }

 

 cvReleaseVideoWriter(&VideoOut); //cvCreateVideoWriter함수에 의해 동적할당된 비디오 writer해제.
 cvReleaseCapture(&capture); //cvRetrieveFrame함수에 의해 할당된 IplImage은 직접해제x,CvCapture해제하여 관련된 메모리 해제.
 cvDestroyWindow("Camera"); //cvNamedWindow에 의해 동적할당된 메모리 해제

 return 0;//프로그램 종료.
}

 

 

 

 

<유용한 함수> 과제

 

과제1. 사진에서 머리카락영역을 검출하여 빨간색으로 표시하고 영역의 무게중심을 구하여 영상에 원을 그리고 영상과 명령창에 무게중심의 좌표를 출력하는 프로그램을 작성하시오. 예제 4,5를 참조하라.

 


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


int main()
{
 IplImage* src_image = NULL; //원본영상의 정보를 담은 구조체의 시작주소를 담을 포인터변수 선언,초기화
 uchar *data; //픽셀값에 직접 접근하기 위한 포인터 변수 선언
 int index, i, j; //반복문 첨자

 

 int nCount; //검출된 픽셀의 갯수
 int DrawX, DrawY; //검출된 픽셀의 x,y좌표 -->누적
 CvFont  font; //폰트 정보를 담는 구조체
 char str[20]; //숫자를 문자열로 저장해둘 버퍼역할 배열변수선언

 nCount = 0; //검출된 픽셀의 갯수 카운트 초기화
 DrawX = 0;//검출된 픽셀의 x,y좌표 초기화
 DrawY = 0;

 

 src_image = cvLoadImage("image.jpg", -1); //파일로부터 영상 원본 그대로 로드

 

cvNamedWindow("Original", CV_WINDOW_AUTOSIZE); //윈도우 생성하기 위한 메모리 동적할당
 cvNamedWindow("Result", CV_WINDOW_AUTOSIZE);

 data = (uchar*)src_image->imageData; //원본영상의 픽셀값 직접접근하기 위해
 cvShowImage("Original", src_image); //원본 이미지 출력

 

 

 for (i = 0; i<src_image->height; i++) //행
  for (j = 0; j<src_image->width; j++)//열
  {
   index = (i * src_image->width + j)*src_image->nChannels; //RGB 색상 인덱스값 저장-->BGR순서
   if (data[index + 2] >30 && data[index + 2] <170 && //r
    data[index + 1] > 10 && data[index + 1] <140 && //g
    data[index + 0] > 10 && data[index + 0] <120) //b
   {
    data[index] = 0;
    data[index + 1] = 0;
    data[index + 2] = 255; //검출된 픽셀은 빨강으로 픽셀값 변경

   

 nCount++; //검출된 픽셀수 카운트
    DrawX +=j; //검출된 픽셀의 X,Y 좌표값 누적 합
    DrawY +=i;
   }
  }

 

 if (nCount != 0) // 0/0 에러방지 코드
 {
  DrawX /= nCount; //무게중심 좌표값 구함
  DrawY /= nCount;
  printf("(%d,%d)\n", DrawX, DrawY); //무게중심 좌표값 명령창에 출력

  cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.4, 0.4, 0.0, 1, 8); //폰트 구조체 정보 초기화
  sprintf(str, "(%d,%d)", DrawX, DrawY); //str에 출력할 문자열 저장
  cvPutText(src_image, str, cvPoint(200, 50), &font, CV_RGB(0, 0, 0)); //폰트 정보 받아서 문자열 출력
  cvCircle(src_image, cvPoint(DrawX, DrawY), 10, CV_RGB(0, 0, 0), 1, 8, 0); //무게중심 좌표에 검정색 원 그린다
 }


 else  // 0/0  에러메세지 출력
  printf("해당 픽셀을 찾을 수 없습니다\n");

 

 cvShowImage("Result", src_image);  //검출된 이미지 출력

 cvWaitKey(0); //키보드입력 무한대기

 cvDestroyWindow("Original"); //동적할당된 메모리 반환
 cvDestroyWindow("Result");

 cvReleaseImage(&src_image);

 

 return 0; //프로그램 종료
}