본문 바로가기

programming/Image Processing

OpenCV 최종과제

OpenCV 최종과제

 

과제1. 라인인식

 

//라인인식 프로그램

#include<highgui.h>
#include<stdio.h>
int main()
{
 IplImage *frame; //원본영상 프레임의 정보를 담고 있는 구조체의 시작주소 저장
 IplImage *dst;  //결과영상 프레임의 정보를 담고 있는 구조체의 시작주소 저장
 int threshold = 180; //임계값 설정
 int i, j, index; //반복문 첨자, 채널의 인덱스 저장할 변수
 int width, height; //프레임의 가로,세로
 int drawx=0, drawy=0; //한 프레임에서 검출된 픽셀의 x좌표의 합,y좌표의 합
 int resultx = 0, resulty = 0; //라인의 무게중심
 int nCount = 0; //검출된 픽셀의 갯수
 int fps = 24; //fps설정, "라인인식.mp3"파일의 fps값
 uchar *data; //픽셀값에 직접 접근하기 위한 uchar형 변수 선언
 uchar *data1;
 //CvSize frame_size;

 

 CvCapture *capture = cvCaptureFromFile("라인인식.mp4");//동영상으로부터 프레임 잡고, IplImage 구조체로 변환후 저장.
 if (capture == NULL)//에러처리
 {
  printf("파일을 찾을 수 없습니다\n"); //에러메세지 출력
  return 1; //비정상 종료
 }

 

 //frame_size = cvSize((int)cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH), (int)cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT));
 //CvVideoWriter* videoWriter = cvCreateVideoWriter("result.avi", -1, 30.0, frame_size, 1);
 //if (!videoWriter)
 // return 0;


 
 while (1) //비디오 영상이므로 무한루프
 {
  nCount = 0;//0으로 초기화-->에러처리
  drawx = 0;
  drawy = 0;

 

  frame = cvQueryFrame(capture);//동영상 파일로부터 정지영상 잡아서 변환후 시작주소 frame에 저장

 

 if (!dst) dst = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 3);//최초 1번만 실행하도록, dst에 할당된게 없을때, 초기값이 NULL일때

  data = (uchar *)frame->imageData; //원본영상 프레임의 픽셀값에 직접 접근.
  data1 = (uchar *)dst->imageData; //결과영상 프레임의 픽셀값에 직접 접근.
  width = frame->width; //가로 저장

  height = frame->height; //세로 저장

 

 for (i = 0; i < height; i++) { //행
   for (j = 0; j < width; j++) {  //열
    index = (i*width + j)*frame->nChannels;  //컬러 R,G,B채널의 인덱스 값

    if (data[index+2] > threshold&& //라인 색에 해당하는 픽셀값 검출범위
     data[index + 1] > threshold &&
     data[index + 0] > threshold)
    {
     data1[index + 2] = 255;  //R
     data1[index + 1] = 0;  //G
     data1[index + 0] = 0;  //B

     nCount++; //검출된 픽셀값 카운트
     drawx += j; //검출된 픽셀의 x좌표의 합
     drawy += i; //검출된 픽셀의 y좌표의 합

    }
    else { //검출되지 않은 픽셀값에 원본영상 픽셀값 대입
     data1[index + 2] = data[index + 2];
     data1[index + 1] = data[index + 1];
     data1[index + 0] = data[index + 0];
    }
   }
  }
  if (nCount != 0) //검출된 픽셀갯수가 1이상일때 실행
  {
   resultx = drawx / nCount; //무게중심 x좌표
   resulty = drawy / nCount; //무게중심 y좌표

   printf("(%d,%d)\n", resultx, resulty); //무게중심 좌표 명령창에 출력
   cvCircle(dst, cvPoint(resultx, resulty), 10, CV_RGB(0, 0, 255), 3, 8, 0); //무게중심 좌표 위치에 파란색 원 표시

  }
  else  //검출된 픽셀갯수 0일때-->0/0 연산 방지 에러처리, 위코드 실행할 필요없음
   printf("해당 픽셀이 없습니다.\n"); //에러메세지 출력


  cvNamedWindow("Original", CV_WINDOW_AUTOSIZE); //원본영상 출력할 윈도우 생성
  cvNamedWindow("Result", CV_WINDOW_AUTOSIZE); //결과영상 출력할 윈도우 생성

 

  cvShowImage("Original", frame); //원본영상 출력
  cvShowImage("Result", dst); //결과영상 출력

 

 if (cvWaitKey(41) >= 0)  break; // 프레임 동기 1000/24 =41.6666...7
 }

 

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

 

 

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

 

 

 

 

 

과제2. 숫자인식

 

 

1)함수 사용

 

//0~9 템플릿 매칭 여러번 반복하여 제일 비슷한 값 유사도 판단.
//값으로 x, 반복하여 매칭.

 

[mylib.h]파일

 

#ifndef _MYLIB_H_
#define _MYLIB_H_
#include<cv.h>
#include<highgui.h>
#include<stdio.h>
#define SIZE 25
typedef struct {
 int num; //인식한 숫자
 int x; //result에서 제일 작은 값의 x좌표, 매칭한 템플릿의 0,0 x 좌표
 int y; //y좌표
 int draw_x; //매칭된 템플릿의 무게중심 x좌표
 int draw_y; //y 좌표
 int index; //IplImage 구조체 타입의 해당 인덱스값
} Res;
int check_dup(CvPoint left_top, Res *pr, int cnt);
void sort(Res *res_num);
#endif

 

[main.c] 파일

#include"mylib.h"
int main()
{
 CvPoint left_top; //매칭된 템플릿의 왼쪽 상단값,(0,0)의 I에서 좌표를 저장하는 변수
 IplImage *image = NULL; // 원본영상
 IplImage *template[10] = { NULL, }; // 템플릿영상
 IplImage* result[10]; // 결과를 저장할 이미지
 FILE *ofp; //파일 출력을 위한 포인터변수 선언
 Res res_num[25] = { 0, }; //매칭된 템플릿의 정보를 저장할 구조체 배열 변수

 int width, height; //image의 가로,세로 저장할 변수
 int twidth, theight;//template의 가로,세로 저장할 변수
 int rwidth, rheight;//result의 가로,세로 저장할 변수
 float *idata; //I의 픽셀값에 직접 접근하기 위한 변수
 uchar *tdata; //T
 float *rdata; //R
 double min, max; //매칭결과 최대,최소값 저장할 변수
 int i, findnum, n; //반복문 첨자 변수
 int cnt = 0; //구조체 배열변수의 인덱스
 int index_dup = 0; //숫자인식 중복검사의 결과값을 저장할 변수


 image = cvLoadImage("숫자인식.jpg", 0);//원본 이미지를 로드. 1채널로 로드,흑백영상
 if (image == NULL)  //에러처리
 {
  printf("파일을 찾지못했습니다\n");//에러메세지 출력
  return 1; //비정상적인 종료
 }

 template[0] = cvLoadImage("0.jpg", 0); //template 이미지(0~9) 흑백채널로 로드
 template[1] = cvLoadImage("1.jpg", 0);
 template[2] = cvLoadImage("2.jpg", 0);
 template[3] = cvLoadImage("3.jpg", 0);
 template[4] = cvLoadImage("4.jpg", 0);
 template[5] = cvLoadImage("5.jpg", 0);
 template[6] = cvLoadImage("6.jpg", 0);
 template[7] = cvLoadImage("7.jpg", 0);
 template[8] = cvLoadImage("8.jpg", 0);
 template[9] = cvLoadImage("9.jpg", 0);

 for (i = 0; i<10; i++) //템플릿이미지 로드에 대한 에러 처리
  if (template[i] == NULL)
  {
   printf("파일을 찾지못했습니다\n");
   return 1;
  }

 for (i = 0; i < 10; i++)//0~9까지 매칭 결과 픽셀값 저장할 IplImage형 변수,할당
 {
  result[i] = cvCreateImage(cvSize(image->width - template[i]->width + 1, image->height - template[i]->height + 1), IPL_DEPTH_32F, 1);
  if (result == NULL)//에러처리
  {
   printf("파일을 찾지못했습니다\n");
   return 1;
  }

 }

 ofp = fopen("result.txt", "w"); //출력파일 개방
 if (ofp == NULL) //fopen 함수 에러처리
 {
  printf("출력파일을 열지 못했습니다\n"); //에러메세지 출력
  return 1; //비정상종료 1 반환
 }

 idata = (float*)image->imageData;//image 의 픽셀값 직접 접근하기 위해, 실수형으로 형변환
 height = image->height; //image 멤버변수 height 저장
 width = image->width; //image 멤버변수 width 저장
 
 for (n = 0; n<4; n++) //숫자 최대반복수 4번
  for (findnum = 0; findnum < 10; findnum++)//0~9까지 템플릿 갯수만큼 반복
  {
   {
    theight = template[findnum]->height; //template
    twidth = template[findnum]->width;
    rwidth = result[i]->width; //result
    rheight = result[findnum]->height;

    tdata = (uchar *)template[findnum]->imageData;
    rdata = (float *)result[findnum]->imageData;

    cvMatchTemplate(image, template[findnum], result[findnum], CV_TM_SQDIFF);//image파일에 template을 옮겨가며 비교하여 둘의 차의 제곱값을 result에 저장한다.
    cvMinMaxLoc(result[findnum], &min, &max, &left_top, NULL, NULL); //최솟값 찾는다.


    if (min < 1000000.0)//검출되면 실행할 코드 최대 여섯자리까지가 정확함. 7자리 이상으로는 한칸옆 템플릿도 매칭됨.
    {
     index_dup = check_dup(left_top, res_num, cnt); //중복 검출되었는지 확인해주는 함수

     if (index_dup<0) //최초 검출된 템플릿만 정보 업데이트
     {
      res_num[cnt].x = left_top.x; //인식된 숫자의 템플릿 (0,0)좌표값 저장
      res_num[cnt].y = left_top.y;

      res_num[cnt].draw_x = left_top.x + template[findnum]->width / 2; //인식된 숫자의 중심좌표 값 저장
      res_num[cnt].draw_y = left_top.y + template[findnum]->height / 2;
      res_num[cnt].num = findnum;  //인식한 숫자 저장
      res_num[cnt].index = res_num[cnt].y*width + res_num[cnt].x; //인식한 숫자의 순서를 판단하기 위한 정보

      cnt++; //템플릿 값을 업데이트 했을때만 구조체 배열변수의 인덱스값 증가

   
      cvRectangle(image, left_top, cvPoint(left_top.x + template[findnum]->width + 1, left_top.y + template[findnum]->height + 1), CV_RGB(255, 0, 0), 1, 8, 0); // 인식된 숫자에 템플릿크기의 사격형을 그린다.
      cvCircle(image, cvPoint(res_num[findnum].draw_x, res_num[findnum].draw_y), 3, CV_RGB(255, 0, 0), 1, 8, 0);//숫자 중심에 원 표시, 단일채널이라 색표시 안됨                               
      printf("min: %lf\n", min);


      //확인코드
      //printf("t:%d, cnt:%d\n", findnum, cnt);
      //printf("min:%lf, max:%lf\n", min, max);
      //printf("%d\n", res_num[findnum].num);
      //printf("(%d, %d)\n", left_top.x, left_top.y); //이거를 그대로 저장 num이랑 같은 인덱스의 멤버변수에 x,y저장

     }

    }

 

   }


  }

 sort(res_num); //인식한 숫자의 인덱스값으로 사진상에서의 순서 판단, 오름차순으로 정렬한다

 

 fprintf(ofp,"중심좌표 인식결과\n");
 for (i = 0; i < SIZE; i++)
 {
  fprintf(ofp, "(%3d,%3d)  %d\n", res_num[i].draw_x, res_num[i].draw_y, res_num[i].num);
 }
 fclose(ofp);

 

 

 printf("인식 결과\n"); //결과값을 명령창에 띄움
 for (i = 0; i < SIZE; i++)
 {
  printf("%d:(%3d,%3d)  findnum:%d, index:%6d\n", i, res_num[i].x, res_num[i].y, res_num[i].num, res_num[i].index);
 }

 

 

 cvNamedWindow("Image", CV_WINDOW_AUTOSIZE); //이미지 띄우기 위한 윈도우 생성

 cvNamedWindow("Result", CV_WINDOW_AUTOSIZE); //이미지 띄우기 위한 윈도우 생성


 cvShowImage("Image", image); //윈도우 창에 image 출력
 cvShowImage("Result", result[1]); //윈도우 창에 image 출력

 

 cvWaitKey(0); //키입력까지 무한대기

 

 

 // 할당된 메모리 공간 반환
 cvReleaseImage(&image);
 for (i = 0; i < 10; i++)
 {
  cvReleaseImage(&template[i]);
  cvReleaseImage(&result[i]);
 }

 // 모든 윈도우 제거
 cvDestroyAllWindows();
 return 0;   //프로그램 종료

}

 

[mylib.c]파일

#include"mylib.h"
int check_dup(CvPoint left_top, Res *pr, int cnt) //인식된 숫자에 대해 중복검사 하는 함수
{
 int i;


 for (i = 0; i < cnt; i++)
  if (left_top.x == pr[i].x&&left_top.y == pr[i].y) //x,y좌표 값을 확인하여 중복판단
   return i;
 

return -1; //중복x 경우 -1반환
}
void sort(Res *res_num) //사진상의 순서대로 구조체배열변수 정보 정렬하는 함수
{
 int i, step;
 Res temp;

 

 for (step = 0; step < SIZE - 1; step++) //인식한 숫자 0~9 순서대로 저장되어있는 구조체 배열변수 -->사진상 순서대로 재배열


  for (i = 0; i < SIZE - 1 - step; i++) //버블정렬 알고리즘
   if ((res_num[i].index > res_num[i + 1].index)) //인덱스 크기순으로 정렬,오름차순
   {
    temp = res_num[i];     //swap
    res_num[i] = res_num[i + 1];
    res_num[i + 1] = temp;
   }

}

 

 

 

 

 

 

 

2)함수 이용x

 

[mylib.h]파일


#define _MYLIB_H_
#include<stdio.h>
#include<cv.h>
#include<highgui.h>
#define SIZE 25 //사진 상 숫자 갯수
#define ROW 0
#define COLUMN 1
typedef struct
{
 CvPoint left_top; //최소값 저장되어있는 지점
 CvPoint drawp; //중심좌표를 저장할 변수
 int num; //인식한 숫자를 저장할 변수
 int line; //row 라인 값을 저장할 변수
} Res;
void sort(Res *res, int val); //사진상의 순서대로 구조체배열변수 정보 정렬하는 함수
void arrange_line(Res *res); //같은 라인 정리
//void on_mouseEvent(int event, int x, int y, int flags, void *param); //x,y좌표값
#endif

 

 

[main.c]파일

 

//cvMatchTemplate 함수 직접구현, 숫자인식 프로그램
#include"mylib.h"
int main()
{
 FILE *ofp; //파일 출력을 위한 포인터변수 선언
 Res res[25] = { 0, }; //인식결과 정보 저장할 구조체 배열변수
 IplImage *image;  //원본 이미지
 IplImage *templ[10]; //템플릿 이미지 0~9
 IplImage *result[10]; //결과 픽셀값 저장할 IplImage 형 배열변수
 uchar *data1; //image의 픽셀값에 직접접근하기 위해
 uchar *data2; //templ[findnum]의 픽셀값에 직접접근하기 위해
 float *data3; //result[findnum]의 픽셀값에 직접접근하기 위해
 int i, j;   //반복문 첨자,i:세로,j:가로
 int s, t;   //반복문 첨자 s:templ[findnum]의 세로,t:templ[findnum]의 가로
 int height, width;  //image의 가로, 세로 저장할 변수
 int height_t, width_t; //templ[findnum]의 가로, 세로 저장할 변수
 int width_r, height_r; //result[findnum]의 가로,세로 저장할 변수

 int rdx, idx, tdx; //템플릿 매칭하기 위한 result[findnum], image, templ[findnum]의 인덱스
 float diff = 0.0; //같은 지점의 픽셀값의 차.
 float sum_sqdiff = 0.0; //diff의 값을 제곱하여 한 템플릿영역의 값을 누적하여 합한 값
 int findnum; //0~9까지 찾을 템플릿의 인덱스
 int n, cnt = 0; //반복문 첨자

 

 

 image = cvLoadImage("숫자인식.jpg", 0);  //원본 이미지 로드
 if (image == NULL) //에러처리
 {
  printf("파일을 찾지 못했습니다...\n"); //에러메세지
  return 1;//비정상 종료
 }

 

 templ[0] = cvLoadImage("00.jpg", 0); //0~9까지 템플릿 영상 로드, 흑백채널로
 templ[1] = cvLoadImage("01.jpg", 0);
 templ[2] = cvLoadImage("02.jpg", 0);
 templ[3] = cvLoadImage("03.jpg", 0);
 templ[4] = cvLoadImage("04.jpg", 0);//
 templ[5] = cvLoadImage("05.jpg", 0);
 templ[6] = cvLoadImage("6.jpg", 0); //
 templ[7] = cvLoadImage("7.jpg", 0);
 templ[8] = cvLoadImage("08.jpg", 0);
 templ[9] = cvLoadImage("09.jpg", 0);

 for (n = 0; n < 10; n++) //템플릿 이미지 로드에 대한 에러처리
 {
  if (templ[n] == NULL) //NULL반환하면 에러
  {
   printf("파일을 찾지 못했습니다...\n"); //에러메세지 출력
   return 1; //비정상 종료
  }

 }

 for (n= 0; n < 10; n++) //결과 픽셀값 저장할 IplImage 구조체 배열변수 생성, 32비트 실수형, 흑백채널
 {
  result[n] = cvCreateImage(cvSize(image->width - templ[n]->width + 1, image->height - templ[n]->height + 1), IPL_DEPTH_32F, 1);//아직 픽셀값 없음, 흑백영상
  if (result[n] == NULL) //에러처리
  {
   printf("파일을 찾지 못했습니다...\n");//에러메세지 출력
   return 1; //비정상 종료
  }

 }

 //I
 data1 = (uchar *)image->imageData; //픽셀값 직접접근
 height = image->height;    //세로값 저장
 width = image->width;    //가로값 저장
 

 //0~9
 for (findnum = 0; findnum < 10; findnum++)  //템플릿 갯수 0~9 찾아야 하므로 10번 반복 0->1->2->...->9까지 찾는다.
 {

  //cvMatchTemplate() 함수 구현.
  
  //T
  data2 = (uchar *)templ[findnum]->imageData;  //0~9 템플릿 픽셀값 직접 접근하기 위해서
  height_t = templ[findnum]->height;    //세로 길이 저장
  width_t = templ[findnum]->width;    //가로 길이 저장


  //R
  data3 = (float *)result[findnum]->imageData; //result의 픽셀값 직접 접근하기 위해, 인식지정범위 값 찾기
  height_r = result[findnum]->height;    //result의 세로 길이 저장
  width_r = result[findnum]->width;    //가로 길이 저장


  //I 반복문
  for (i = 0; i < (height - height_t + 1); i++) { //행
   for (j = 0; j < (width - width_t + 1); j++) //렬
   {
    sum_sqdiff = 0.0;   //한템플릿의 결과값 초기화
    rdx = i * width_r + j;  //R(x,y) 좌표

    //T 반복문
    //한 템플릿 검사하여 값을 I 시작위치와 같은지점 R에 넣어주기
    for (s = 0; s < height_t; s++)  //행
     for (t = 0; t < width_t; t++)//렬
     {
      diff = 0.0;//한 픽셀마다 처리

      //I(x+x',y+y'), T(x',y')
      idx = (s + i)*width + (t + j); //I, 템플릿 위치와 같이 움직이도록
      tdx = s * width_t + t;   //T

      //같은 위치의 픽셀값의 차, 차의 제곱, 한템플릿의 차의 제곱 누적
      diff = (float)data2[tdx] - data1[idx]; //한픽셀마다 처리
      sum_sqdiff += (float)diff * diff;  //한픽셀마다 처리

      
      //printf("idx:%5d(%3d,%3d),   tdx: %5d(%3d,%3d),  rdx:%5d(%3d,%3d)\n", idx, i + t, j + s, tdx, t, s, rdx, i, j);

     }
    data3[i*width_r + j] = sum_sqdiff; //한 템플릿끝나면 결과값 업데이트, 한템플릿마다 처리.
   }

  }

  //R
  for (i = 0; i<height_r; i++)  //유사도 값에서 임계값지정(605147), 범위 내에 값이면 인식.
   for (j = 0; j < width_r; j++)
   {
    rdx = i * width_r + j;  //유사도 값 확인할 인덱스
    if (data3[rdx] <= 605147) //인식값 판단 조건문
    {
     res[cnt].num = findnum;     //인식한 숫자 저장.
     res[cnt].left_top = cvPoint(j, i);  //Rectangle pt1 좌표 저장
     res[cnt].drawp = cvPoint(res[cnt].left_top.x + templ[findnum]->width / 2, res[cnt].left_top.y + templ[findnum]->height / 2); //중심좌표 저장.
     cvRectangle(image,cvPoint(j,i),cvPoint( j + templ[findnum]->width + 1, i + templ[findnum]->height + 1), CV_RGB(0, 0, 0), 1, 8, 0); //인식한 템플릿 영역에 사각형 그림
     cvCircle(image, cvPoint(res[cnt].drawp.x,res[cnt].drawp.y ), 3, CV_RGB(255, 0, 0), 1, 8, 0);//숫자 중심에 원 표시, 단일채널이라 색표시 안됨                    

     printf("%f, %d,(%d,%d), num:%d\n", data3[i*width_r + j], rdx, res[cnt].left_top.x, res[cnt].left_top.y, res[cnt].num); //숫자 인식과정 확인
     //printf("(%d,%d), (%d,%d)\n", j, i, res[cnt].left_top.x, res[cnt].left_top.y);

     cnt++; //순서대로 저장되도록 인덱스값 증가
    }

   }

 

 }

 arrange_line(res);   // 몇번째 줄인지 판단,값 저장하는 함수.
 
 //사진 상의 순서대로 res의 데이터 정렬.
 sort(res,ROW);
 sort(res, COLUMN);

 


 //파일 입출력

 ofp = fopen("result.txt", "w"); //출력파일 개방
 if (ofp == NULL) //fopen 함수 에러처리
 {
  printf("출력파일을 열지 못했습니다\n"); //에러메세지 출력
  return 1; //비정상종료 1 반환
 }

 fprintf(ofp, "중심좌표 인식결과\n");//result.txt파일에 출력
 for (i = 0; i < SIZE; i++)
 {
  fprintf(ofp, "(%3d,%3d)  %d\n", res[i].drawp.x, res[i].drawp.y, res[i].num);
 }
 fclose(ofp);

 printf("\n\n#인식 결과\n"); //결과값을 명령창에 띄움
 for (i = 0; i < SIZE; i++)
 {
  printf("%d:(%3d,%3d)  findnum:%d, line:%d\n", i, res[i].left_top.x, res[i].left_top.y, res[i].num,res[i].line);
 }


 cvNamedWindow("Image", CV_WINDOW_AUTOSIZE); //image 출력할 윈도우 생성

 cvShowImage("Image", image);    //image 출력.
 cvWaitKey(0); //키입력할 때까지 대기.

 cvRelease(&image); //cvLoadImage 함수에 의해 image에 할당된 메모리 반환

 for (n = 0; n < 10; n++) //생성,로드된 영상이 여러개 이므로, 10개(0~9)
 {
  cvRelease(&templ[n]);  //cvLoadImage 함수에 의해 IplImage형 배열변수 templ에 할당된 메모리 반환.
  cvRelease(&result[n]);  //cvCreateImage 함수에 의해 IplImage형 배열변수 result에 할당된 메모리 반환.
 }

 cvDestroyWindow("Image"); //cvNamedWindow 함수에 의해 생성된 윈도우 파괴

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

 

 

 

[mylib.c]파일

 

#include "mylib.h"
void sort(Res *res, int val) //순서대로 구조체배열변수 오름차순으로 정렬하는 함수
{
 int i, step; //반복문 첨자
 Res temp;  //swap하기 위해 원본값 임시 저장 해놓을 구조체 변수
 int cmpval1, cmpval2; //정렬에 필요한 비교값


 for (step = 0; step < SIZE - 1; step++) //인식한 숫자 0~9 순서대로 저장되어있는 구조체 배열변수 -->사진상 순서대로 재배열
  for (i = 0; i < SIZE - 1 - step; i++) //버블정렬
  {
   switch (val)  //두번째 매개변수 값에 의해 정렬할 값 설정.
   {
   case ROW:        //lin값 비교하여 Res형 구조체 배열변수 정렬
    cmpval1 = res[i].line; //비교할 값(line번째 줄) 저장
    cmpval2 = res[i + 1].line;
    if (cmpval1 > cmpval2) //오름차순으로 정렬
    {
     temp = res[i];     //swap
     res[i] = res[i + 1];
     res[i + 1] = temp;
    }
    break;
   case COLUMN:
    cmpval1 = res[i].left_top.x; //x좌표 값으로 비교
    cmpval2 = res[i + 1].left_top.x;

    //y좌표가 같은 경우-->temp의 width 크기가 계속 달라지므로 경우나눠 처리할 필요있음
    if (res[i].line == res[i + 1].line) //라인이 같은 경우에 대해서만 처리
     if (cmpval1 > cmpval2) //오름차순으로 정렬
     {
      temp = res[i];     //swap
      res[i] = res[i + 1];
      res[i + 1] = temp;

     }
    break;
   }
  }
}
void arrange_line(Res *res) //같은 라인 정리
{

 int i, yval; //반복문 첨자,y축 값 저장할 변수 선언

 for (i = 0; i < SIZE; i++) //총 25개 숫자 검사
 {
  yval = res[i].left_top.y; //y좌표 값으로 n번째 줄에 있는 숫자인지 범위지정하여 판단.

  if (yval >= 35 && yval <= 65) res[i].line = 1;   //값 저장, 1~5번째 줄.
  else if (yval >= 195 && yval <= 225) res[i].line = 2;
  else if (yval >= 355 && yval <= 385) res[i].line = 3;
  else if (yval >= 515 && yval <= 545) res[i].line = 4;
  else if (yval >= 675 && yval <= 705) res[i].line = 5;

 }
}

 

 

 

과제3. 차선인식

 

//차선인식 프로그램
#include<highgui.h>
#include<stdio.h>
int main()
{
 IplImage *frame; //원본영상 프레임의 정보를 담고 있는 구조체의 시작주소 저장
 IplImage *dst;  //결과영상 프레임의 정보를 담고 있는 구조체의 시작주소 저장
 int threshold = 200; //임계값 설정
 int i, j, index; //반복문 첨자, 채널의 인덱스 저장할 변수
 int width, height; //프레임의 가로,세로
 int drawX = 0, drawY = 0; //한 프레임에서 검출된 픽셀의 x좌표의 합,y좌표의 합
 int resultX = 0, resultY = 0; //라인의 무게중심
 int nCount = 0; //검출된 픽셀의 갯수
 int fps = 24; //fps설정, "라인인식.mp3"파일의 fps값
 uchar *data; //픽셀값에 직접 접근하기 위한 uchar형 변수 선언
 uchar *data1;

 

 CvCapture *capture = cvCaptureFromFile("차선인식.mp4");//동영상으로부터 프레임 잡고, IplImage 구조체로 변환후 저장.
 if (capture == NULL)//에러처리
 {
  printf("파일을 찾을 수 없습니다\n"); //에러메세지 출력
  return 1; //비정상 종료
 }

 

 cvNamedWindow("Original", CV_WINDOW_AUTOSIZE); //원본영상 출력할 윈도우 생성
 cvNamedWindow("Result", CV_WINDOW_AUTOSIZE); //결과영상 출력할 윈도우 생성


 while (1)
 {
  nCount = 0;//0으로 초기화-->에러처리
  drawX = 0;
  drawY = 0;

  frame = cvQueryFrame(capture);//동영상 파일로부터 정지영상 잡아서 변환후 시작주소 frame에 저장
  if (frame == NULL) break; //에러처리


  if (!dst) dst = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 3);//최초 1번만 실행하도록, dst에 할당된게 없을때, 초기값이 NULL일때

  data = (uchar *)frame->imageData; //원본영상 프레임의 픽셀값에 직접 접근
  data1 = (uchar *)dst->imageData; //결과영상 프레임의 픽셀값에 직접 접근
  width = frame->width; //가로 저장
  height = frame->height; //세로 저장

  for (i = 0; i < height; i++) { //행
   for (j = 0; j < width; j++) {  //열
    index = (i*width + j)*frame->nChannels;  //컬러 R,G,B채널의 인덱스 값

    if (data[index + 2] > threshold&& //라인 색에 해당하는 픽셀값 검출범위
     data[index + 1] > threshold &&
     data[index + 0] > threshold)
    {
     data1[index + 2] = 255;  //R
     data1[index + 1] = 0;  //G
     data1[index + 0] = 0;  //B

     nCount++; //검출된 픽셀값 카운트
     drawX += j; //검출된 픽셀의 x좌표의 합
     drawY += i; //검출된 픽셀의 y좌표의 합

    }
    else { //검출되지 않은 픽셀값에 원본영상 픽셀값 대입
     data1[index + 2] = data[index + 2];
     data1[index + 1] = data[index + 1];
     data1[index + 0] = data[index + 0];
    }
   }
  }
  if (nCount != 0) //검출된 픽셀갯수가 1이상일때 실행
  {
   resultX = drawX / nCount; //무게중심 x좌표
   resultY = drawY / nCount; //무게중심 y좌표

   printf("(%d,%d)\n", resultX, resultY); //무게중심 좌표 명령창에 출력
   cvCircle(dst, cvPoint(resultX, resultY), 10, CV_RGB(0, 0, 255), 3, 8, 0); //무게중심 좌표 위치에 파란색 원 표시

  }
  else  //검출된 픽셀갯수 0일때-->0/0 연산 방지 에러처리, 위코드 실행할 필요없음
   printf("해당 픽셀이 없습니다.\n"); //에러메세지 출력
  cvShowImage("Original", frame); //원본영상 출력
  cvShowImage("Result", dst); //결과영상 출력

  if (cvWaitKey(41) >= 0)  break; // 프레임 동기 1000/24 =41.6666...7
 }
 cvReleaseCapture(&capture);//동적할당 메모리 해제
 cvReleaseImage(&dst);//동적할당 메모리 해제
 cvDestroyWindow("Original");//동적할당 메모리 해제
 cvDestroyWindow("Result");//동적할당 메모리 해제

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

 

 

 

 

 

 

 

과제4. 움직이는 물체 추적

 

//물체추적 프로그램
#include<stdio.h>
#include<highgui.h>
#include<cv.h>
int main()
{
 IplImage* frame;  //영상을 IplImage형으로 출력해야 함.
 IplImage* gray;  //흑백으로 담을 변수, IplImage 자동 초기화해줌. NULL로
 IplImage* dst=NULL; //cvcanny함수 적용할 변수.
 CvCapture* capture;
 CvThreshType threshold_type = CV_THRESH_BINARY;

 CvMemStorage *storage; //시퀀스가 실질적으로 저장될 곳.
 CvSeq* circles = 0;  //cvHoughCircles함수가 반환한 값 저장할 포인터변수
 float *p;
 int k;

 capture = cvCaptureFromFile("red.mp4"); //동영상 파일 로드
 if (capture == NULL)//에러처리
 {
  printf("파일을 찾을 수 없습니다\n"); //에러메세지 출력
  return 1; //비정상 종료
 }


 cvNamedWindow("Video", CV_WINDOW_AUTOSIZE); //윈도우 생성
 //cvNamedWindow("black", CV_WINDOW_AUTOSIZE);
 //cvNamedWindow("edge", CV_WINDOW_AUTOSIZE);

 while (1)
 {
  frame = cvQueryFrame(capture);//동영상 파일로부터 정지영상 잡아서 변환후 시작주소 frame에 저장.

  //printf("%s\n", frame->channelSeq);
          
  cvSmooth(frame, frame, CV_GAUSSIAN, 5, 5,0,0);//5X5 가우시안 커널,Gausian blur 필터 적용->영상에서 잡음제거, cvCanny()함수에서 해주지 않으므로

  gray = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 1); //원본 컬러 이미지의 크기만큼 1채널 영상 생성, 픽셀값 빈 상태

  cvCvtColor(frame, gray, CV_BGR2GRAY);      // 원본 이미지를 흑백영상으로 바꿔 gray 공간에 copy, 픽셀값 저장

  cvThreshold(gray, gray, 150.0, 255.0, threshold_type); //이진화

  dst = cvCreateImage(cvGetSize(gray), IPL_DEPTH_8U, 1); //edge에 흑백영상 크기만큼 영역 생성 1채널
  cvCanny(gray, dst, 50, 200, 3);      //cvCanny함수는 단일채널이어야 해서 흑백영상 써야함

  storage = cvCreateMemStorage(0); //메모리 블록의 메모리공간을 생성하고 포인터를 반환, 0:64KB의 메모리 블록의 크기를 생성.
  circles = cvHoughCircles(dst, storage, CV_HOUGH_GRADIENT, 1, 100, 200, 25, 30, 50);//MAX(edge->width,edge->height));//Edge에서 원 찾기

  for (k = 0; k<circles->total; k++) //시퀀스 내 포인터 or 객체들의 전체 갯수만큼 반복.
  {
   p = (float*)cvGetSeqElem(circles, k); // 검출된 원을 저장한 시퀀스 circles에서 원의 파라미터를 circle에 저장, 원의 중심, 반지름->circle[0,1,2,]에 저장
             //원소 직접접근.
   cvCircle(frame, cvPoint(cvRound(p[0]), cvRound(p[1])), 3, CV_RGB(0, 255, 0), -1, 8, 0); //중점에 green 원
   cvCircle(frame, cvPoint(cvRound(p[0]), cvRound(p[1])), cvRound(p[2]), CV_RGB(255, 0, 0), 3, 8, 0); //바깥 테두리에 red 원
  }


  cvShowImage("Video", frame); //frame 출력
  //cvShowImage("black", gray);

  if (cvWaitKey(34) >=0)//fps
   break;
 }
 cvReleaseCapture(&capture); //할당된 메모리 공간 반환.
 cvReleaseImage(&gray);
 cvReleaseImage(&dst);

 cvDestroyWindow("Video"); //윈도우 파괴
 //cvDestroyWindow("black");
 //cvDestroyWindow("edge");

 return 0; //프로그램 종료

}