0x00. 平均值法
通過計算兩幀影象之間變化了的畫素點佔的百分比,來確定影象中是否有動作產生。
這裡主要用到 Absdiff 函式,比較兩幀影象之間有差異的點,當然需要將影象進行一些處理,例如平滑處理,灰度化處理,二值化處理,經過處理之後的二值影象上的點將更有效。
程式碼示例:
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 |
import cv2.cv as cv capture=cv.CaptureFromCAM(0) frame1 = cv.QueryFrame(capture) frame1gray = cv.CreateMat(frame1.height, frame1.width, cv.CV_8U) cv.CvtColor(frame1, frame1gray, cv.CV_RGB2GRAY) res = cv.CreateMat(frame1.height, frame1.width, cv.CV_8U) frame2gray = cv.CreateMat(frame1.height, frame1.width, cv.CV_8U) w= frame2gray.width h= frame2gray.height nb_pixels = frame2gray.width * frame2gray.height while True: frame2 = cv.QueryFrame(capture) cv.CvtColor(frame2, frame2gray, cv.CV_RGB2GRAY) cv.AbsDiff(frame1gray, frame2gray, res) cv.ShowImage("After AbsDiff", res) cv.Smooth(res, res, cv.CV_BLUR, 5,5) element = cv.CreateStructuringElementEx(5*2+1, 5*2+1, 5, 5, cv.CV_SHAPE_RECT) cv.MorphologyEx(res, res, None, None, cv.CV_MOP_OPEN) cv.MorphologyEx(res, res, None, None, cv.CV_MOP_CLOSE) cv.Threshold(res, res, 10, 255, cv.CV_THRESH_BINARY_INV) cv.ShowImage("Image", frame2) cv.ShowImage("Res", res) #----------- nb=0 for y in range(h): for x in range(w): if res[y,x] == 0.0: nb += 1 avg = (nb*100.0)/nb_pixels #print "Average: ",avg, "%r", if avg >= 5: print "Something is moving !" #----------- cv.Copy(frame2gray, frame1gray) c=cv.WaitKey(1) if c==27: #Break if user enters 'Esc'. break |
0x01. 背景建模與前景檢測
背景建模也是檢測運動物體的一種辦法,下面是程式碼示例:
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 |
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)) gray = cv.CreateImage((width,height), cv.IPL_DEPTH_8U, 1) background = cv.CreateMat(height, width, cv.CV_32F) backImage = cv.CreateImage((width,height), cv.IPL_DEPTH_8U, 1) foreground = cv.CreateImage((width,height), cv.IPL_DEPTH_8U, 1) output = cv.CreateImage((width,height), 8, 1) begin = True threshold = 10 while True: frame = cv.QueryFrame( capture ) cv.CvtColor(frame, gray, cv.CV_BGR2GRAY) if begin: cv.Convert(gray, background) #Convert gray into background format begin = False cv.Convert(background, backImage) #convert existing background to backImage cv.AbsDiff(backImage, gray, foreground) #Absdiff to get differences cv.Threshold(foreground, output, threshold, 255, cv.CV_THRESH_BINARY_INV) cv.Acc(foreground, background,output) #Accumulate to background cv.ShowImage("Output", output) cv.ShowImage("Gray", gray) c=cv.WaitKey(1) if c==27: #Break if user enters 'Esc'. break |
0x02. 我的方法
上面的幾種辦法我都試了下,基本上能識別出運動的物體,但是發現總是有點瑕疵,所以又比對了幾種別人的方案,然後合成了一個自己的方案:
具體處理思路:
- 對兩幀影象做一個absdiff得到新影象。
- 對新影象做灰度和二值化處理。
- 使用findContours函式獲取二值化處理之後的圖片中的輪廓。
- 使用contourArea()過濾掉自己不想要的面積範圍的輪廓。
這個辦法基本上能夠檢測出物體的影象中物體的移動,而且我覺得通過設定contourArea()函式的過濾範圍,可以檢測距離攝像頭不同距離範圍的運動物體。
以下是程式碼示例:
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 |
#!usr/bin/env python #coding=utf-8 import cv2 import numpy as np camera = cv2.VideoCapture(0) width = int(camera.get(3)) height = int(camera.get(4)) firstFrame = None while True: (grabbed, frame) = camera.read() gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (21, 21), 0) if firstFrame is None: firstFrame = gray continue frameDelta = cv2.absdiff(firstFrame, gray) thresh = cv2.threshold(frameDelta, 25, 255, cv2.THRESH_BINARY)[1] # thresh = cv2.adaptiveThreshold(frameDelta,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\ # cv2.THRESH_BINARY,11,2) # thresh = cv2.adaptiveThreshold(frameDelta,255,cv2.ADAPTIVE_THRESH_MEAN_C,\ # cv2.THRESH_BINARY,11,2) thresh = cv2.dilate(thresh, None, iterations=2) (_, cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE) for c in cnts: if cv2.contourArea(c) < 10000: continue (x, y, w, h) = cv2.boundingRect(c) cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2) cv2.imshow("Security Feed", frame) firstFrame = gray.copy() camera.release() cv2.destroyAllWindows() |