해당 포스팅은 OpenCv 4로 배우는 컴퓨터 비전과 머신러닝 (황선규 저)를 보고 공부하며 개인적인 용도를 위해 정리한 글이다.
HOG (Histogram of Oriented Gradients) 알고리즘
- 사람이 서있는 영상에서 그래디언트를 구하고 그래디언트 크기와 방향 성분을 이용하여 사람이 서있는 형태에 대한 특징 벡터를 정의한다.
- 특징 벡터를 머신 러닝의 일종인
서포트 벡터 머신 (SVM, Support Vector Machine)
을 이용하여 입력 영상에서 보행자 위치를 검출하는 방법이다.
계산 방법
- 기본적으로 $(64, 128)$ 영상에서 그래디언트를 계산한다.
- 크기와 방향성분으로 계산하며 방향성분은 $0^{\circ}$부터 $180^{\circ}$까지로 설정한다.
- 입력 영상을 $(8, 8)$ 크기 단위로 분할하며 해당 크기의 영상을 셀 (cell) 이라고 정의한다.
- $(64, 128)$개로 분할한 영상에서 가로로 8개, 세로로 16개의 셀을 만들 수 있고, 각 셀별로 그래디언트 방향 성분을 $20^{\circ}$로 설정하여 총 9개의 빈 (bin) 을 갖는 히스토그램을 만든다.
- 이 때, 인접한 4개의 셀을 블록 (block) 이라고 정의한다.
- 하나의 블록엔 4개의 셀이 있고 하나의 셀에는 9개의 히스토그램이 있으므로 하나의 블록에서는 총 36개의 실수로 된 히스토그램 데이터가 나온다.
- 블록은 가로세로 방향으로 한 칸씩 움직이며 정의하므로 $(64, 128)$ 영상에선 총 가로 7개, 세로 15개의 블록을 정의할 수 있으며, 히스토그램의 총 갯수는 $15 * 7 * 36 = 3780$개가 된다.
- 이 $3780$개의 히스토그램은 $(64, 128)$크기의 영상의 특징 벡터를 의미한다.
- 해당 특징 벡터들을 보행자의 특징 벡터, 보행자가 아닌 특징 벡터로 학습한
SVM
을 통해 검출을 시도한다.
cv::HOGDescriptor
- 미리 정의 된 기술자 정보를 반환하는 정적 멤버 함수
getDefaultPeopleDetector()
를 제공한다.- 정적 멤버 함수이므로
cv::HOGDescriptor::getDefaultPeopleDetector()
의 형태로 선언한다.
- 정적 멤버 함수이므로
- 객체를 검출하기 위해선 훈련 된
SVM
분류기 계수를setSVMDetector()
로 등록해야한다. cv::HOGDescriptor::detectMultiScale()
는 두 개의 형태로 정의 되어있는데,foundWeights
변수에 검출 된 객체의 신뢰도를 전달하냐의 차이이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include "opencv2/opencv.hpp"
int main(void)
{
cv::videoCapture cap("path/to/video");
if (!cap.isOpened())
{
std::cerr << "the video file is not opened!" << std::endl;
return 1;
}
cv::HOGDescriptor hog; // 검출기 객체 생성
hog.setSVMDetector(cv::HOGDescriptor::getDefaultPeopleDetector()); // 객체에 검출 분류기 전달
cv::Mat frame;
while(1)
{
cap >> frame; // 영상을 frame 에 전달
if (frame.empty())
{
std::cerr << "the video is ended." << std::endl;
break;
}
std::vector<cv::Rect> detected;
hog.detectMultiScale(frame, detected); // 보행자 검출
for (cv::Rect r: detected)
{
cv::Scalar c = cv::Scalar(rand() & 256, rand() & 256, rand() & 256);
cv::rectangle(frame, r, c, 2);
}
cv::imshow("frame", frame);
if (cv::waitKey(10) == 27)
{
break;
}
}
cap.release();
return 0;
}