728x90
728x90
옵티컬플로우(Optical flow)란?- 광학 흐름
- 연속하는 두 프레임(영상)에서 카메라 or 객체의 움직임에 의해 나타나는
객체의 이동 정보 패턴
== Structure from Motion, Video Compression, Video Stabilization(손떨림 방지), etc
두 가지 사실을 가정
1. 연속된 프레임 사이에서 움직이는 물체의 픽셀 강도(intensity)는 변함이 없다.
2. 이웃하는 픽셀은 비슷한 움직임을 갖는다.
옵티컬플로우(Optical flow) 계산 함수
* 루카스-카나데 알고리즘(Lucas-Kanade algorithm)
= 주로 Sparse(희소한) points에 대한 이동 벡터 계산
==> 특정 픽셀에서 optical flow 벡터 계산
이웃하는 픽셀은 비슷한 움직임을 갖는다고 생각하고 광학 흐름을 파악
루카스-카나데 알고리즘은 작은 윈도우(3 x 3 patch)를 사용하여 움직임을 계산
그래서 물체 움직임이 크면 문제가 생긴다. 이 문제를 개선하기 위해 이미지 피라미드를 사용
이미지 피라미드 위쪽으로 갈수록(이미지가 작아질수록) 작은 움직임은 티가 안 나고 큰 움직임은
작은 움직임 같이 보이기 때문에 큰 움직임도 감지할 수 있다.
src1 = cv2.imread('ch10\\images\\frame1.jpg')
src2 = cv2.imread('ch10\\images\\frame2.jpg')
if src1 is None or src2 is None:
print('Image load failed!')
sys.exit()
gray1 = cv2.cvtColor(src1, cv2.COLOR_BGR2GRAY)
# cv2.goodFeaturesToTrack(image, maxCorners, qualityLevel, minDistance)
# grayscale image만 받음(corner 검출을 위함)
pt1 = cv2.goodFeaturesToTrack(gray1, 50, 0.1, 10)
'''
corners, shape=(N, 1, 2)
maxCorners: maxCorners <=0 이면 무제한
minDistance : 두 corner가 너무 근접해서 나타나면 하나는 버리겠다.
10 pixel 금방에 있는 것들은 그 중에서 코너해리스가 높은 것만 선택 나머진 버림
'''
pt2, status, err = cv2.calcOpticalFlowPyrLK(src1, src2, pt1, None)
'''
cv2.calcOpticalFlowPyrLK(prevImg, nextImg, prevPts, nextPts, status=None,
err=None, winSize=None, maxLevel=None, criteria=None, flags=None,
minEigThreshold=None) -> nextPts, status, err
prevPts: 이전 프레임에서 추적할 점들. shape=(N, 1, 2), dtype=np.float32
nextPts: 출력으로 받음(pt2)
status: 점들의 매칭상태. shape=(N,1)
i번째 원소가 1이면 prevPts의 i번째 점이 nextPts의 i번째 점으로 이동
'''
dst = cv2.addWeighted(src1, 0.5, src2, 0.5, 0)
for i in range(pt2.shape[0]): # corner 개수
# 잘 된것만 표현해주기 위함
if status[i,0] == 0: # status.shape= (34,1)
continue
# 도형그릴땐 int값만 받음=> 안하면 error
# error: only size-1 arrays can be converted to Python scalars
'''
pt1, pt2 = [[[1,2], [2,4], ...]]
각 좌표성분이 들어가 있는데
*각 좌표 접근방법*
==> pt1[1, 0] = 첫번째 좌표
'''
cv2.circle(dst, (pt1[i,0]).astype(int), 4, (0,255,255), 2, cv2.LINE_AA)
cv2.circle(dst, (pt2[i,0]).astype(int), 4, (0,0,255), 2, cv2.LINE_AA)
cv2.arrowedLine(dst, (pt1[i,0]).astype(int), (pt2[i,0]).astype(int), (0,255,0), 2)
cv2.imshow('dst', dst)
cv2.waitKey()
* 파네백 알고리즘(Farneback's algorithm)
= Dense(밀집) points에 대한 이동 벡터 계산
==> 모든 픽셀에서 optical flow 벡터 계산
def draw_flow(img, flow, step=16):
h, w = img.shape[:2]
y, x = np.mgrid[step/2:h:step, step/2:w:step].reshape(2, -1).astype(int)
fx, fy = flow[y, x].T
lines = np.vstack([x, y, x+fx, y+fy]).T.reshape(-1, 2, 2)
lines = np.int32(lines + 0.5)
vis = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
cv2.polylines(vis, lines, 0, (0, 255, 255), 2, lineType=cv2.LINE_AA)
for (x1, y1), (_x2, _y2) in lines:
cv2.circle(vis, (x1, y1), 1, (0, 128, 255), -1, lineType=cv2.LINE_AA)
return vis
cap = cv2.VideoCapture("ch10\\videos\\vtest.avi")
if not cap.isOpened():
print('Camera open failed!')
sys.exit()
ret, frame1 = cap.read()
if not ret:
print('frame read failed!')
sys.exit()
gray1 = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY)
# np.zeros_like = 똑같은 크기와 타입이지만 0으로 초기화한 값
hsv = np.zeros_like(frame1)
# hsv에서 s에 해당하는건 255
hsv[..., 1] = 255
while True:
ret, frame2 = cap.read()
if not ret:
print('frame read failed!')
sys.exit()
gray2 = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)
flow = cv2.calcOpticalFlowFarneback(gray1, gray2, None, 0.5, 3, 13, 3, 5, 1.1, 0)
'''
# 파라미터 값을 잘 줘야함(사용하기가 어려움...)
cv2.calcOpticalFlowFarneback(prev, next, flow, pyr_scale, levels, winsize,
iterations, poly_n, poly_sigma, flags) -> flow
flow: 계산된 optical_flow, shape=(h, w, 2)
'''
# 모션벡터의 x 성분 = flow[..., 0] h, w, x
# 모션벡터의 y 성분 = flow[..., 1] h, w, y
# mag, ang 두 좌표 벡터의 크기와 각도(방향정보)
mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1])
# hsv[..., 0] == h
# hsv[..., 2] == v
hsv[..., 0] = ang*180/np.pi/2
hsv[..., 2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)
bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
cv2.imshow('frame', frame2)
cv2.imshow('flow', bgr)
cv2.imshow('frame2', draw_flow(gray2, flow))
if cv2.waitKey(20) == 27:
break
# 이렇게 안하면 특정 위치에서 값을 계속 가지고있는데..왜?
gray1 = gray2
728x90
'OpenCV > OpenCV-Chapter' 카테고리의 다른 글
CH10 OpenCV-Python 추적(Mean Shift, Cam Shift) (0) | 2021.12.25 |
---|---|
CH10 OpenCV-Python 배경차분(MOG) (1) | 2021.12.25 |
CH10 OpenCV-Python 객체 추적(이동 평균 배경) Mean shift (0) | 2021.12.25 |
CH10 OpenCV-Python 객체 추적(배경차분) (2) | 2021.12.25 |
CH09 OpenCV-Python 스티칭 Stitching(PANORAMA) (0) | 2021.12.25 |
댓글