def bgsub(vidfile_basename, threshold, quiet=False, drawBoxes=True): operator = BackgroundSubtractor(2000, threshold, True) # Learn the bg operator.model_bg2(VIDEO_DIR + vidfile_basename) tp_t = fp_t = fn_t = p_t = n_t = 0 video = cv2.VideoCapture(VIDEO_DIR + vidfile_basename) ret, frame = video.read() frame_num = 0 while ret: mask = operator.apply(frame) mask = tools.morph_openclose(mask) mask_binary = (mask == 255).astype(np.uint8) gt_filename = "{0}/{1}/{2}.jpg.seg.bmp".format(GT_IMG_DIR, vidfile_basename, frame_num) if os.path.exists(gt_filename): if not quiet: cv2.imshow("Ground truth", cv2.imread(gt_filename) * 255) tp, fp, fn = compare_response_to_truth(mask_binary, gt_filename) # print("True Pos: {0}\nFalse Pos: {1}".format(tp, fp)) pos_detected, neg_detected = class_counter.count_posneg(mask_binary) tp_t += tp fp_t += fp fn_t += fn p_t += pos_detected n_t += neg_detected # print("Foreground pixels: {0}\nBackground pixels: {1}".format(pos_detected, neg_detected)) if not quiet: mask = ((mask == 255) * 255).astype(np.uint8) cv2.imshow("Mask", mask) if drawBoxes: blob_detect(mask, frame) else: cv2.imshow("Frame", frame) ret, frame = video.read() frame_num += 1 if handle_keys() is 1: break with np.errstate(invalid='ignore'): precision = np.float64(tp_t) / (tp_t + fp_t) recall = np.float64(tp_t) / (tp_t + fn_t) if np.isinf(precision) or np.isnan(precision): precision = 1 if np.isinf(recall) or np.isnan(recall): recall = 1 return precision, recall
class App: def __init__(self, video_src="", quiet=False, invisible=False, draw_contours=False, bgsub_thresh=64, drawTracks=False, drawFrameNum=False, drawBoundary=False): self.quiet = quiet self.invisible = invisible self.drawContours = draw_contours self.threshold = bgsub_thresh self.drawTracks = drawTracks self.drawFrameNum = drawFrameNum self.drawBoundary = drawBoundary self.areas = [] # Learn the bg self.operator = BackgroundSubtractor(2000, self.threshold, True) self.operator.model_bg2(video_src) self.cam = cv2.VideoCapture(video_src) self.maxTimeInvisible = 0 self.trackAgeThreshold = 4 self.tracks = [] self.lostTracks = [] self.frame_idx = 0 self.arrivals = self.departures = 0 def run(self, as_script=True): if self.invisible: cv2.namedWindow("Control") prev_gray = None prev_points = [] self.nextTrackID = 0 while True: # Get frame ret, frame = self.cam.read() if not ret: break frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # Segment fg_mask = self.operator.apply(frame) fg_mask = ((fg_mask == 255) * 255).astype(np.uint8) fg_mask = morph_openclose(fg_mask) # Detect blobs if "3.0." in cv2.__version__: _, contours, _ = cv2.findContours((fg_mask.copy()), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_L1) else: contours, _ = cv2.findContours((fg_mask.copy()), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_L1) areas, detections = drawing.draw_min_ellipse(contours, frame, MIN_AREA, MAX_AREA, draw=False) self.areas += areas # Track self.predictNewLocations(frame) assignments, unmatchedTracks, unmatchedDetections = self.assignTracks(detections, frame) self.updateMatchedTracks(assignments, detections) self.updateUnmatchedTracks(unmatchedTracks) self.deleteLostTracks() self.createNewTracks(detections, unmatchedDetections) self.showTracks(frame) # self.showLostTracks(frame) self.checkTrackCrosses() # Store frame and go to next prev_gray = frame_gray prev_points = detections self.frame_idx += 1 if not self.invisible: self.draw_overlays(frame, fg_mask) cv2.imshow('Tracking', frame) cv2.imshow("Mask", fg_mask) delay = FRAME_DELAY if handle_keys(delay) == 1: break # else: # if handle_keys(delay) == 1: # break # Should we continue running or yield some information about the current frame if as_script: continue else: pass # After the video, examine tracks # self.checkLostTrackCrosses() self.cam.release() def deleteLostTracks(self): newTracks = [] tracksLost = 0 for track in self.tracks: # Fraction of tracks age in which is was visible visibilty = float(track.totalVisibleCount) / track.age # Determine lost tracks if not ((track.age < self.trackAgeThreshold and visibilty < .6) or (track.timeInvisible > self.maxTimeInvisible)): newTracks.append(track) else: self.lostTracks.append(track) tracksLost += 1 # print("Tracks lost", tracksLost) self.tracks = newTracks def createNewTracks(self, detections, unmatchedDetections): for detectionIndex in unmatchedDetections: detection = detections[detectionIndex] array_detection = np.array(detection, np.float32) # TODO: Create Kalman filter object kf = cv2.KalmanFilter(4, 2) kf.measurementMatrix = MEASUREMENT_MATRIX kf.transitionMatrix = TRANSITION_MATRIX # kf.processNoiseCov = PROCESS_NOISE_COV # Create the new track newTrack = Track(self.nextTrackID, kf) newTrack.update(array_detection) newTrack.locationHistory.append(detection) self.tracks.append(newTrack) self.nextTrackID += 1 def updateMatchedTracks(self, assignments, detections): for assignment in assignments: trackIndex = assignment.trackIndex detectionIndex = assignment.detectionIndex detection = detections[detectionIndex] array_detection = np.array(detection, np.float32) track = self.tracks[trackIndex] track.update(array_detection) # Update track track.age += 1 track.totalVisibleCount += 1 track.timeInvisible = 0 track.locationHistory.append(detection) def updateUnmatchedTracks(self, unmatchedTracks): for trackIndex in unmatchedTracks: tr = self.tracks[trackIndex] tr.age += 1 tr.timeInvisible += 1 def assignTracks(self, detections, frame): """ Returns assignments, unmatchedTracks, unmatchedDetections """ if len(self.tracks) == 0: # There are no tracks, all detections are unmatched unmatchedDetections = range(len(detections)) return [], [], unmatchedDetections elif len(detections) == 0: # There are no detections, all tracks are unmatched unmatchedTracks = range(len(self.tracks)) return [], unmatchedTracks, [] else: costMatrix = np.zeros((len(self.tracks), len(detections))) for i, track in enumerate(self.tracks): x1, y1 = track.getPredictedXY() for j, (x2, y2) in enumerate(detections): # cv2.line(frame, (x1, y1), (x2, y2), (255, 0, 0)) costMatrix[i, j] = np.sqrt( (x1 - x2)**2 + (y1 - y2)**2 ) return tools.assignment(costMatrix) def predictNewLocations(self, frame): for track in self.tracks: track.predict(frame) def showTracks(self, frame): if self.drawTracks: for track in self.tracks: track.drawTrack(frame) def showLostTracks(self, frame): for track in self.lostTracks: loc = track.locationHistory[-1] cv2.circle(frame, loc, 2, color=(0,0,255), thickness=-1) def checkTrackCrosses(self): for track in self.tracks: result = track.checkCrossLastTwo(ROI, ROI_W, ROI_H) if result == 1: self.arrivals += 1 # print("Arrival") elif result == -1: self.departures += 1 # print("Departure") def checkLostTrackCrosses(self): self.lostTracks += self.tracks for track in self.lostTracks: result = track.checkCross() if result == 1: self.arrivals += 1 # print("Arrival") elif result == -1: self.departures += 1 # print("Departure") def draw_overlays(self, frame, fg_mask): if self.drawBoundary: drawing.draw_rectangle(frame, ROI, (ROI[0]+ROI_W, ROI[1]+ROI_H)) if self.drawFrameNum: drawing.draw_frame_num(frame, self.frame_idx) if self.drawContours: pass # drawing.draw_contours(frame, fg_mask) def openNewVideo(self, video_src): self.cam.release() self.cam = cv2.VideoCapture(video_src)
class App: def __init__(self, video_src, quiet=True, invisible=False, draw_contours=True, bgsub_thresh=64): self.quiet = quiet self.invisible = invisible self.drawContours = draw_contours self.threshold = bgsub_thresh self.drawTracks = True self.drawFrameNum = False self.areas = [] # Learn the bg self.operator = BackgroundSubtractor(2000, self.threshold, True) self.operator.model_bg2(video_src) self.track_len = 10 self.detect_interval = 5 self.tracks = [] self.cam = cv2.VideoCapture(video_src) self.frame_idx = 0 self.arrivals = self.departures = 0 def run(self, as_script=True): if self.invisible: cv2.namedWindow("Control") prev_gray = None prev_points = None while True: ret, frame = self.cam.read() if not ret: break fg_mask = self.operator.apply(frame) fg_mask = ((fg_mask == 255) * 255).astype(np.uint8) fg_mask = morph_openclose(fg_mask) frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) if prev_gray is not None and prev_points is not None: p0 = np.float32([point for point in prev_points]).reshape(-1, 1, 2) if drawing.draw_prev_points(frame, prev_points): # p1, st, err = cv2.calcOpticalFlowPyrLK(prev_gray, frame_gray, p0, None, **lk_params) frame_gray[fg_mask == 0] = 255 p1, st, err = cv2.calcOpticalFlowPyrLK( prev_gray, frame_gray, p0, None, **lk_params) for p_i, p_f in zip(p0.reshape(-1, 2), p1.reshape(-1, 2)): result = cross(ROI, ROI_W, ROI_H, p_i, p_f) if result is 1: self.arrivals += 1 if not self.quiet: print("Arrival") elif result is -1: self.departures += 1 if not self.quiet: print("Departure") if self.drawTracks: drawing.draw_line(frame, tuple(p_i), tuple(p_f)) prev_gray = frame_gray contours, hier = drawing.draw_contours(frame, fg_mask) areas, prev_points = drawing.draw_min_ellipse( contours, frame, MIN_AREA, MAX_AREA) self.areas += areas self.frame_idx += 1 if not self.invisible: self.draw_overlays(frame, fg_mask) cv2.imshow("Fas", frame_gray) cv2.imshow('Tracking', frame) cv2.imshow("Mask", fg_mask) delay = 33 else: delay = 1 if handle_keys(delay) == 1: break # Should we continue running or yield some information about the current frame if as_script: continue else: pass return self.areas def draw_overlays(self, frame, fg_mask): drawing.draw_rectangle(frame, ROI, (ROI[0] + ROI_W, ROI[1] + ROI_H)) if self.drawFrameNum: drawing.draw_frame_num(frame, self.frame_idx) if self.drawContours: pass
class App: def __init__(self, video_src, quiet=True, invisible=False, draw_contours=True, bgsub_thresh=64): self.quiet = quiet self.invisible = invisible self.drawContours = draw_contours self.threshold = bgsub_thresh self.drawTracks = True self.drawFrameNum = False self.areas = [] # Learn the bg self.operator = BackgroundSubtractor(2000, self.threshold, True) self.operator.model_bg2(video_src) self.track_len = 10 self.detect_interval = 5 self.tracks = [] self.cam = cv2.VideoCapture(video_src) self.frame_idx = 0 self.arrivals = self.departures = 0 def run(self, as_script=True): if self.invisible: cv2.namedWindow("Control") prev_gray = None prev_points = None while True: ret, frame = self.cam.read() if not ret: break fg_mask = self.operator.apply(frame) fg_mask = ((fg_mask == 255) * 255).astype(np.uint8) fg_mask = morph_openclose(fg_mask) frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) if prev_gray is not None and prev_points is not None: p0 = np.float32([point for point in prev_points]).reshape(-1, 1, 2) if drawing.draw_prev_points(frame, prev_points): # p1, st, err = cv2.calcOpticalFlowPyrLK(prev_gray, frame_gray, p0, None, **lk_params) frame_gray[fg_mask == 0] = 255 p1, st, err = cv2.calcOpticalFlowPyrLK(prev_gray, frame_gray, p0, None, **lk_params) for p_i, p_f in zip(p0.reshape(-1, 2), p1.reshape(-1, 2)): result = cross(ROI, ROI_W, ROI_H, p_i, p_f) if result is 1: self.arrivals += 1 if not self.quiet: print("Arrival") elif result is -1: self.departures += 1 if not self.quiet: print("Departure") if self.drawTracks: drawing.draw_line(frame, tuple(p_i), tuple(p_f)) prev_gray = frame_gray contours, hier = drawing.draw_contours(frame, fg_mask) areas, prev_points = drawing.draw_min_ellipse(contours, frame, MIN_AREA, MAX_AREA) self.areas += areas self.frame_idx += 1 if not self.invisible: self.draw_overlays(frame, fg_mask) cv2.imshow("Fas", frame_gray) cv2.imshow('Tracking', frame) cv2.imshow("Mask", fg_mask) delay = 33 else: delay = 1 if handle_keys(delay) == 1: break # Should we continue running or yield some information about the current frame if as_script: continue else: pass return self.areas def draw_overlays(self, frame, fg_mask): drawing.draw_rectangle(frame, ROI, (ROI[0]+ROI_W, ROI[1]+ROI_H)) if self.drawFrameNum: drawing.draw_frame_num(frame, self.frame_idx) if self.drawContours: pass
class App: def __init__(self, video_src="", quiet=False, invisible=False, draw_contours=False, bgsub_thresh=64, drawTracks=False, drawFrameNum=False, drawBoundary=False): self.quiet = quiet self.invisible = invisible self.drawContours = draw_contours self.threshold = bgsub_thresh self.drawTracks = drawTracks self.drawFrameNum = drawFrameNum self.drawBoundary = drawBoundary self.areas = [] # Learn the bg self.operator = BackgroundSubtractor(2000, self.threshold, True) self.operator.model_bg2(video_src) self.cam = cv2.VideoCapture(video_src) self.maxTimeInvisible = 0 self.trackAgeThreshold = 4 self.tracks = [] self.lostTracks = [] self.frame_idx = 0 self.arrivals = 0 self.departures = 0 def run(self, as_script=True): if self.invisible: cv2.namedWindow("Control") prev_gray = None prev_points = [] self.nextTrackID = 0 while True: # Get frame ret, frame = self.cam.read() if not ret: break # Convert frame to grayscale frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # Segment fg_mask = self.operator.apply(frame) fg_mask = ((fg_mask == 255) * 255).astype(np.uint8) fg_mask = morph_openclose(fg_mask) # Detect blobs version = int(re.findall(r'\d+', cv2.__version__)[0]) if version == 3: _, contours, _ = cv2.findContours((fg_mask.copy()), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_L1) else: # Get contours for detected bees using the foreground mask contours, _ = cv2.findContours((fg_mask.copy()), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_L1) areas, detections = drawing.draw_min_ellipse(contours, frame, MIN_AREA, MAX_AREA, draw=False) self.areas += areas # Track self.predictNewLocations(frame) assignments, unmatchedTracks, unmatchedDetections = self.assignTracks(detections, frame) self.updateMatchedTracks(assignments, detections) self.updateUnmatchedTracks(unmatchedTracks) self.deleteLostTracks() self.createNewTracks(detections, unmatchedDetections) self.showTracks(frame) # self.showLostTracks(frame) self.checkTrackCrosses() # Store frame and go to next prev_gray = frame_gray prev_points = detections self.frame_idx += 1 if not self.invisible: self.draw_overlays(frame, fg_mask) cv2.imshow('Tracking', frame) cv2.imshow("Mask", fg_mask) delay = FRAME_DELAY if handle_keys(delay) == 1: break # else: # if handle_keys(delay) == 1: # break # Should we continue running or yield some information about the current frame if as_script: continue else: pass # After the video, examine tracks # self.checkLostTrackCrosses() self.cam.release() def deleteLostTracks(self): newTracks = [] tracksLost = 0 for track in self.tracks: # Fraction of tracks age in which is was visible visibilty = float(track.totalVisibleCount) / track.age # Determine lost tracks if not ((track.age < self.trackAgeThreshold and visibilty < .6) or (track.timeInvisible > self.maxTimeInvisible)): #track valid newTracks.append(track) else: #track invalid self.lostTracks.append(track) tracksLost += 1 # print("Tracks lost", tracksLost) self.tracks = newTracks def createNewTracks(self, detections, unmatchedDetections): for detectionIndex in unmatchedDetections: detection = detections[detectionIndex] array_detection = np.array(detection, np.float32) # TODO: Create Kalman filter object kf = cv2.KalmanFilter(4, 2) kf.measurementMatrix = MEASUREMENT_MATRIX kf.transitionMatrix = TRANSITION_MATRIX # kf.processNoiseCov = PROCESS_NOISE_COV # Create the new track newTrack = Track(self.nextTrackID, kf) newTrack.update(array_detection) newTrack.locationHistory.append(detection) self.tracks.append(newTrack) self.nextTrackID += 1 def updateMatchedTracks(self, assignments, detections): for assignment in assignments: trackIndex = assignment.trackIndex detectionIndex = assignment.detectionIndex detection = detections[detectionIndex] array_detection = np.array(detection, np.float32) track = self.tracks[trackIndex] track.update(array_detection) # Update track track.age += 1 track.totalVisibleCount += 1 track.timeInvisible = 0 track.locationHistory.append(detection) def updateUnmatchedTracks(self, unmatchedTracks): for trackIndex in unmatchedTracks: track = self.tracks[trackIndex] track.age += 1 track.timeInvisible += 1 def assignTracks(self, detections, frame): """ Returns assignments, unmatchedTracks, unmatchedDetections """ if len(self.tracks) == 0: # There are no tracks, all detections are unmatched unmatchedDetections = range(len(detections)) return [], [], unmatchedDetections elif len(detections) == 0: # There are no detections, all tracks are unmatched unmatchedTracks = range(len(self.tracks)) return [], unmatchedTracks, [] else: costMatrix = np.zeros((len(self.tracks), len(detections))) for i, track in enumerate(self.tracks): x1, y1 = track.getPredictedXY() for j, (x2, y2) in enumerate(detections): # cv2.line(frame, (x1, y1), (x2, y2), (255, 0, 0)) costMatrix[i, j] = np.sqrt( (x1 - x2)**2 + (y1 - y2)**2 ) return tools.assignment(costMatrix) def predictNewLocations(self, frame): for track in self.tracks: track.predict(frame) def showTracks(self, frame): if self.drawTracks: for track in self.tracks: track.drawTrack(frame) def showLostTracks(self, frame): for track in self.lostTracks: loc = track.locationHistory[-1] cv2.circle(frame, loc, 2, color=(0,0,255), thickness=-1) def checkTrackCrosses(self): for track in self.tracks: result = track.checkCrossLastTwo(ROI, ROI_W, ROI_H) if result == 1: self.arrivals += 1 # print("Arrival") elif result == -1: self.departures += 1 # print("Departure") def checkLostTrackCrosses(self): self.lostTracks += self.tracks for track in self.lostTracks: result = track.checkCross() if result == 1: self.arrivals += 1 # print("Arrival") elif result == -1: self.departures += 1 # print("Departure") def draw_overlays(self, frame, fg_mask): if self.drawBoundary: drawing.draw_rectangle(frame, ROI, (ROI[0]+ROI_W, ROI[1]+ROI_H)) if self.drawFrameNum: drawing.draw_frame_num(frame, self.frame_idx) if self.drawContours: pass # drawing.draw_contours(frame, fg_mask) def openNewVideo(self, video_src): self.cam.release() self.cam = cv2.VideoCapture(video_src)