1. 程式人生 > >Python-OpenCV 處理視訊(三)(四)(五): 標記運動軌跡 運動檢測 運動方向判斷

Python-OpenCV 處理視訊(三)(四)(五): 標記運動軌跡 運動檢測 運動方向判斷

0x00. 光流

光流是進行視訊中運動物件軌跡標記的一種很常用的方法,在OpenCV中實現光流也很容易。

CalcOpticalFlowPyrLK 函式計算一個稀疏特徵集的光流,使用金字塔中的迭代 Lucas-Kanade 方法。

簡單的實現流程:

  1. 載入一段視訊。

  2. 呼叫GoodFeaturesToTrack函式尋找興趣點。

  3. 呼叫CalcOpticalFlowPyrLK函式計算出兩幀影象中興趣點的移動情況。

  4. 刪除未移動的興趣點。

  5. 在兩次移動的點之間繪製一條線段。

程式碼示例:

 
  1. import cv2.cv as cv

  2.  
  3. capture = cv.CaptureFromFile('img/myvideo.avi')

  4.  
  5. nbFrames = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_COUNT))

  6. fps = cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FPS)

  7. wait = int(1/fps * 1000/1)

  8. width = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH))

  9. height = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_HEIGHT))

  10.  
  11. prev_gray = cv.CreateImage((width,height), 8, 1) #Will hold the frame at t-1

  12. gray = cv.CreateImage((width,height), 8, 1) # Will hold the current frame

  13.  
  14. prevPyr = cv.CreateImage((height / 3, width + 8), 8, cv.CV_8UC1) #Will hold the pyr frame at t-1

  15. currPyr = cv.CreateImage((height / 3, width + 8), 8, cv.CV_8UC1) # idem at t

  16.  
  17. max_count = 500

  18. qLevel= 0.01

  19. minDist = 10

  20. prev_points = [] #Points at t-1

  21. curr_points = [] #Points at t

  22. lines=[] #To keep all the lines overtime

  23.  
  24. for f in xrange( nbFrames ):

  25.  
  26. frame = cv.QueryFrame(capture) #Take a frame of the video

  27.  
  28. cv.CvtColor(frame, gray, cv.CV_BGR2GRAY) #Convert to gray

  29. output = cv.CloneImage(frame)

  30.  
  31. prev_points = cv.GoodFeaturesToTrack(gray, None, None, max_count, qLevel, minDist) #Find points on the image

  32.  
  33. #Calculate the movement using the previous and the current frame using the previous points

  34. 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)

  35.  
  36.  
  37. #If points status are ok and distance not negligible keep the point

  38. k = 0

  39. for i in range(len(curr_points)):

  40. nb = abs( int(prev_points[i][0])-int(curr_points[i][0]) ) + abs( int(prev_points[i][1])-int(curr_points[i][1]) )

  41. if status[i] and nb > 2 :

  42. prev_points[k] = prev_points[i]

  43. curr_points[k] = curr_points[i]

  44. k += 1

  45.  
  46. prev_points = prev_points[:k]

  47. curr_points = curr_points[:k]

  48. #At the end only interesting points are kept

  49.  
  50. #Draw all the previously kept lines otherwise they would be lost the next frame

  51. for (pt1, pt2) in lines:

  52. cv.Line(frame, pt1, pt2, (255,255,255))

  53.  
  54. #Draw the lines between each points at t-1 and t

  55. for prevpoint, point in zip(prev_points,curr_points):

  56. prevpoint = (int(prevpoint[0]),int(prevpoint[1]))

  57. cv.Circle(frame, prevpoint, 15, 0)

  58. point = (int(point[0]),int(point[1]))

  59. cv.Circle(frame, point, 3, 255)

  60. cv.Line(frame, prevpoint, point, (255,255,255))

  61. lines.append((prevpoint,point)) #Append current lines to the lines list

  62.  
  63.  
  64. cv.Copy(gray, prev_gray) #Put the current frame prev_gray

  65. prev_points = curr_points

  66.  
  67. cv.ShowImage("The Video", frame)

  68. #cv.WriteFrame(writer, frame)

  69. cv.WaitKey(wait)

直接呼叫攝像頭使用該方法:

 
  1. import cv2.cv as cv

  2.  
  3. capture = cv.CaptureFromCAM(0)

  4.  
  5. width = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH))

  6. height = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_HEIGHT))

  7.  
  8. prev_gray = cv.CreateImage((width,height), 8, 1)

  9. gray = cv.CreateImage((width,height), 8, 1)

  10.  
  11. prevPyr = cv.CreateImage((height / 3, width + 8), 8, cv.CV_8UC1) #Will hold the pyr frame at t-1

  12. currPyr = cv.CreateImage((height / 3, width + 8), 8, cv.CV_8UC1) # idem at t

  13.  
  14. max_count = 500

  15. qLevel= 0.01

  16. minDist = 10

  17. prev_points = [] #Points at t-1

  18. curr_points = [] #Points at t

  19. lines=[] #To keep all the lines overtime

  20.  
  21. while True:

  22. frame = cv.QueryFrame(capture)

  23. cv.CvtColor(frame, gray, cv.CV_BGR2GRAY) #Convert to gray

  24. output = cv.CloneImage(frame)

  25.  
  26. prev_points = cv.GoodFeaturesToTrack(gray, None, None, max_count, qLevel, minDist)

  27. 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)

  28.  
  29. #If points status are ok and distance not negligible keep the point

  30. k = 0

  31. for i in range(len(curr_points)):

  32. nb = abs( int(prev_points[i][0])-int(curr_points[i][0]) ) + abs( int(prev_points[i][1])-int(curr_points[i][1]) )

  33. if status[i] and nb > 2 :

  34. prev_points[k] = prev_points[i]

  35. curr_points[k] = curr_points[i]

  36. k += 1

  37.  
  38. prev_points = prev_points[:k]

  39. curr_points = curr_points[:k]

  40. #At the end only interesting points are kept

  41.  
  42. #Draw all the previously kept lines otherwise they would be lost the next frame

  43. for (pt1, pt2) in lines:

  44. cv.Line(frame, pt1, pt2, (255,255,255))

  45.  
  46. #Draw the lines between each points at t-1 and t

  47. for prevpoint, point in zip(prev_points,curr_points):

  48. prevpoint = (int(prevpoint[0]),int(prevpoint[1]))

  49. cv.Circle(frame, prevpoint, 15, 0)

  50. point = (int(point[0]),int(point[1]))

  51. cv.Circle(frame, point, 3, 255)

  52. cv.Line(frame, prevpoint, point, (255,255,255))

  53. lines.append((prevpoint,point)) #Append current lines to the lines list

  54.  
  55.  
  56. cv.Copy(gray, prev_gray) #Put the current frame prev_gray

  57. prev_points = curr_points

  58.  
  59. cv.ShowImage("The Video", frame)

  60. #cv.WriteFrame(writer, frame)

  61. c = cv.WaitKey(1)

  62. if c == 27: #Esc on Windows

  63. break

0x01. 尋找最大特徵值的角點

cv.GoodFeaturesToTrack 函式可以檢測出影象中最大特徵值的角點,使用這個函式可以對影象中的特徵點進行跟蹤,從而繪製出運動軌跡。

直接載入視訊:

 
  1. import cv2.cv as cv

  2.  
  3. capture = cv.CaptureFromFile('img/myvideo.avi')

  4.  
  5. #-- Informations about the video --

  6. nbFrames = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_COUNT))

  7. fps = cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FPS)

  8. wait = int(1/fps * 1000/1)

  9. width = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH))

  10. height = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_HEIGHT))

  11. #For recording

  12. #codec = cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FOURCC)

  13. #writer=cv.CreateVideoWriter("img/output.avi", int(codec), int(fps), (width,height), 1) #Create writer with same parameters

  14. #----------------------------------

  15.  
  16. prev_gray = cv.CreateImage((width,height), 8, 1) #Will hold the frame at t-1

  17. gray = cv.CreateImage((width,height), 8, 1) # Will hold the current frame

  18.  
  19. output = cv.CreateImage((width,height), 8, 3)

  20.  
  21. prevPyr = cv.CreateImage((height / 3, width + 8), 8, cv.CV_8UC1)

  22. currPyr = cv.CreateImage((height / 3, width + 8), 8, cv.CV_8UC1)

  23.  
  24. max_count = 500

  25. qLevel= 0.01

  26. minDist = 10

  27.  
  28. begin = True

  29.  
  30. initial = []

  31. features = []

  32. prev_points = []

  33. curr_points = []

  34.  
  35. for f in xrange( nbFrames ):

  36.  
  37. frame = cv.QueryFrame(capture)

  38.  
  39. cv.CvtColor(frame, gray, cv.CV_BGR2GRAY) #Convert to gray

  40. cv.Copy(frame, output)

  41.  
  42.  
  43. if (len(prev_points) <= 10): #Try to get more points

  44. #Detect points on the image

  45. features = cv.GoodFeaturesToTrack(gray, None, None, max_count, qLevel, minDist)

  46. prev_points.extend(features) #Add the new points to list

  47. initial.extend(features) #Idem

  48.  
  49. if begin:

  50. cv.Copy(gray, prev_gray) #Now we have two frames to compare

  51. begin = False

  52.  
  53. #Compute movement

  54. 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)

  55.  
  56. #If points status are ok and distance not negligible keep the point

  57. k = 0

  58. for i in range(len(curr_points)):

  59. nb = abs( int(prev_points[i][0])-int(curr_points[i][0]) ) + abs( int(prev_points[i][1])-int(curr_points[i][1]) )

  60. if status[i] and nb > 2 :

  61. initial[k] = initial[i]

  62. curr_points[k] = curr_points[i]

  63. k += 1

  64.  
  65. curr_points = curr_points[:k]

  66. initial = initial[:k]

  67. #At the end only interesting points are kept

  68.  
  69. #Draw the line between the first position of a point and the

  70. #last recorded position of the same point

  71. for i in range(len(curr_points)):

  72. cv.Line(output, (int(initial[i][0]),int(initial[i][1])), (int(curr_points[i][0]),int(curr_points[i][1])), (255,255,255))

  73. cv.Circle(output, (int(curr_points[i][0]),int(curr_points[i][1])), 3, (255,255,255))

  74.  
  75.  
  76. cv.Copy(gray, prev_gray)

  77. prev_points = curr_points

  78.  
  79.  
  80. cv.ShowImage("The Video", output)

  81. cv.WriteFrame(writer, output)

  82. cv.WaitKey(wait)

呼叫攝像頭繪製:

 
  1. import cv2.cv as cv

  2.  
  3. capture = cv.CaptureFromCAM(0)

  4.  
  5. width = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH))

  6. height = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_HEIGHT))

  7.  
  8. prev_gray = cv.CreateImage((width,height), 8, 1) #Will hold the frame at t-1

  9. gray = cv.CreateImage((width,height), 8, 1) # Will hold the current frame

  10.  
  11. output = cv.CreateImage((width,height), 8, 3)

  12.  
  13. prevPyr = cv.CreateImage((height / 3, width + 8), 8, cv.CV_8UC1)

  14. currPyr = cv.CreateImage((height / 3, width + 8), 8, cv.CV_8UC1)

  15.  
  16. max_count = 500

  17. qLevel= 0.01

  18. minDist = 10

  19.  
  20. begin = True

  21.  
  22. initial = []

  23. features = []

  24. prev_points = []

  25. curr_points = []

  26.  
  27. while True:

  28.  
  29. frame = cv.QueryFrame(capture)

  30.  
  31. cv.CvtColor(frame, gray, cv.CV_BGR2GRAY) #Convert to gray

  32. cv.Copy(frame, output)

  33.  
  34.  
  35. if (len(prev_points) <= 10): #Try to get more points

  36. #Detect points on the image

  37. features = cv.GoodFeaturesToTrack(gray, None, None, max_count, qLevel, minDist)

  38. prev_points.extend(features) #Add the new points to list

  39. initial.extend(features) #Idem

  40.  
  41. if begin:

  42. cv.Copy(gray, prev_gray) #Now we have two frames to compare

  43. begin = False

  44.  
  45. #Compute movement

  46. 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)

  47.  
  48. #If points status are ok and distance not negligible keep the point

  49. k = 0

  50. for i in range(len(curr_points)):

  51. nb = abs( int(prev_points[i][0])-int(curr_points[i][0]) ) + abs( int(prev_points[i][1])-int(curr_points[i][1]) )

  52. if status[i] and nb > 2 :

  53. initial[k] = initial[i]

  54. curr_points[k] = curr_points[i]

  55. k += 1

  56.  
  57. curr_points = curr_points[:k]

  58. initial = initial[:k]

  59. for i in range(len(curr_points)):

  60. cv.Line(output, (int(initial[i][0]),int(initial[i][1])), (int(curr_points[i][0]),int(curr_points[i][1])), (255,255,255))

  61. cv.Circle(output, (int(curr_points[i][0]),int(curr_points[i][1])), 3, (255,255,255))

  62.  
  63.  
  64. cv.Copy(gray, prev_gray)

  65. prev_points = curr_points

  66.  
  67. cv.ShowImage("The Video", output)

  68. c = cv.WaitKey(1)

  69. if c == 27: #Esc on Windows

  70. break

 
  1.  
  2.  
 
  1.  
  2.  
 
  1.  
  2.  
————————————————————————————————————分割線來了————————————————————————————————————
 
 
 

0x00. 平均值法

通過計算兩幀影象之間變化了的畫素點佔的百分比,來確定影象中是否有動作產生。

這裡主要用到 Absdiff 函式,比較兩幀影象之間有差異的點,當然需要將影象進行一些處理,例如平滑處理,灰度化處理,二值化處理,經過處理之後的二值影象上的點將更有效。

程式碼示例:

 
  1. import cv2.cv as cv

  2.  
  3. capture=cv.CaptureFromCAM(0)

  4.  
  5. frame1 = cv.QueryFrame(capture)

  6. frame1gray = cv.CreateMat(frame1.height, frame1.width, cv.CV_8U)

  7. cv.CvtColor(frame1, frame1gray, cv.CV_RGB2GRAY)

  8.  
  9. res = cv.CreateMat(frame1.height, frame1.width, cv.CV_8U)

  10.  
  11. frame2gray = cv.CreateMat(frame1.height, frame1.width, cv.CV_8U)

  12.  
  13. w= frame2gray.width

  14. h= frame2gray.height

  15. nb_pixels = frame2gray.width * frame2gray.height

  16.  
  17. while True:

  18. frame2 = cv.QueryFrame(capture)

  19. cv.CvtColor(frame2, frame2gray, cv.CV_RGB2GRAY)

  20.  
  21. cv.AbsDiff(frame1gray, frame2gray, res)

  22. cv.ShowImage("After AbsDiff", res)

  23.  
  24. cv.Smooth(res, res, cv.CV_BLUR, 5,5)

  25. element = cv.CreateStructuringElementEx(5*2+1, 5*2+1, 5, 5, cv.CV_SHAPE_RECT)

  26. cv.MorphologyEx(res, res, None, None, cv.CV_MOP_OPEN)

  27. cv.MorphologyEx(res, res, None, None, cv.CV_MOP_CLOSE)

  28. cv.Threshold(res, res, 10, 255, cv.CV_THRESH_BINARY_INV)

  29.  
  30. cv.ShowImage("Image", frame2)

  31. cv.ShowImage("Res", res)

  32.  
  33. #-----------

  34. nb=0

  35. for y in range(h):

  36. for x in range(w):

  37. if res[y,x] == 0.0:

  38. nb += 1

  39. avg = (nb*100.0)/nb_pixels

  40. #print "Average: ",avg, "%\r",

  41. if avg >= 5:

  42. print "Something is moving !"

  43. #-----------

  44.  
  45.  
  46. cv.Copy(frame2gray, frame1gray)

  47. c=cv.WaitKey(1)

  48. if c==27: #Break if user enters 'Esc'.

  49. break

0x01. 背景建模與前景檢測

背景建模也是檢測運動物體的一種辦法,下面是程式碼示例:

 
  1. import cv2.cv as cv

  2.  
  3. capture = cv.CaptureFromCAM(0)

  4. width = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH))

  5. height = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_HEIGHT))

  6.  
  7. gray = cv.CreateImage((width,height), cv.IPL_DEPTH_8U, 1)

  8.  
  9. background = cv.CreateMat(height, width, cv.CV_32F)

  10. backImage = cv.CreateImage((width,height), cv.IPL_DEPTH_8U, 1)

  11. foreground = cv.CreateImage((width,height), cv.IPL_DEPTH_8U, 1)

  12. output = cv.CreateImage((width,height), 8, 1)

  13.  
  14. begin = True

  15. threshold = 10

  16.  
  17. while True:

  18. frame = cv.QueryFrame( capture )

  19.  
  20. cv.CvtColor(frame, gray, cv.CV_BGR2GRAY)

  21.  
  22. if begin:

  23. cv.Convert(gray, background) #Convert gray into background format

  24. begin = False

  25.  
  26. cv.Convert(background, backImage) #convert existing background to backImage

  27.  
  28. cv.AbsDiff(backImage, gray, foreground) #Absdiff to get differences

  29.  
  30. cv.Threshold(foreground, output, threshold, 255, cv.CV_THRESH_BINARY_INV)

  31.  
  32. cv.Acc(foreground, background,output) #Accumulate to background

  33.  
  34. cv.ShowImage("Output", output)

  35. cv.ShowImage("Gray", gray)

  36. c=cv.WaitKey(1)

  37. if c==27: #Break if user enters 'Esc'.

  38. break

0x02. 我的方法

上面的幾種辦法我都試了下,基本上能識別出運動的物體,但是發現總是有點瑕疵,所以又比對了幾種別人的方案,然後合成了一個自己的方案:

具體處理思路:

  • 對兩幀影象做一個absdiff得到新影象。

  • 對新影象做灰度和二值化處理。

  • 使用findContours函式獲取二值化處理之後的圖片中的輪廓。

  • 使用contourArea()過濾掉自己不想要的面積範圍的輪廓。

這個辦法基本上能夠檢測出物體的影象中物體的移動,而且我覺得通過設定contourArea()函式的過濾範圍,可以檢測距離攝像頭不同距離範圍的運動物體。

以下是程式碼示例:

 
  1. #!usr/bin/env python

  2. #coding=utf-8

  3.  
  4. import cv2

  5. import numpy as np

  6.  
  7. camera = cv2.VideoCapture(0)

  8. width = int(camera.get(3))

  9. height = int(camera.get(4))

  10.  
  11. firstFrame = None

  12.  
  13. while True:

  14. (grabbed, frame) = camera.read()

  15. gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

  16. gray = cv2.GaussianBlur(gray, (21, 21), 0)

  17.  
  18. if firstFrame is None:

  19. firstFrame = gray

  20. continue

  21.  
  22. frameDelta = cv2.absdiff(firstFrame, gray)

  23. thresh = cv2.threshold(frameDelta, 25, 255, cv2.THRESH_BINARY)[1]

  24. # thresh = cv2.adaptiveThreshold(frameDelta,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\

  25. # cv2.THRESH_BINARY,11,2)

  26. # thresh = cv2.adaptiveThreshold(frameDelta,255,cv2.ADAPTIVE_THRESH_MEAN_C,\

  27. # cv2.THRESH_BINARY,11,2)

  28. thresh = cv2.dilate(thresh, None, iterations=2)

  29. (_, cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)

  30. for c in cnts:

  31. if cv2.contourArea(c) < 10000:

  32. continue

  33. (x, y, w, h) = cv2.boundingRect(c)

  34.  
  35. cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)

  36.  
  37. cv2.imshow("Security Feed", frame)

  38.  
  39. firstFrame = gray.copy()

  40. camera.release()

  41. cv2.destroyAllWindows()

 

 
 
——————————————————————————————————汪星人說這是分割線——————————————————————————————————
 
 
 
 

注意,我使用的OpenCV 版本是 3.0, 低版本就有可能出現第一條評論裡的報錯

在檢測出運動的物體之後,我還需要知道運動的方向,使用了上一節中的辦法檢測運動我發現很難去計算運動方向,開始考慮通過計算輪廓的中點的變化來實現,但是因為每次檢測出得輪廓的數量不穩定,所以這個辦法會讓誤差不可控。

這時我發現了 goodFeaturesToTrack 函式,簡直是救了我,goodFeaturesToTrack 函式可以獲取影象中的最大特徵值的角點,以下是我的思路:

Tips: 看程式碼之前請先看看我下面寫的實現思路,另外還有程式碼裡的註釋也對於理解程式碼會有所幫助

  • 對兩幀影象做一個 absdiff 得到新影象。

  • 對新影象做灰度和二值化處理。

  • 使用 goodFeaturesToTrack 函式得到最大特徵值的角點。

  • 計算角點的平均點,寫入佇列。(通過計算平均點的解決辦法類似物理中剛體問題抽象成質點解決的思路)

  • 維護一個長度為 10 的佇列,佇列滿時計算佇列中資料的增減情況,來確定運動方向。

程式碼示例(只實現了左右移動的判斷):

 
  1. #!usr/bin/env python

  2. #coding=utf-8

  3.  
  4. import cv2

  5. import numpy as np

  6. import Queue

  7.  
  8. camera = cv2.VideoCapture(0)

  9. width = int(camera.get(3))

  10. height = int(camera.get(4))

  11.  
  12. firstFrame = None

  13. lastDec = None

  14. firstThresh = None

  15.  
  16. feature_params = dict( maxCorners = 100,

  17. qualityLevel = 0.3,

  18. minDistance = 7,

  19. blockSize = 7 )

  20.  
  21. lk_params = dict( winSize = (15,15),

  22. maxLevel = 2,

  23. criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))

  24.  
  25. color = np.random.randint(0,255,(100,3))

  26. num = 0

  27.  
  28. q_x = Queue.Queue(maxsize = 10)

  29. q_y = Queue.Queue(maxsize = 10)

  30.  
  31. while True:

  32. (grabbed, frame) = camera.read()

  33. gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

  34. gray = cv2.GaussianBlur(gray, (21, 21), 0)

  35.  
  36. if firstFrame is None:

  37. firstFrame = gray

  38. continue

  39.  
  40. # 對兩幀影象進行 absdiff 操作

  41. frameDelta = cv2.absdiff(firstFrame, gray)

  42. # diff 之後的影象進行二值化

  43. thresh = cv2.threshold(frameDelta, 25, 255, cv2.THRESH_BINARY)[1]

  44. # 下面的是幾種不同的二值化的方法,感覺對我來說效果都差不多

  45. # thresh = cv2.adaptiveThreshold(frameDelta,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\

  46. # cv2.THRESH_BINARY,11,2)

  47. # thresh = cv2.adaptiveThreshold(frameDelta,255,cv2.ADAPTIVE_THRESH_MEAN_C,\

  48. # cv2.THRESH_BINARY,11,2)

  49. thresh = cv2.dilate(thresh, None, iterations=2)

  50. # 識別角點

  51. p0 = cv2.goodFeaturesToTrack(thresh, mask = None, **feature_params)

  52. if p0 is not None:

  53. x_sum = 0

  54. y_sum = 0

  55. for i, old in enumerate(p0):

  56. x, y = old.ravel()

  57. x_sum += x

  58. y_sum += y

  59. # 計算出所有角點的平均值

  60. x_avg = x_sum / len(p0)

  61. y_avg = y_sum / len(p0)

  62.  
  63. # 寫入固定長度的佇列

  64. if q_x.full():

  65. # 如果佇列滿了,就計算這個佇列中元素的增減情況

  66. qx_list = list(q_x.queue)

  67. key = 0

  68. diffx_sum = 0

  69. for item_x in qx_list:

  70. key +=1

  71. if key < 10:

  72. # 下一個元素減去上一個元素

  73. diff_x = item_x - qx_list[key]

  74. diffx_sum += diff_x

  75. # 加和小於0,表明佇列中的元素在遞增

  76. if diffx_sum < 0:

  77. print "left"

  78. cv2.putText(frame, "some coming form left", (100,100), 0, 0.5, (0,0,255),2)

  79. else:

  80. print "right"

  81.  
  82. print x_avg

  83. q_x.get()

  84. q_x.put(x_avg)

  85. cv2.putText(frame, str(x_avg), (300,100), 0, 0.5, (0,0,255),2)

  86. frame = cv2.circle(frame,(int(x_avg),int(y_avg)),5,color[i].tolist(),-1)

  87.  
  88. cv2.imshow("Security Feed", frame)

  89. firstFrame = gray.copy()

  90.  
  91. camera.release()

  92. cv2.destroyAllWindows()

總的來講作為一個影象處理的小白,不斷地折騰和嘗試,終於搞出了自己想要的東西,OpenCV絕對是喜歡折騰的人必要掌握的一個庫了,以後肯定還會繼續研究這塊東西。

 

 
from: https://segmentfault.com/a/1190000003804820
https://segmentfault.com/a/1190000003804835
https://segmentfault.com/a/1190000003804867