반응형
Optical Flow
- Optical flow는 연속적인 프레임(Video) 사이에서 물체나 카메라의 움직임으로 인해 발생하는 차이.
- 이동을 나타내는 2D vector field이다.
- optical flow는 몇 가지 가정에 따라 작동한다.
- 개체의 픽셀 강도는 연속 프레임 간에 변경되지 않는다.
- 인접한 이웃 픽셀은 비슷한 움직임을 갖는다.
- 첫 번째 Frame의 pixel I(x, y, t)
- dt 시간 이후에 찍은 다음 Frame에서 거리 (dx, dy) 만큼 이동.
- 위 가정에서 해당 픽셀은 동일하고 강도는 변경되지 않음으로 아래 식과 같다.
- 우변에 테일러 급수를 취하고 공통항을 제거하고 dt로 나누면 아래와 같다.
- 위 방정식을 Optical Flow 방정식이라고 한다. (fx, fy는 이미지 gradient, ft는 시간에 따른 기울기)
- u, v의 값은 알 수 없다. → Lucas-Kanade 방법으로 알 수 있다.
Lucas-Kanade method
- 이웃한 픽셀이 유사한 움직임을 가질 것이라는 가정.
- 3x3 patch 사용. → 9개의 점은 모두 같은 움직임을 갖는다.
- u, v를 변수로 최소자승법을 이용해 9개의 방정식을 풀 수 있다.
- 추적할 몇 가지 포인트를 제공하고 해당 포인트의 광학 흐름 벡터를 수신한다.
- 작은 움직임을 다루다 보니 큰 움직임이 있으면 실패한다. → 이를 해결하기 위해 pyramid 사용.
- 피라미드에 오르면 작은 움직임은 제거되고 큰 움직임은 작은 움직임이 된다.
Lucas-Kanade Optical Flow in OpneCV
- calcOpticalFlowPyrLK() 함수에서 기능 제공.
- 비디오의 일부 지점을 추적하는 예제.
- 일부 지점은 goodFeaturesToTracks() 함수를 이용하여 선택.
CString szFilter = _T("Video (*.MP4) | *.MP4;*.jpg | All Files(*.*)|*.*||");
CFileDialog dlg(FALSE, NULL, NULL, OFN_HIDEREADONLY, szFilter);
CString path;
if (IDOK == dlg.DoModal()) {
path = dlg.GetPathName();
}
else {
return;
}
cv::String strPaht = cv::format("%S", path);
cv::VideoCapture cap(strPaht);
if (!cap.isOpened())
return;
// 색상표
vector<Scalar> colors;
RNG rng;
for (int i = 0; i < 100; i++)
{
int r = rng.uniform(0, 256);
int g = rng.uniform(0, 256);
int b = rng.uniform(0, 256);
colors.push_back(Scalar(r, g, b));
}
// 1. get first frame feature.
Mat old_frame, old_gray;
vector<Point2f> p0, p1;
cap >> old_frame;
cvtColor(old_frame, old_gray, COLOR_BGR2GRAY);
goodFeaturesToTrack(old_gray, p0, 100, 0.3, 7, Mat(), 7, false, 0.04); // 100개의 feature point -> p0
// Create a mask image for drawing purposes
Mat mask = Mat::zeros(old_frame.size(), old_frame.type());
while (true) {
Mat frame, frame_gray;
cap >> frame;
if (frame.empty())
break;
cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
vector<uchar> status;
vector<float> err;
// 2. calculate optical flow (old gray -> frame gray : p0 -> p1)
TermCriteria criteria = TermCriteria((TermCriteria::COUNT) + (TermCriteria::EPS), 10, 0.03);
calcOpticalFlowPyrLK(old_gray, frame_gray, p0, p1, status, err, Size(15, 15), 2, criteria);
// 3. status보고 good point만 선택
vector<Point2f> good_new;
for (uint i = 0; i < p0.size(); i++)
{
// Select good points
if (status[i] == 1) {
good_new.push_back(p1[i]);
// draw the tracks
line(mask, p1[i], p0[i], colors[i], 2);
circle(frame, p1[i], 5, colors[i], -1);
}
}
Mat img;
add(frame, mask, img);
imshow("Frame", img);
int keyboard = waitKey(30);
if (keyboard == 'q' || keyboard == 27)
break;
// 4. Now update the previous frame and previous points
old_gray = frame_gray.clone();
p0 = good_new;
}
Dense Optical Flow in OpenCV
- Lucas-Kanade method는 (goodFeaturesToTrack에 의해) 감지된 point에 대한 Optical Flow 계산.
- OpenCV는 프레임의 모든 점에 대한 Optical Flow 알고리즘을 제공.
- Gunnar Farneback의 알고리즘을 사용.
CString szFilter = _T("Video (*.MP4) | *.MP4;*.jpg | All Files(*.*)|*.*||");
CFileDialog dlg(FALSE, NULL, NULL, OFN_HIDEREADONLY, szFilter);
CString path;
if (IDOK == dlg.DoModal()) {
path = dlg.GetPathName();
}
else {
return;
}
cv::String strPaht = cv::format("%S", path);
cv::VideoCapture cap(strPaht);
if (!cap.isOpened())
return;
Mat frame1, prvs;
cap >> frame1;
cvtColor(frame1, prvs, COLOR_BGR2GRAY);
while (true) {
Mat frame2, next;
cap >> frame2;
if (frame2.empty())
break;
cvtColor(frame2, next, COLOR_BGR2GRAY);
Mat flow(prvs.size(), CV_32FC2);
calcOpticalFlowFarneback(prvs, next, flow, 0.5, 3, 15, 3, 5, 1.2, 0);
// visualization
Mat flow_parts[2];
split(flow, flow_parts);
Mat magnitude, angle, magn_norm;
cartToPolar(flow_parts[0], flow_parts[1], magnitude, angle, true);
normalize(magnitude, magn_norm, 0.0f, 1.0f, NORM_MINMAX);
angle *= ((1.f / 360.f) * (180.f / 255.f));
//build hsv image
Mat _hsv[3], hsv, hsv8, bgr;
_hsv[0] = angle;
_hsv[1] = Mat::ones(angle.size(), CV_32F);
_hsv[2] = magn_norm;
merge(_hsv, 3, hsv);
hsv.convertTo(hsv8, CV_8U, 255.0);
cvtColor(hsv8, bgr, COLOR_HSV2BGR);
imshow("frame2", bgr);
int keyboard = waitKey(30);
if (keyboard == 'q' || keyboard == 27)
break;
prvs = next;
}
반응형
'Computer Vision > OpenCV' 카테고리의 다른 글
[OpenCV] cv::VideoCapture RTSP open failed. (0) | 2022.06.14 |
---|---|
[OpenCV] Histogram Equalization (히스토그램 평활화) (0) | 2022.02.25 |
[OpenCV] Gamma Correction(감마 보정) (0) | 2021.05.14 |
[OpenCV] Canny Edge (0) | 2021.04.05 |