0x00. 光流
光流是進行視訊中運動物件軌跡標記的一種很常用的方法,在OpenCV中實現光流也很容易。
CalcOpticalFlowPyrLK
函式計算一個稀疏特徵集的光流,使用金字塔中的迭代 Lucas-Kanade 方法。
簡單的實現流程:
- 載入一段視訊。
- 呼叫
GoodFeaturesToTrack
函式尋找興趣點。 - 呼叫
CalcOpticalFlowPyrLK
函式計算出兩幀影象中興趣點的移動情況。 - 刪除未移動的興趣點。
- 在兩次移動的點之間繪製一條線段。
程式碼示例:
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
import cv2.cv as cv capture = cv.CaptureFromFile('img/myvideo.avi') nbFrames = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_COUNT)) fps = cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FPS) wait = int(1/fps * 1000/1) width = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH)) height = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_HEIGHT)) prev_gray = cv.CreateImage((width,height), 8, 1) #Will hold the frame at t-1 gray = cv.CreateImage((width,height), 8, 1) # Will hold the current frame prevPyr = cv.CreateImage((height / 3, width + 8), 8, cv.CV_8UC1) #Will hold the pyr frame at t-1 currPyr = cv.CreateImage((height / 3, width + 8), 8, cv.CV_8UC1) # idem at t max_count = 500 qLevel= 0.01 minDist = 10 prev_points = [] #Points at t-1 curr_points = [] #Points at t lines=[] #To keep all the lines overtime for f in xrange( nbFrames ): frame = cv.QueryFrame(capture) #Take a frame of the video cv.CvtColor(frame, gray, cv.CV_BGR2GRAY) #Convert to gray output = cv.CloneImage(frame) prev_points = cv.GoodFeaturesToTrack(gray, None, None, max_count, qLevel, minDist) #Find points on the image #Calculate the movement using the previous and the current frame using the previous points curr_points, status, err = cv.CalcOpticalFlowPyrLK(prev_gray, gray, prevPyr, currPyr, prev_points, (10, 10), 3, (cv.CV_TERMCRIT_ITER|cv.CV_TERMCRIT_EPS,20, 0.03), 0) #If points status are ok and distance not negligible keep the point k = 0 for i in range(len(curr_points)): nb = abs( int(prev_points[i][0])-int(curr_points[i][0]) ) + abs( int(prev_points[i][1])-int(curr_points[i][1]) ) if status[i] and nb > 2 : prev_points[k] = prev_points[i] curr_points[k] = curr_points[i] k += 1 prev_points = prev_points[:k] curr_points = curr_points[:k] #At the end only interesting points are kept #Draw all the previously kept lines otherwise they would be lost the next frame for (pt1, pt2) in lines: cv.Line(frame, pt1, pt2, (255,255,255)) #Draw the lines between each points at t-1 and t for prevpoint, point in zip(prev_points,curr_points): prevpoint = (int(prevpoint[0]),int(prevpoint[1])) cv.Circle(frame, prevpoint, 15, 0) point = (int(point[0]),int(point[1])) cv.Circle(frame, point, 3, 255) cv.Line(frame, prevpoint, point, (255,255,255)) lines.append((prevpoint,point)) #Append current lines to the lines list cv.Copy(gray, prev_gray) #Put the current frame prev_gray prev_points = curr_points cv.ShowImage("The Video", frame) #cv.WriteFrame(writer, frame) cv.WaitKey(wait) |
直接呼叫攝像頭使用該方法:
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
import cv2.cv as cv capture = cv.CaptureFromCAM(0) width = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH)) height = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_HEIGHT)) prev_gray = cv.CreateImage((width,height), 8, 1) gray = cv.CreateImage((width,height), 8, 1) prevPyr = cv.CreateImage((height / 3, width + 8), 8, cv.CV_8UC1) #Will hold the pyr frame at t-1 currPyr = cv.CreateImage((height / 3, width + 8), 8, cv.CV_8UC1) # idem at t max_count = 500 qLevel= 0.01 minDist = 10 prev_points = [] #Points at t-1 curr_points = [] #Points at t lines=[] #To keep all the lines overtime while True: frame = cv.QueryFrame(capture) cv.CvtColor(frame, gray, cv.CV_BGR2GRAY) #Convert to gray output = cv.CloneImage(frame) prev_points = cv.GoodFeaturesToTrack(gray, None, None, max_count, qLevel, minDist) curr_points, status, err = cv.CalcOpticalFlowPyrLK(prev_gray, gray, prevPyr, currPyr, prev_points, (10, 10), 3, (cv.CV_TERMCRIT_ITER|cv.CV_TERMCRIT_EPS,20, 0.03), 0) #If points status are ok and distance not negligible keep the point k = 0 for i in range(len(curr_points)): nb = abs( int(prev_points[i][0])-int(curr_points[i][0]) ) + abs( int(prev_points[i][1])-int(curr_points[i][1]) ) if status[i] and nb > 2 : prev_points[k] = prev_points[i] curr_points[k] = curr_points[i] k += 1 prev_points = prev_points[:k] curr_points = curr_points[:k] #At the end only interesting points are kept #Draw all the previously kept lines otherwise they would be lost the next frame for (pt1, pt2) in lines: cv.Line(frame, pt1, pt2, (255,255,255)) #Draw the lines between each points at t-1 and t for prevpoint, point in zip(prev_points,curr_points): prevpoint = (int(prevpoint[0]),int(prevpoint[1])) cv.Circle(frame, prevpoint, 15, 0) point = (int(point[0]),int(point[1])) cv.Circle(frame, point, 3, 255) cv.Line(frame, prevpoint, point, (255,255,255)) lines.append((prevpoint,point)) #Append current lines to the lines list cv.Copy(gray, prev_gray) #Put the current frame prev_gray prev_points = curr_points cv.ShowImage("The Video", frame) #cv.WriteFrame(writer, frame) c = cv.WaitKey(1) if c == 27: #Esc on Windows break |
0x01. 尋找最大特徵值的角點
cv.GoodFeaturesToTrack 函式可以檢測出影象中最大特徵值的角點,使用這個函式可以對影象中的特徵點進行跟蹤,從而繪製出運動軌跡。
直接載入視訊:
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
import cv2.cv as cv capture = cv.CaptureFromFile('img/myvideo.avi') #-- Informations about the video -- nbFrames = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_COUNT)) fps = cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FPS) wait = int(1/fps * 1000/1) width = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH)) height = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_HEIGHT)) #For recording #codec = cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FOURCC) #writer=cv.CreateVideoWriter("img/output.avi", int(codec), int(fps), (width,height), 1) #Create writer with same parameters #---------------------------------- prev_gray = cv.CreateImage((width,height), 8, 1) #Will hold the frame at t-1 gray = cv.CreateImage((width,height), 8, 1) # Will hold the current frame output = cv.CreateImage((width,height), 8, 3) prevPyr = cv.CreateImage((height / 3, width + 8), 8, cv.CV_8UC1) currPyr = cv.CreateImage((height / 3, width + 8), 8, cv.CV_8UC1) max_count = 500 qLevel= 0.01 minDist = 10 begin = True initial = [] features = [] prev_points = [] curr_points = [] for f in xrange( nbFrames ): frame = cv.QueryFrame(capture) cv.CvtColor(frame, gray, cv.CV_BGR2GRAY) #Convert to gray cv.Copy(frame, output) if (len(prev_points) <= 10): #Try to get more points #Detect points on the image features = cv.GoodFeaturesToTrack(gray, None, None, max_count, qLevel, minDist) prev_points.extend(features) #Add the new points to list initial.extend(features) #Idem if begin: cv.Copy(gray, prev_gray) #Now we have two frames to compare begin = False #Compute movement curr_points, status, err = cv.CalcOpticalFlowPyrLK(prev_gray, gray, prevPyr, currPyr, prev_points, (10, 10), 3, (cv.CV_TERMCRIT_ITER|cv.CV_TERMCRIT_EPS,20, 0.03), 0) #If points status are ok and distance not negligible keep the point k = 0 for i in range(len(curr_points)): nb = abs( int(prev_points[i][0])-int(curr_points[i][0]) ) + abs( int(prev_points[i][1])-int(curr_points[i][1]) ) if status[i] and nb > 2 : initial[k] = initial[i] curr_points[k] = curr_points[i] k += 1 curr_points = curr_points[:k] initial = initial[:k] #At the end only interesting points are kept #Draw the line between the first position of a point and the #last recorded position of the same point for i in range(len(curr_points)): cv.Line(output, (int(initial[i][0]),int(initial[i][1])), (int(curr_points[i][0]),int(curr_points[i][1])), (255,255,255)) cv.Circle(output, (int(curr_points[i][0]),int(curr_points[i][1])), 3, (255,255,255)) cv.Copy(gray, prev_gray) prev_points = curr_points cv.ShowImage("The Video", output) cv.WriteFrame(writer, output) cv.WaitKey(wait) |
呼叫攝像頭繪製:
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
import cv2.cv as cv capture = cv.CaptureFromCAM(0) width = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH)) height = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_HEIGHT)) prev_gray = cv.CreateImage((width,height), 8, 1) #Will hold the frame at t-1 gray = cv.CreateImage((width,height), 8, 1) # Will hold the current frame output = cv.CreateImage((width,height), 8, 3) prevPyr = cv.CreateImage((height / 3, width + 8), 8, cv.CV_8UC1) currPyr = cv.CreateImage((height / 3, width + 8), 8, cv.CV_8UC1) max_count = 500 qLevel= 0.01 minDist = 10 begin = True initial = [] features = [] prev_points = [] curr_points = [] while True: frame = cv.QueryFrame(capture) cv.CvtColor(frame, gray, cv.CV_BGR2GRAY) #Convert to gray cv.Copy(frame, output) if (len(prev_points) <= 10): #Try to get more points #Detect points on the image features = cv.GoodFeaturesToTrack(gray, None, None, max_count, qLevel, minDist) prev_points.extend(features) #Add the new points to list initial.extend(features) #Idem if begin: cv.Copy(gray, prev_gray) #Now we have two frames to compare begin = False #Compute movement curr_points, status, err = cv.CalcOpticalFlowPyrLK(prev_gray, gray, prevPyr, currPyr, prev_points, (10, 10), 3, (cv.CV_TERMCRIT_ITER|cv.CV_TERMCRIT_EPS,20, 0.03), 0) #If points status are ok and distance not negligible keep the point k = 0 for i in range(len(curr_points)): nb = abs( int(prev_points[i][0])-int(curr_points[i][0]) ) + abs( int(prev_points[i][1])-int(curr_points[i][1]) ) if status[i] and nb > 2 : initial[k] = initial[i] curr_points[k] = curr_points[i] k += 1 curr_points = curr_points[:k] initial = initial[:k] for i in range(len(curr_points)): cv.Line(output, (int(initial[i][0]),int(initial[i][1])), (int(curr_points[i][0]),int(curr_points[i][1])), (255,255,255)) cv.Circle(output, (int(curr_points[i][0]),int(curr_points[i][1])), 3, (255,255,255)) cv.Copy(gray, prev_gray) prev_points = curr_points cv.ShowImage("The Video", output) c = cv.WaitKey(1) if c == 27: #Esc on Windows break |