Computer Vision2015. 9. 25. 20:05


옵티컬 플로우는 컴퓨터비전을 공부하다 보면 꼭 나오는 주제입니다. 원리와 수식은 위키피디아, 블로그, openCV API에 많이 나와있으니 글 하단에
참고사이트로 대신하고, 이 포스팅에서는 제가 헷갈렸던 이야기와 몇 가지 개념에 대해 써보겠습니다.


옵티컬 플로우 또는 광류라고 하는 이 알고리즘은 간단히 말하면 차영상의 진화버전이라고 할 수 있겠습니다. 이전 프레임과 현재 프레임의 차이에 관심을 둔다는 점에서요.


저는 옵티컬 플로우를 처음에 아래 그림처럼 접했었습니다. 제 선배가 옵티컬 플로우를 사용해서 논문을 쓰는걸 봤는데 아래 그림과 같은 방식으로 사용하시더라구요.




이전 프레임에서 강인해 보이는(다음 프레임에서도 추출될 만한) 특징점 추출 후 현재 프레임에서 같은 특징점을 찾아 얼만큼 위치변화가 있었는지 보는 방식입니다.


여기서 짚고 넘어가야할 점은, 특징점의 분포가 움직이는 물체 부분에 밀집되어 있다는 점입니다. 위 그림처럼 카메라가 고정되어있고 자동차가 움직인다면 특징점은 차도에 많이 생기겠죠.


이렇다 보니 옵티컬 플로우를 객체 위치 인식 및 추적용으로 생각하시는 분들이 많은 것 같아요.(실제로 그렇게 사용하기도 합니다.)


하지만 제 생각에는 옵티컬 플로우는 물체가 어떻게 움직이고 있는지 판단할 때 가장 좋은 알고리즘이 아닐까 싶습니다. 


여기서 잠깐, Lucas-Kanade(LK), Horn-Schunk(HS)라는 키워드에 대해 짚고 넘어가겠습니다.


이것도 많이 헤매게 된 부분인데요, AR.Drone 논문에서 옵티컬 플로우를 LK와 HS를 모두 사용했다고 나오길래, 옵티컬 플로우는 크게 두 가지 방법이 있는 줄 알았습니다. openCV에는 아예 대놓고 calcOpticalFlowPyrLK()라는 함수가 있고 API를 봐도 루카스 카나데 방법을 사용한다고 써놨습니다. 근데 HS방법은 아무리 검색을 해봐도 안나와서 이상타 싶었는데 HS는 옵티컬 플로우를 어떻게 해석하는지에 중점을 두고 연구한 사람들이더라구요. (아래 참고사이트에 책 내용이 잘 나와 있다는 사이트를 참고하세요~)


위 자동차 그림처럼 특징점의 위치가 고르지 않은 상황에서는 HS방법을 쓰기 힘들 것 같네요.



            



이렇게 되어있는 경우 잘 들어맞을 것 같습니다.


객체와 배경이 함께 움직인다면 배경 부분까지 옵티컬 플로우가 만들어질 겁니다. 배경이 움직인다는건 다시 말해 카메라가 움직인다는 걸로도 볼 수 있기 때문에 배경의 속도는 카메라의 속도로 이어집니다.


이런 생각에 착안해 화면 전체의 옵티컬 플로우를 구하기 위해 찾아보았습니다.


아래의 제가 찍은 옵티컬플로우 동영상과 같이, 윙윙이에도 이런 방식을 적용했습니다.





openCV로 구현했구요, 프레임을 100개의 정사각형 블럭으로 나누고 블럭 중앙을 특징점으로 정한다음에 다음 프레임에서 특징점을 찾는 방식입니다.


노이즈가 심한거는 옵티컬 플로우 함수의 파라미터를 조정해서 개선했구요, 말도 안되게 튀는 노이즈는 if문으로 제거했습니다.


원래는 RANSAC을 이용해서 outlier 필터링을 하려고 했는데 각 벡터들을 평균해보니 꽤 쓸만한 값이 나와서 일단 그대로 사용하는 중입니다.


함수는 


calcOpticalFlowPyrLK(frame_prev, frame_gray, featurePrev, featureNext, isFound, err, winSize, 3, termcrit, 0, 0.01);


이렇게 사용중입니다.


frame_prev : 이전 프레임(8비트 단일 채널)

frame_gray : 현재 프레임(8비트 단일 채널)

featurePrev : 이전 프레임의 특징점 좌표들(vector<Point2f>)

featureNext : 현재 프레임의 특징점 좌표들(vector<Point2f>) - 함수 내부에서 만들어서 출력해줌(길이는 featurePrev와 동일)

isFound : 특징점을 찾는데 성공했는지 배열로 저장(길이는 featurePrev와 동일)

err : 이전 특징점과 현재 특징점간의 거리를 배열에 저장((길이는 featurePrev와 동일)

winsize : LK방법이므로 지역적으로 찾기위한 윈도우 크기(Size)

3 : 피라미드 최대 계층 개수

termcrit : 종료 조건(TermCriteria termcrit(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03); 이렇게 사용중)

0.01 : 최소 고유값


여기서 성능에 가장 영향을 많이 미치는 부분은 윈도우 크기와 피라미드 최대 계층 개수였습니다. 윈도우 크기를 늘리거나 계층 수를 늘리면 노이즈가 적어지고 성능이 좋아지지만 처리 속도가 느려져 실시간 피드백용으로는 적합하지 않았습니다.


위 동영상의 성능과 보정, 융합 결과는 다음 포스팅에서 다루기로 하고 오늘은 여기까지~!




참고 사이트 및 문헌

OpenCV-optical flow ( http://docs.opencv.org/master/d7/d8b/tutorial_py_lucas_kanade.html#gsc.tab=0 )

책의 내용과 이론 설명이 잘 되어있는 사이트( http://lueseypid.tistory.com/98 )

Determining optical flow - HornSchunk ( http://dspace.mit.edu/bitstream/handle/1721.1/6337/AIM-572.pdf?sequence=2 )

The navigation and control technology inside the ar. drone micro uav http://cas.ensmp.fr/~petit/papers/ifac11/PJB.pdf )






Posted by 너를위한노래

댓글을 달아 주세요

  1. 김지환

    글 정말 많이 도움되었습니다! 감사합니다. 한가지 질문이 있는데요, 100개로 나뉜 블럭의 중심을 특징으로 사용하셔서 다음 프레임에서 같은 특징을 찾으신다고 하시는데 어떤 특징을 사용하셨는지 알려주실 수 있으신가요?

    2016.05.27 22:28 [ ADDR : EDIT/ DEL : REPLY ]
    • 특징점을 고르는 것도 연산 부하가 걸려서 이 단계를 생략했습니다. 그냥 고정된 x, y 좌표 100개를 사용했습니다. 굳이 특징이라고 하면 픽셀의 그레이스케일 intensity를 사용했다고 해도 될까요 ㅋㅋ

      2016.08.24 20:42 신고 [ ADDR : EDIT/ DEL ]
  2. 광류

    궁금한 것이 있어 질문드립니다. 제가 optical flow를 써서 야구배트를 추적하려고 하는데요 배트의 속도가 빠른데 optical flow로 가능할까요?

    카메라는 고정 되어 있습니다. 야구배트의 체크스윙을 판별하려고 하는데 가능한지 알고 싶습니다. ㅠㅠ 도와주세요 ㅠㅠ

    2016.10.03 23:00 [ ADDR : EDIT/ DEL : REPLY ]