Optical Flow
จาก Morange Wiki
เนื้อหา
Optical Flow
วัตถุประสงค์
- เรียนรู้เกี่ยวกับการใช้งานและแนวคิดของ Optical Flow และวิธีการประมาณการโดย Lucas-Kanade
- ใช้ฟังก์ชั่น cv2.calcOpticalFlowPyrLK() เพื่อติิดตามจุดต่างๆในวิดีโอ
ทฤษฏี
- Optical flow นั้นคือ pattern ของ apparent motion โดยจะมี 2 ส่วนเฟรมที่ติดต่อกัน จะเกิดจากการเคลื่อนที่ของวัตถุหรือกล้อง เรียกว่า 2D Vector โดยที่อีก vector นึง จะแสดงเป็นการเคลื่อนไหวของจุดจากเฟรมแรก และ เฟรมที่สอง
- ในการพิจารณา (Consider) พิกเซล I(x,y,t) และจะมีการเคลื่อนที่เป็นระยะทางเรียกค่านี้คือ (dx,dy) ในเฟรมต่อไป โดยจะมีสูตรคือ I(x , y , t) = I( x + dx , y + dy , t + dt)
- และหลังจากนั้นใช้ชุดเวลาเทย์เลอร์เข้ามาช่วยโดยหาจากด้าน ขวามือ และลบด้วยสูตรปกติและหารด้วย DT เพื่อหาค่าสมการต่อไปนี้ fxu + fyv + ft=0
- เมื่อ
- ข้านบนนี้จะเรียกว่าการไหลของ Optical โดนจะสามารถหาค่า FX และ การไล่ระดับสีของภาพได้ในทำนองเดียวกันกัับ Gradient ไปตามเวลา แต่ (U,V) เราจะไม่สามารถแก้ปัญหานี้อย่างใดอย่างหนั่งกับสมการสองตัวแปรที่ไม่รู้จักได้ โดยมีวิธีแก้ไขหลากหลายวิธีมากเกี่ยวกับสิ่งนี้ โดยหนึ่งในนั้นคือ Lucas-Kanade
Lucas-Kanade method
- โดยเราจะสามารถเห็นสมมติฐานก่อนว่าทุกๆพิกเซลที่อยู่ใกล้เคียง จะเคลื่อนไหวคล้ายกัน โดยวิธีของ Lucas-Kanade นั้นจะใช้ patch ขนาดเท่ากับ 3x3 รอบจุด จะสามารถเห็นทั้งหมด 9 จุดที่มีการเคลื่อนไหวเหมือนกัน เราสามารถหา (fx , fy , ft) สำหรับทั้ง 9 จุดนั้น มีสองตัวแปรที่ไม่รู้จักซึ่งมีมากกว่ากำหนด โดยทางออกที่ดีที่สุดนั้นจะได้รับรู้ด้วยวิธีที่หาค่าน้องของตาราง โดยด้านล่างนี้จะเป็นทางออกสุดท้ายที่เป็นสองสมการ สองปัญหาที่ไม่รู้จักและการแก้ปัญหาจะได้รับการแก้ไขด้วยวิธีข้างล่างนี้ ด้วยสูตร
Lucas-Kanade Optical Flow in OpenCV
- ใน OpenCV นั้นมีฟังก์ชั่นที่เข้ามาช่วยการใช้ Lucas-Kanade Optical Flow คือฟังก์ชั่นที่ชื่อว่า cv2.calcOpticalFlowPyrLK(). ต่อไป จะเป็นการสร้างตัวอย่างการใช้งานแบบง่าๆ โดยมีฟังก์ชั้นเพื่อตัดสินใจ (decide) เราจะใช้ฟังก์ชั่น cv2.goodFeaturesToTrack()
CODE EXAMPLE
import numpy as np import cv2 cap = cv2.VideoCapture('slow.flv') # params for ShiTomasi corner detection feature_params = dict( maxCorners = 100, qualityLevel = 0.3, minDistance = 7, blockSize = 7 ) # Parameters for lucas kanade optical flow lk_params = dict( winSize = (15,15), maxLevel = 2, criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03)) # Create some random colors color = np.random.randint(0,255,(100,3)) # Take first frame and find corners in it ret, old_frame = cap.read() old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY) p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, **feature_params) # Create a mask image for drawing purposes mask = np.zeros_like(old_frame) while(1): ret,frame = cap.read() frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # calculate optical flow p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params) # Select good points good_new = p1[st==1] good_old = p0[st==1] # draw the tracks for i,(new,old) in enumerate(zip(good_new,good_old)): a,b = new.ravel() c,d = old.ravel() mask = cv2.line(mask, (a,b),(c,d), color[i].tolist(), 2) frame = cv2.circle(frame,(a,b),5,color[i].tolist(),-1) img = cv2.add(frame,mask) cv2.imshow('frame',img) k = cv2.waitKey(30) & 0xff if k == 27: break # Now update the previous frame and previous points old_gray = frame_gray.copy() p0 = good_new.reshape(-1,1,2) cv2.destroyAllWindows() cap.release()
Result
Dense Optical Flow in OpenCV
- ใน Method ของ Lucas-Kanade นั้น จะคำนวณการไหลของ Optical flow สำหรับกลุ่มหรือพวกที่มีคุณลักษณะที่เบาบาง โดย OpenCV จะมีขั้นตอนและวิธีการที่จะหาการไหลของแสงหนาแน่น โดยจะคำนวณการไหลของแสงสำหรับจุดที่อยู่ในกรอบ โดนจะขึ้นอยู่กับขั้นตอนของ Gunner Farneback's algorithm โดวจะอธิบายในกรอบการเคลื่อนไหวและประเมินจากการขยายตัวของพหุนาม)
- ในด้านล่างนี้จะเป็นตัวอย่างเพื่อให้เห็นถึงวิธีการหาการไหลของแสงหนาแน่น
Code Example
import cv2 import numpy as np cap = cv2.VideoCapture(0) ret, frame1 = cap.read() prvs = cv2.cvtColor(frame1,cv2.COLOR_BGR2GRAY) hsv = np.zeros_like(frame1) hsv[...,1] = 255 while(1): ret, frame2 = cap.read() next = cv2.cvtColor(frame2,cv2.COLOR_BGR2GRAY) flow = cv2.calcOpticalFlowFarneback(prvs,next, None, 0.5, 3, 15, 3, 5, 1.2, 0) mag, ang = cv2.cartToPolar(flow[...,0], flow[...,1]) 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('frame2',bgr) k = cv2.waitKey(30) & 0xff if k == 27: break elif k == ord('s'): cv2.imwrite('opticalfb.png',frame2) cv2.imwrite('opticalhsv.png',bgr) prvs = next cap.release() cv2.destroyAllWindows()