관리 메뉴

마틴블로그닷넷

OpenCV 강좌 08. 마커 추출 (3) - 마커 꼭지점 구하기 본문

[ 프로그래밍 ]/강좌

OpenCV 강좌 08. 마커 추출 (3) - 마커 꼭지점 구하기

K. Martin 2009.07.15 21:37
마커의 영역이 추출되면 그 마커의 윤곽선만을 추출해 낼 수 있으며,
이를 위해 OpenCV에서는 cvFindContours() 함수를 제공하고 있다.

/* Retrieves outer and optionally inner boundaries of white (non-zero) connected
   components in the black (zero) background */

CVAPI(int)  cvFindContours( CvArr* image, CvMemStorage* storage, CvSeq** first_contour,
                            int header_size CV_DEFAULT(sizeof(CvContour)),
                            int mode CV_DEFAULT(CV_RETR_LIST),
                            int method CV_DEFAULT(CV_CHAIN_APPROX_SIMPLE),
                            CvPoint offset CV_DEFAULT(cvPoint(0,0)));
CvArr* image는 0을 배경으로 0이 아닌 값(백색)을 개체로 하는 영상이며,
CvSeq** first_contour에 윤곽선 정보가 들어간다.

이를 이용하여 윤곽선을 추출한 뒤, 이를 이용하여 마커의 네 꼭지점을 구한다.

1. 윤곽선 검출

CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* contours   = 0;


마커의 이미지가 들어갈 영상을 생성한 뒤 윤곽선을 추출한다.
다섯 번째 인수인 윤곽 추출 모드는 CV_RETR_TREE로 지정한다. 이는 영상 내의 모든 윤곽을 추출해 분기된 윤곽 모두를 계층구조로 나타낸다. 여섯 번째 인수는 윤곽점 중 특징점(두 점을 잇는 직선으로 표현 안되는 점)들만 배열에 정렬하기 위해 CV_CHAIN_APPROX_SIMPLE로 둔다.
cvDrawContours()를 이용하면 영상 위에 간단하게 윤곽선을 출력할 수 있다.

2. 꼭지점 추출
- 임의의 점에서 가장 먼 점을 첫 번째 꼭지점으로 설정한다.


CvSeq* 형의 contours 변수에서 CvPoint* 형의 실제 좌표를 가져올 수 있다.
CvPoint *st  = (CvPoint *)cvGetSeqElem( contours, 0 );
시퀀스의 첫 점을 초기위치로 하여 모든 특징점들과의 거리를 계산한다.

첫 번째 점은 corner[0]에 저장한다.

- 같은 방법으로 두 번째 꼭지점을 구할 수 있다.
직사각형의 경우 당연히 대각점이 가장 먼 점이 되지만,
사각형은 경우에 따라 아래와 같이 여러 방향에서 두 번째 꼭지점이 나타난다.
두 번째 점은 corner[1]에 저장한다.

- 세 번째 꼭지점은 첫 번째, 두 번째 점에서 가장 먼 점을 구한다.
세 번째 점은 corner[2]에 저장한다.


- 이렇게 하면 어떻게든 세 개의 꼭지점을 구해낼 수 있다.
이제 네 번째 꼭지점이 눈앞이다.

- 그런데 문제가 있다.
같은 방법으로 네 번째 꼭지점을 구하는 일이 항상 가능한 일이 아니라는 점은 아래 테스트 영상에서 확인할 수 있다.


첫 번째 점은 좌측 하단의 점 (136,381)이고, 두 번째 점은 우측 하단의 점 (418,340)이다.
첫 번째, 두 번째 점에서 거리가 가장 먼 점은 좌측 상단의 점 (153,255)이다.
세 개의 점에서 가장 먼 점이 우측상단의 점이 되어야 하지만, 애석하게도 그 점은 우측 하단의 점 (481, 336)이다.

- 이런 이유로 거리정보만으로 네 꼭지점 모두를 구하는 것은 무리가 있다고 하겠다.
이 시점에서는 사각형의 넓이정보를 이용한다.

직교 좌표계에서 각 꼭지점의 좌표가 그 내부를 반시계방향으로 도는 순서대로 (x1,y1), (x2,y2), ... , (xn,yn)로 주어져 있는 단순한 다각형의 넓이 A는 다음과 같이 계산할 수 있다.


이 공식은 1769년 마이스터가, 1795년 가우스가 사용하였다.


- 알고리즘에서는 이미 구해둔 세 개의 꼭지점과 나머지 한 점. 즉, 윤곽선 상의 모든 점 (x, y)을 세 개의 삼각형으로 나눈 뒤 그 넓이의 합이 최대가 되는 점 (x, y)를 네 번째 꼭지점으로 정한다.


3. 추출된 꼭지점과 좌표 출력
- 글자는 안겹치게 5픽셀씩 오른쪽으로 밀어주는 센스! ^^*

4. 테스트
- 단일 마커


- 다중 마커





이제 강좌도 막바지에 접어듭니다.
다음편에는 여기에 뮤직비디오를 뿌립니다.
기대하세요!


20 Comments
  • Favicon of http://blog.naver.com/niceggal1 mang 2009.09.09 09:04 신고 정말 잘 정리 해놓으셨네요. 많이 배워 갑니다.
    저는 회사에서 현재 ar프로젝트를 진행 중인데, 일단 AR엔진의 회형적 구현은 쉬워도,
    T-Immersion 사의 AR엔진이나, ARToolkit pro 수준까지 가는 완성도를 높이는 작업은
    정말 어려운 듯 합니다.
  • Favicon of http://martinblog.net K. Martin 2009.09.15 01:29 신고 네. 맞는 말씀입니다.
    전문적으로 AR을 할 것이 아니기 때문에 그렇지,
    안그러면 머리좀 많이 아팠을겁니다.
  • Favicon of http://linuxmarine.tistory.com 마리니 2009.09.11 21:18 신고 OpenCV 카페에서도 질문을 올립니다. 예제에서 보이는것 과 같은 사각형이 아닌 단색으로 채워진 물체에서도 좌표값을 나타낼 수 있는 건가요???
  • Favicon of http://martinblog.net K. Martin 2009.09.15 01:30 신고 물론 가능합니다.
    최초에 마커를 찾고 검증하는 부분의 코드를 약간만 수정하면 될 것 같네요.
  • 배우는 학생 2009.11.06 21:41 신고 오... 예전에 봤을 때는 그저. 그런가보다.. 하고 지나쳤는데
    직접 구현하다가 마틴님 블로그를 보니.
    그저.. 완전 고마울 뿐입니다. 정말 고맙습니다. ^^
  • Favicon of http://martinblog.net K. Martin 2009.11.10 10:41 신고 도움이 되었다니 다행입니다.
    고맙습니다.
  • 서형석 2010.08.26 15:56 신고 안녕하십니까
    강좌를 잘 보고 있습니다.
    한가지 도움을 청해볼까 하고 이렇게 게시판에 글을 남깁니다.
    제가 하고 싶은것은 마킹한 부분의 object를 따로 분리하여 비교하고자 하는 영상과 비교를 하고 싶은데요.
    마킹을 하고 트레킹을 하는데 이 부분에서 막히고 있습니다.
    어떠한 해결 방법이 있는지 좀 알려주시면 많은 도움이 될것 같습니다.
    영상쪽에 초보이다 보니 이런 질문드리네요.
    좋은 하루 되십시오.
  • Favicon of http://martinblog.net K. Martin 2010.09.04 23:45 신고 현재 제가 소개한 프로그램은 매 프레임에서 마커를 찾고 있습니다만, 말씀하신대로 트래킹을 구현하려면 여러가지 방법이 사용됩니다. mean shift나 CAMShift 같은 알고리즘이 많이 이용되고 있고 검색해보시면 많은 자료를 얻으실 수 있을겁니다.
  • 손동언 2010.10.28 14:47 신고 안녕하세요! 마틴님^^ 강좌 잘보았습니다.
    한가지 질문드리고 싶은게 있어 글을 남겨보네요^_^
    꼭지점 추출시에 윤곽선을 검출 후 "임의점 한점"으로 부터 두번째 꼭지점 세번째 꼭지점 들을 찾아나가기
    시작하는데요~
    이 "임이의 한점"을 선택하는 건 어떻게 할 수 있는지 알고 싶어서 문의드립니다^^
    즐거운 하루 보내시길 바래요^^
  • Favicon of http://martinblog.net K. Martin 2010.10.28 15:33 신고 임의의 한 점은 말 그대로 '임의의' 한 점입니다.
    그 점이 꼭지점이 아니라, 추출된 윤곽선 중의 한 점입니다.
    소스에서 보시면 아시다시피 예제에서는 contours의 첫 번째 좌표값을 사용했습니다.
  • 손동언 2010.10.28 16:27 신고 마틴님 답변감사합니다^^ 그렇다면 추출된 윤곽선 중의 한점이라면, 꼭지점이 아닌 사각형의 한 변에도 임의의 한점이 잡히게 된어서 두번째 꼭지점을 찾게 된다면 마커의 영역이 달라지지 않을까요??ㅠㅠ
    제가 이해력이 많이 부족해서 다시한번 질문을 드려보네요^^
  • Favicon of http://martinblog.net K. Martin 2010.10.28 16:43 신고 네 맞습니다.
    사각형의 한 변에서 임의의 점을 잡아서 사용을 하게될 수도 있는데요, 이런 이유로 첫 번째 임의의 한 점이 시작점이 되는 것이 아니라 그 임의의 한 점에서 가장 먼 점을 시작점으로 두는 것입니다.
    자세한 내용은 2. 꼭지점 추출에 설명되어 있습니다.
    아마도 글로 풀어 쓰다보니 다소 오해의 소지가 있었던 것 같네요.
  • 손동언 2010.10.28 17:27 신고 ㅇ ㅏ! 감사합니다^^ 마틴님의 글을 이해하지 못한 제잘못이 크네요^^;;
    아무튼 너무너무 좋은 강좌 감사합니다.!!^^
    행복하세요!!^^
  • 임형우 2012.01.30 16:46 신고 마틴님 안녕하세요. 제가 이 강의를 mimic 하려고 해서, 지금 1번 윤곽선 추출에서 막혔거든요. Run-Time Check Failure #3 - The variable 'i' is being used without being initialized. 이 에러가 계속 뜨고, 제 생각엔,
    int mw = blob.m_recBlobs[i].width;
    int mh = blob.m_recBlobs[i].height;
    이 부분에서, [i]에 대한 선언이 제대로 않되있나 싶은데요. 도와 주시면 진심으로 감사드리곘습니다.
  • uncleu 2012.05.24 00:19 신고 안녕하세요.
    항상 이곳에 들려 강의를 보고 있습니다.
    한가지 궁금한 점이 생겨 이렇게 질문을 드립니다.

    가우스 공식보면 좌표로 계산을하고 1/2를 곱해주는 것으로 되어 있는데,
    코드상에서 보면 0.5곱이 없습니다.

    이 연산이 필요 없어서 작성을 안하신건지 궁금합니다.~!
  • Favicon of http://martinblog.net K. Martin 2012.05.24 00:45 신고 네. 정확히 기억나진 않지만,
    넓이 개념에서 비교대상인 양변의 1/2는 곱할 필요가 없었던 것으로 생각 됩니다.
  • 이정형 2012.10.19 02:55 신고 안녕하세요 궁금한 점이 있습니다.
    저 마커의 모양을 바꾸려면 코드 내에서 어떤것을 바꿔 주어야 하나요??
    아무리 시도를 해보아도 잘 안되서 여쭤봅니다ㅜ
  • Favicon of http://blog.naver.com/kwm5376 어리보기 2014.07.15 12:09 신고 정말 많은 도움이 되었습니다.
    처음 영상 처리에 관한 프로그래밍을 하게 되어, 외곽선을 어떻게 처리해줄까
    고민했었는데. 이 자료를 보고 해결 하였습니다.
  • 으아아앙 2015.04.16 01:29 신고 컴파일에선 cvvimage가 오류가 생겨서 이와 관련된 부분을 모두 지우고 컴파일 했더니 컴파일은 되나
    IplImage* gray = cvCreateImage( cvSize(m_pImage->width, m_pImage->height), 8, 1 );
    오류가 발생해서 디버깅 부분을보니 여기서 계속 멈추는데... 혹시 알려주실 수 있나요? ㅠㅠ
  • Format 에러ㅠㅠ 2016.07.14 09:11 신고 안녕하십니까 마틴님!!
    강좌 1부터 쭉 공부해보고 있는데요~
    WebCamDlg.cpp의 OnTimer에서 사각형의 각 꼭지점에 좌표 출력하는 곳에서
    text.Format("(%d, %d)", x, y); 의 . 에 오류가 뜨면서 ' 인수 목록이 일치하는 오버로드된 함수 ... 의 인스턴스가 없다'고 나옵니다.

    어떻게 해결할 수 있을까요? ㅠㅠ
댓글쓰기 폼