2013년 1월 26일 토요일

OpenCV #7-2 Example (허프 변환으로 영상 내 선 감지 - 부연 설명)

 - 허프 변환은 또한 다른 기하학적인 요소를 감지하기 위해 사용.
 - 확률 방정식으로 표현하는 임의 요소는 허프 변환을 위한 좋은 후보.


  • 원 감지
 - 원인 경우에 해당 확률 방정식은 다음과 같다.
 - 이 방정식은 세 가지 파라미터(원의 반지름과 중심 좌표)를 갖는데, 3차원 누산기가 필요함을 의미.
 - 그러나 일반적으로 허프 변환은 누산기의 차원이 증가하면 신뢰도가 떨어짐.
 - 이 경우에는 누산기 요소의 많은 개수가 각 점에 대해 증가하고, 결과로는 지역 봉우리의 정확한 지역화가 더욱 어려워짐.
 - 그러므로 이런 문제를 극복하기 위한 다른 전략이 제안됨.
 - 그 중 하나는 OpenCV에서 허프 원 감지를 구현할 때 두 가시 패스를 사용하는 방법.

 - 첫 번째 패스 과정에서 2차원 누산기는 후보 원 위치를 찾는 데 사용.
 - 원 둘레에 놓인 점의 기울기는 반지를 방향에 있는 점이어야 하므로, 다음 각 점에 대해 누산기 내의 각 요소는 기울기 방향에 따라 증가. (미리 정의된 최소와 최대 반지름 값)
 - 일단 가능한 원 중심을 감지하면(미리 정의한 투표 개수를 받아들이면) 두번째 패스 동안 가능한 반지름의 1차원 히스토그램을 구축.
 - 히스토그램 내 봉우리 값은 감지한 원의 반지름에 대응.

 - cv::HoughCircles 함수는 위의 전략을 구현하기 위해 캐니 감지와 허프 변환을 모두 통합.


cv::GaussianBlur(image, image, cv::Size(5,5), 1.5);
std::vector<cv::Vec3f> circles;
cv::HoughCircles(image, circles, CV_HOUGH_GRADIENT, 
2,   // 누적기 해상도(영상크기/2)
50,  // 두 원 간의 최소 거리
200, // 캐니 최대 경계값
100, // 투표 최소 개수
25, 100); // 최소와 최대 반지름


 - 몇 가지 잘못된 원 감지를 일으킬 수 있는 영상 잡음을 제거하기 위해 cv::HoughCircles 함수를 호출하기 전에 영상을 부드럽게 할 것을 권장.
 - cv::Vec3f 인스턴스의 벡터에 감지 결과가 들어 있음.
 - 처음 두 값은 원의 중심이고, 세 번째는 반지름이다.
 - CV_HOUGH_GRADIENT 인자는 2패스 원 감지 메소드에 해당.
 - 네 번째 파라미터는 누산기 해상도를 정의.
 - 분할자를 예를 들어 2로 지정하면 영상의 절반 크기인 누산기를 만듬.
 - 다음 파라미터는 두 감지된 원 간의 화소에서 최소 거리.
 - 다른 파라미터는 캐니 에지 감지기의 높은 경계값에 해당.
 - 낮은 경계값은 이 값의 절반으로 설정.
 - 일곱 번째 파라미터는 두번째 패스에서 후보 원으로 간주하기 위해 첫 번째 패스 동안 중심 위치에서 반드시 받아야 하는 투표 최소 개수.
 - 끝으로 마지막 두 파라미터는 감지하기 위한 원에 대한 최소와 최대 반지름 값.
 - 이렇듯 이 함수는 조정하기 어렵게 만드는 많은 파라미터를 가짐.

 - 일단 감지한 원의 벡터를 얻으면 벡터를 반복해 영상 내에 그릴 수 있고, 찾은 파라미터와 함께 cv::circle 그리기 함수를 호출.


std::vector<cv::Vec3f>::const_iterator itc= circles.begin();
while (itc!=circles.end()) {
 cv::circle(image, 
 cv::Point((*itc)[0], (*itc)[1]), // 원 중심
 (*itc)[2], // 원 반지름
 cv::Scalar(255), // 컬러 
 2); // 두께
 ++itc;
}

 - 소스
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

int main()
{
// 원 감지
cv::Mat image;
image = cv::imread("chariot.jpg",0);

cv::GaussianBlur(image, image, cv::Size(5,5), 1.5);
std::vector<cv::Vec3f> circles;
cv::HoughCircles(image, circles, CV_HOUGH_GRADIENT, 
2,   // 누적기 해상도(영상크기/2)
50,  // 두 원 간의 최소 거리
200, // 캐니 최대 경계값
100, // 투표 최소 개수
25, 100); // 최소와 최대 반지름

std::cout << "Circles: " << circles.size() << std::endl;

// 원 그리기
image= cv::imread("chariot.jpg",0);
std::vector<cv::Vec3f>::const_iterator itc= circles.begin();
while (itc!=circles.end()) {
 cv::circle(image, 
 cv::Point((*itc)[0], (*itc)[1]), // 원 중심
 (*itc)[2], // 원 반지름
 cv::Scalar(255), // 컬러 
 2); // 두께
 ++itc;
}

cv::namedWindow("Detected Circles");
cv::imshow("Detected Circles",image);

cv::waitKey(0);

return 0;
}

 - 결과



  • 일반화 허프 변환
 - 일부 모양에 대해 간결한 파라메트릭 표현을 찾기가 어려움.
 - 삼각형, 팔각형, 다각형, 객체 프로파일등을 예로 들 수 있음.
 - 영상 내에서 이런 모양의 위치에 대한 허프 변환을 사용할 수 있음.
 - 2차원 누산기는 목표 모양에 대한 모든 가능한 위치를 보여주기 위해 만들었다.
 - 모양에서 참조점을 정의해야 하고, 가능한 참조점 위치에 대해 영상 내의 각 특징점에 투표 해야 함.
 - 점은 모양의 외곽선 어디서나 존재할 수 있으므로, 가능한 모든 참조 위치로 누산기 내 관심 모양의 거울인 모양을 추적.
 - 거기에 영상 안의 같은 모양에 속하는 점은 누산기 내 모양의 위치에 대응하는 교차점에서 정점peak을 만듬.

 - 다음 그림에서 참조가 하단 왼쪽 모서리에 정의된 관심 모양이 삼각형(오른쪽에 보임)임을 보여줌.
 - 누산기는 해당 특징점을 통과하는 삼각형 참조점이 있을 법한 위치에 대응해 그려진 위치에서 모든 요소를 증가하는 특징점을 보여줌.



 - 이런 접근은 종종 일반화 허프 변환이라고 함.
 - 분명 기술 가능한 크기 변경이나 모양 회전에 대해서는 계산할 수 없음.
 - 더 높은 차원에서 검색해야함.
  • 참고문헌 : OpenCV 2 Computer Vision Application Programming Cookbook