12
2016-Mar
[OpenCV] 마커 추출
작성자: Blonix
IP ADRESS: *.148.87.98 조회 수: 1405
마찬가지로 아래 문자인식, 레이블링 글과 동일한 블로그.
출처 :: http://martinblog.net/827
예제파일
http://fogeaters.cafe24.com/xe/board11/13777
OpenCV 강좌 06. 마커 추출 (1) - 잡영 제거
K. Martin 2009.07.02 23:57
BlobBigSizeConstraint(int nWidth, int nHeight)는 지정한 값 보다 큰 레이블들을 제거한다.
각각의 함수는 클래스 내부에서 각각 _BlobSmallSizeConstraint()와 _BlobBigSizeConstraint()를 호출한다.
2. 제거 알고리즘의 작성(작은 레이블을 제거하는 루틴)
큰 값들은 temp에 저장하고, 작은값(잡영으로 판단한 값)을 가지는 레이블은 과감히 제낀다 -_-a
이후 temp의 내용을 원래 레이블 크기정보가 들어있던 rect에 옮겨 담음으로써 마무리된다.
3. 잡영 제거
- 영상의 80% 이상, 30px 이하의 레이블들은 모두 제거한다.
실제로는 사이사이 엄청나게 많은 고민과 변화가 필요하다.
예를들어, 지금은 단순히 OTSU의 이진화 방법을 이용하고 있지만,
조명의 영향을 덜 받기 위해 배경평면을 만들어 낸다던지,
이진화 기법을 개선하기 위해 Kmeans 알고리즘 등을 이용하여 추출률을 높힐 수 있다.
(실제로 번호판 문자의 추출에 본 알고리즘을 적용하여 사용하고 있다.)
적당한 크기를 미리 정하여 휴리스틱하게 맞춰가는 방법 등도 고려할 수 있다.
OpenCV 강좌 07. 마커 추출 (2) - 마커 검증
K. Martin 2009.07.07 00:05이번 장은 앞서 검출된 마커 후보영역들 중에서,
실제 마커영역이 가지는 특징을 가지는 것을 최종적으로 남기는 검증단계를 구현한다.
검증의 방법은 간단하다.
레이블의 내부에 홀이 있는지 없는지 파악한 뒤,
그 홀의 위치와 크기를 외부 레이블의 그것과 비교해 보고,
현재 레이블이 마커인지 아닌지 구분해 내는 것이다.
- 만들어둔 레이블링 알고리즘 사용의 적극 권장!

보다시피 몇 줄 안되면서도 동족방뇨스럽기 그지없는 코드이지만, 결과는 꽤나 만족할 만 하다. (자화자찬-_-)
홀을 찾는다는 것은 반전된 이미지의 개체(레이블)를 찾는 것과 같은 의미이다. (쉽게가자)
각 레이블들의 가로세로 정보를 토대로 각 레이블을 담을 새로운 이미지(sub_gray)를 생성한 뒤,
여기에 각각의 레이블 이미지를 반전(CV_THRESH_BINARY_INV)하여 담는다.
반전된 이미지를 레이블링 한 뒤,
그것의 크기가 테두리 레이블 크기의 40% 이상, 80% 이하인 것들만을 남기고 제거한다.
적절한 수치는 마커의 크기에 따라 테스트를 계속 하면서 바꿔줄 수 있을 것 같다.
이후,
반전된 이미지의 레이블(홀)이 테두리 레이블의 가장자리에 있다는 것은,
이 테두리 레이블이 닫힌 형태가 아닌라는 것, 즉. 홀이 존재하는 것이 아니라는 말이므로 과감하게 제낀다.
홀은 녹색으로 칠해준다.
이후 작업 예고 >
먼저, 추출된 마커의 외부/내부 사각형의 네 꼭지점을 구한다.
이때, 마커 내부 사각형의 꼭지점 정보는,
사각형 내부 영상을 정규화하고 어떤 문자를 담고 있는지 파악하는데 사용 할 것이고,
외부 사각형의 꼭지점 정보는,
뮤직비디오의 영상을 마커의 모양과 동일하게 와핑하여 출력시키는데 사용 할 것이다.
와핑 관련 예습 자료 : cvWarpPerspective() 사용 방법
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
OpenCV 강좌 08. 마커 추출 (3) - 마커 꼭지점 구하기
K. Martin 2009.07.15 21:37이를 위해 OpenCV에서는 cvFindContours() 함수를 제공하고 있다.
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)));
CvSeq** first_contour에 윤곽선 정보가 들어간다.
이를 이용하여 윤곽선을 추출한 뒤, 이를 이용하여 마커의 네 꼭지점을 구한다.
1. 윤곽선 검출
CvSeq* contours = 0;
다섯 번째 인수인 윤곽 추출 모드는 CV_RETR_TREE로 지정한다. 이는 영상 내의 모든 윤곽을 추출해 분기된 윤곽 모두를 계층구조로 나타낸다. 여섯 번째 인수는 윤곽점 중 특징점(두 점을 잇는 직선으로 표현 안되는 점)들만 배열에 정렬하기 위해 CV_CHAIN_APPROX_SIMPLE로 둔다.
cvDrawContours()를 이용하면 영상 위에 간단하게 윤곽선을 출력할 수 있다.
2. 꼭지점 추출
- 임의의 점에서 가장 먼 점을 첫 번째 꼭지점으로 설정한다.
CvPoint *st = (CvPoint *)cvGetSeqElem( contours, 0 );
시퀀스의 첫 점을 초기위치로 하여 모든 특징점들과의 거리를 계산한다.
첫 번째 점은 corner[0]에 저장한다.
- 같은 방법으로 두 번째 꼭지점을 구할 수 있다.
직사각형의 경우 당연히 대각점이 가장 먼 점이 되지만,
사각형은 경우에 따라 아래와 같이 여러 방향에서 두 번째 꼭지점이 나타난다.
두 번째 점은 corner[1]에 저장한다.
- 세 번째 꼭지점은 첫 번째, 두 번째 점에서 가장 먼 점을 구한다.
세 번째 점은 corner[2]에 저장한다.
- 이렇게 하면 어떻게든 세 개의 꼭지점을 구해낼 수 있다.
이제 네 번째 꼭지점이 눈앞이다.
- 그런데 문제가 있다.
같은 방법으로 네 번째 꼭지점을 구하는 일이 항상 가능한 일이 아니라는 점은 아래에서 확인할 수 있다.
첫 번째, 두 번째 점에서 거리가 가장 먼 점은 좌측 상단의 점 (153,255)이다.
세 개의 점에서 가장 먼 점이 우측상단의 점이 되어야 하지만, 애석하게도 그 점은 우측 하단의 점 (481, 336)이다.
- 이런 이유로 거리정보만으로 네 꼭지점 모두를 구하는 것은 무리가 있다고 하겠다.
이 시점에서는 사각형의 넓이정보를 이용한다.
- 알고리즘에서는 이미 구해둔 세 개의 꼭지점과 나머지 한 점. 즉, 윤곽선 상의 모든 점 (x, y)을 세 개의 삼각형으로 나눈 뒤 그 넓이의 합이 최대가 되는 점 (x, y)를 네 번째 꼭지점으로 정한다.
3. 추출된 꼭지점과 좌표 출력
- 글자는 안겹치게 5픽셀씩 오른쪽으로 밀어주는 센스! ^^*