1. 获取前景和背景算法
1.1. 基本运动物体检测
import cv2
OPENCV_MAJOR_VERSION = int(cv2.__version__.split('.')[0])
BLUR_RADIUS = 21
erode_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
dilate_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (9, 9))
cap = cv2.VideoCapture(0)
for i in range(10):
success, frame = cap.read()
if not success:
exit(1)
gray_background = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray_background = cv2.GaussianBlur(gray_background,(BLUR_RADIUS, BLUR_RADIUS), 0)
success, frame = cap.read()
while success:
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray_frame = cv2.GaussianBlur(gray_frame,
(BLUR_RADIUS, BLUR_RADIUS), 0)
diff = cv2.absdiff(gray_background, gray_frame)
_, thresh = cv2.threshold(diff, 40, 255, cv2.THRESH_BINARY)
cv2.erode(thresh, erode_kernel, thresh, iterations=2)
cv2.dilate(thresh, dilate_kernel, thresh, iterations=2)
if OPENCV_MAJOR_VERSION >= 4:
# OpenCV 4 or a later version is being used.
contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
else:
# OpenCV 3 or an earlier version is being used.
# cv2.findContours has an extra return value.
# The extra return value is the thresholded image, which is
# unchanged, so we can ignore it.
_, contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
if cv2.contourArea(c) > 4000:
x, y, w, h = cv2.boundingRect(c)
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 255, 0), 2)
cv2.imshow('diff', diff)
cv2.imshow('thresh', thresh)
cv2.imshow('detection', frame)
k = cv2.waitKey(1)
if k == 27: # Escape
break
success, frame = cap.read()
1.2. mog获取前景和背景
import cv2
OPENCV_MAJOR_VERSION = int(cv2.__version__.split('.')[0])
bg_subtractor = cv2.createBackgroundSubtractorMOG2(detectShadows=True)
erode_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
dilate_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))
cap = cv2.VideoCapture(r"D:\GProject\105_OpenCV\resource\lo4cvwptem\videos\traffic.flv")
success, frame = cap.read()
while success:
fg_mask = bg_subtractor.apply(frame)
_, thresh = cv2.threshold(fg_mask, 244, 255, cv2.THRESH_BINARY)
cv2.erode(thresh, erode_kernel, thresh, iterations=2)
cv2.dilate(thresh, dilate_kernel, thresh, iterations=2)
if OPENCV_MAJOR_VERSION >= 4:
# OpenCV 4 or a later version is being used.
contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
else:
# OpenCV 3 or an earlier version is being used.
# cv2.findContours has an extra return value.
# The extra return value is the thresholded image, which is
# unchanged, so we can ignore it.
_, contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
if cv2.contourArea(c) > 1000:
x, y, w, h = cv2.boundingRect(c)
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 255, 0), 2)
cv2.imshow('mog', fg_mask)
cv2.imshow('thresh', thresh)
cv2.imshow('background',
bg_subtractor.getBackgroundImage())
cv2.imshow('detection', frame)
k = cv2.waitKey(30)
if k == 27: # Escape
break
success, frame = cap.read()
1.3. knn获取前景和背景
import cv2
OPENCV_MAJOR_VERSION = int(cv2.__version__.split('.')[0])
bg_subtractor = cv2.createBackgroundSubtractorKNN(detectShadows=True)
erode_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 5))
dilate_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (17, 11))
cap = cv2.VideoCapture(r"D:\GProject\105_OpenCV\resource\lo4cvwptem\videos\traffic.flv")
success, frame = cap.read()
while success:
fg_mask = bg_subtractor.apply(frame)
_, thresh = cv2.threshold(fg_mask, 244, 255, cv2.THRESH_BINARY)
cv2.erode(thresh, erode_kernel, thresh, iterations=2)
cv2.dilate(thresh, dilate_kernel, thresh, iterations=2)
if OPENCV_MAJOR_VERSION >= 4:
# OpenCV 4 or a later version is being used.
contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
else:
# OpenCV 3 or an earlier version is being used.
# cv2.findContours has an extra return value.
# The extra return value is the thresholded image, which is
# unchanged, so we can ignore it.
_, contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
if cv2.contourArea(c) > 1000:
x, y, w, h = cv2.boundingRect(c)
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 255, 0), 2)
cv2.imshow('knn', fg_mask)
cv2.imshow('thresh', thresh)
cv2.imshow('background',
bg_subtractor.getBackgroundImage())
cv2.imshow('detection', frame)
k = cv2.waitKey(30)
if k == 27: # Escape
break
success, frame = cap.read()
1.4. gmg获取前景和背景
import cv2
OPENCV_MAJOR_VERSION = int(cv2.__version__.split('.')[0])
bg_subtractor = cv2.bgsegm.createBackgroundSubtractorGMG()
erode_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (13, 9))
dilate_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (17, 11))
cap = cv2.VideoCapture(r"D:\GProject\105_OpenCV\resource\lo4cvwptem\videos\traffic.flv")
success, frame = cap.read()
while success:
fg_mask = bg_subtractor.apply(frame)
_, thresh = cv2.threshold(fg_mask, 244, 255, cv2.THRESH_BINARY)
cv2.erode(thresh, erode_kernel, thresh, iterations=2)
cv2.dilate(thresh, dilate_kernel, thresh, iterations=2)
if OPENCV_MAJOR_VERSION >= 4:
# OpenCV 4 or a later version is being used.
contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
else:
# OpenCV 3 or an earlier version is being used.
# cv2.findContours has an extra return value.
# The extra return value is the thresholded image, which is
# unchanged, so we can ignore it.
_, contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
if cv2.contourArea(c) > 1000:
x, y, w, h = cv2.boundingRect(c)
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 255, 0), 2)
cv2.imshow('gmg', fg_mask)
cv2.imshow('thresh', thresh)
cv2.imshow('detection', frame)
k = cv2.waitKey(30)
if k == 27: # Escape
break
success, frame = cap.read()
1.5. meanshift获取前景背景
import cv2
cap = cv2.VideoCapture(0)
# Capture several frames to allow the camera's autoexposure to adjust.
for i in range(10):
success, frame = cap.read()
if not success:
exit(1)
# Define an initial tracking window in the center of the frame.
frame_h, frame_w = frame.shape[:2]
w = frame_w//8
h = frame_h//8
x = frame_w//2 - w//2
y = frame_h//2 - h//2
track_window = (x, y, w, h)
# Calculate the normalized HSV histogram of the initial window.
roi = frame[y:y+h, x:x+w]
hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
mask = None
roi_hist = cv2.calcHist([hsv_roi], [0], mask, [180], [0, 180])
cv2.normalize(roi_hist, roi_hist, 0, 255, cv2.NORM_MINMAX)
# Define the termination criteria:
# 10 iterations or convergence within 1-pixel radius.
term_crit = (cv2.TERM_CRITERIA_COUNT | cv2.TERM_CRITERIA_EPS, 10, 1)
success, frame = cap.read()
while success:
# Perform back-projection of the HSV histogram onto the frame.
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
back_proj = cv2.calcBackProject([hsv], [0], roi_hist, [0, 180], 1)
# Perform tracking with MeanShift.
num_iters, track_window = cv2.meanShift(
back_proj, track_window, term_crit)
# Draw the tracking window.
x, y, w, h = track_window
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
cv2.imshow('back-projection', back_proj)
cv2.imshow('meanshift', frame)
k = cv2.waitKey(1)
if k == 27: # Escape
break
success, frame = cap.read()
1.6. camshift获取前景背景
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
# Capture several frames to allow the camera's autoexposure to adjust.
for i in range(10):
success, frame = cap.read()
if not success:
exit(1)
# Define an initial tracking window in the center of the frame.
frame_h, frame_w = frame.shape[:2]
w = frame_w//8
h = frame_h//8
x = frame_w//2 - w//2
y = frame_h//2 - h//2
track_window = (x, y, w, h)
# Calculate the normalized HSV histogram of the initial window.
roi = frame[y:y+h, x:x+w]
hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
mask = None
roi_hist = cv2.calcHist([hsv_roi], [0], mask, [180], [0, 180])
cv2.normalize(roi_hist, roi_hist, 0, 255, cv2.NORM_MINMAX)
# Define the termination criteria:
# 10 iterations or convergence within 1-pixel radius.
term_crit = (cv2.TERM_CRITERIA_COUNT | cv2.TERM_CRITERIA_EPS, 10, 1)
success, frame = cap.read()
while success:
# Perform back-projection of the HSV histogram onto the frame.
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
back_proj = cv2.calcBackProject([hsv], [0], roi_hist, [0, 180], 1)
# Perform tracking with CamShift.
rotated_rect, track_window = cv2.CamShift(
back_proj, track_window, term_crit)
# Draw the tracking window.
box_points = cv2.boxPoints(rotated_rect)
box_points = np.int0(box_points)
cv2.polylines(frame, [box_points], True, (255, 0, 0), 2)
cv2.imshow('back-projection', back_proj)
cv2.imshow('camshift', frame)
k = cv2.waitKey(1)
if k == 27: # Escape
break
success, frame = cap.read()
2. 案例
2.1. kalman跟踪并预测鼠标
import cv2
import numpy as np
# Create a black image.
img = np.zeros((800, 800, 3), np.uint8)
# Initialize the Kalman filter.
kalman = cv2.KalmanFilter(4, 2)
kalman.measurementMatrix = np.array(
[[1, 0, 0, 0],
[0, 1, 0, 0]], np.float32)
kalman.transitionMatrix = np.array(
[[1, 0, 1, 0],
[0, 1, 0, 1],
[0, 0, 1, 0],
[0, 0, 0, 1]], np.float32)
kalman.processNoiseCov = np.array(
[[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]], np.float32) * 0.03
last_measurement = None
last_prediction = None
def on_mouse_moved(event, x, y, flags, param):
global img, kalman, last_measurement, last_prediction
measurement = np.array([[x], [y]], np.float32)
if last_measurement is None:
# This is the first measurement.
# Update the Kalman filter's state to match the measurement.
kalman.statePre = np.array(
[[x], [y], [0], [0]], np.float32)
kalman.statePost = np.array(
[[x], [y], [0], [0]], np.float32)
prediction = measurement
else:
kalman.correct(measurement)
prediction = kalman.predict() # Gets a reference, not a copy
# Trace the path of the measurement in green.
cv2.line(img, (int(last_measurement[0]), int(last_measurement[1])),
(int(measurement[0]), int(measurement[1])), (0, 255, 0))
# Trace the path of the prediction in red.
cv2.line(img, (int(last_prediction[0]), int(last_prediction[1])),
(int(prediction[0]), int(prediction[1])), (0, 0, 255))
last_prediction = prediction.copy()
last_measurement = measurement
cv2.namedWindow('kalman_tracker')
cv2.setMouseCallback('kalman_tracker', on_mouse_moved)
while True:
cv2.imshow('kalman_tracker', img)
k = cv2.waitKey(1)
if k == 27: # Escape
cv2.imwrite('kalman.png', img)
break
2.2. kalman跟踪行人
import cv2
import numpy as np
OPENCV_MAJOR_VERSION = int(cv2.__version__.split('.')[0])
class Pedestrian():
"""A tracked pedestrian with a state including an ID, tracking
window, histogram, and Kalman filter.
"""
def __init__(self, id, hsv_frame, track_window):
self.id = id
self.track_window = track_window
self.term_crit = \
(cv2.TERM_CRITERIA_COUNT | cv2.TERM_CRITERIA_EPS, 10, 1)
# Initialize the histogram.
x, y, w, h = track_window
roi = hsv_frame[y:y+h, x:x+w]
roi_hist = cv2.calcHist([roi], [0, 2], None, [15, 16],
[0, 180, 0, 256])
self.roi_hist = cv2.normalize(roi_hist, roi_hist, 0, 255,
cv2.NORM_MINMAX)
# Initialize the Kalman filter.
self.kalman = cv2.KalmanFilter(4, 2)
self.kalman.measurementMatrix = np.array(
[[1, 0, 0, 0],
[0, 1, 0, 0]], np.float32)
self.kalman.transitionMatrix = np.array(
[[1, 0, 1, 0],
[0, 1, 0, 1],
[0, 0, 1, 0],
[0, 0, 0, 1]], np.float32)
self.kalman.processNoiseCov = np.array(
[[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]], np.float32) * 0.03
cx = x+w/2
cy = y+h/2
self.kalman.statePre = np.array(
[[cx], [cy], [0], [0]], np.float32)
self.kalman.statePost = np.array(
[[cx], [cy], [0], [0]], np.float32)
def update(self, frame, hsv_frame):
back_proj = cv2.calcBackProject(
[hsv_frame], [0, 2], self.roi_hist, [0, 180, 0, 256], 1)
ret, self.track_window = cv2.meanShift(
back_proj, self.track_window, self.term_crit)
x, y, w, h = self.track_window
center = np.array([x+w/2, y+h/2], np.float32)
prediction = self.kalman.predict()
estimate = self.kalman.correct(center)
center_offset = estimate[:,0][:2] - center
self.track_window = (x + int(center_offset[0]),
y + int(center_offset[1]), w, h)
x, y, w, h = self.track_window
# Draw the predicted center position as a blue circle.
cv2.circle(frame, (int(prediction[0]), int(prediction[1])),
4, (255, 0, 0), -1)
# Draw the corrected tracking window as a cyan rectangle.
cv2.rectangle(frame, (x,y), (x+w, y+h), (255, 255, 0), 2)
# Draw the ID above the rectangle in blue text.
cv2.putText(frame, 'ID: %d' % self.id, (x, y-5),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 0),
1, cv2.LINE_AA)
def main():
cap = cv2.VideoCapture(r"D:\GProject\105_OpenCV\resource\lo4cvwptem\videos\pedestrians.avi")
# Create the KNN background subtractor.
bg_subtractor = cv2.createBackgroundSubtractorKNN()
history_length = 20
bg_subtractor.setHistory(history_length)
erode_kernel = cv2.getStructuringElement(
cv2.MORPH_ELLIPSE, (3, 3))
dilate_kernel = cv2.getStructuringElement(
cv2.MORPH_ELLIPSE, (5, 7))
pedestrians = []
num_history_frames_populated = 0
while True:
grabbed, frame = cap.read()
if not grabbed:
break
# Apply the KNN background subtractor.
fg_mask = bg_subtractor.apply(frame)
# Let the background subtractor build up a history.
if num_history_frames_populated < history_length:
num_history_frames_populated += 1
continue
# Create the thresholded image.
_, thresh = cv2.threshold(fg_mask, 127, 255,
cv2.THRESH_BINARY)
cv2.erode(thresh, erode_kernel, thresh, iterations=2)
cv2.dilate(thresh, dilate_kernel, thresh, iterations=2)
# Detect contours in the thresholded image.
if OPENCV_MAJOR_VERSION >= 4:
# OpenCV 4 or a later version is being used.
contours, hier = cv2.findContours(
thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
else:
# OpenCV 3 or an earlier version is being used.
# cv2.findContours has an extra return value.
# The extra return value is the thresholded image, which
# is unchanged, so we can ignore it.
_, contours, hier = cv2.findContours(
thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
hsv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# Draw green rectangles around large contours.
# Also, if no pedestrians are being tracked yet, create some.
should_initialize_pedestrians = len(pedestrians) == 0
id = 0
for c in contours:
if cv2.contourArea(c) > 500:
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(frame, (x, y), (x+w, y+h),
(0, 255, 0), 1)
if should_initialize_pedestrians:
pedestrians.append(
Pedestrian(id, hsv_frame,
(x, y, w, h)))
id += 1
# Update the tracking of each pedestrian.
for pedestrian in pedestrians:
pedestrian.update(frame, hsv_frame)
cv2.imshow('Pedestrians Tracked', frame)
k = cv2.waitKey(110)
if k == 27: # Escape
break
if __name__ == "__main__":
main()