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; //프로그램 종료
}
'programming > Image Processing' 카테고리의 다른 글
OpenCV로 배우는 영상처리 및 응용:: 1장 (0) | 2020.06.25 |
---|---|
opencv 4.3.0 프로젝트 설정 (0) | 2020.05.12 |
OpenCV를 이용한 영상처리::11장~12장 과제 (0) | 2020.03.29 |
OpenCV를 이용한 영상처리::4~6장 과제 (0) | 2020.03.29 |
OpenCV를 이용한 영상처리::1~3장 과제 (0) | 2020.03.29 |