// +build !circleci /* DESCRIPTION A filter that detects motion and discards frames without motion. The algorithm calculates the absolute difference for each pixel between two frames, then finds the mean. If the mean is above a given threshold, then it is considered motion. AUTHORS Scott Barnard LICENSE diff.go is Copyright (C) 2020 the Australian Ocean Lab (AusOcean) It is free software: you can redistribute it and/or modify them under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License in gpl.txt. If not, see http://www.gnu.org/licenses. */ package filter import ( "fmt" "io" "bitbucket.org/ausocean/av/revid/config" "gocv.io/x/gocv" ) const defaultDiffThreshold = 3 // NewDiff returns a pointer to a new difference motion filter. func NewDiff(dst io.WriteCloser, c config.Config) *Motion { // Validate parameters. if c.MotionThreshold <= 0 { c.LogInvalidField("MotionThreshold", defaultDiffThreshold) c.MotionThreshold = defaultDiffThreshold } alg := &Diff{ thresh: c.MotionThreshold, prev: gocv.NewMat(), debugging: newWindows("DIFF"), } return NewMotion(dst, alg, c) } // Diff is a motion detection algorithm. It calculates the absolute // difference for each pixel between two frames, then finds the mean. // If the mean is above a given threshold, it is considered motion. type Diff struct { debugging debugWindows thresh float64 prev gocv.Mat } // Close frees resources used by gocv. It has to be done manually, // due to gocv using c-go. func (d *Diff) Close() error { d.debugging.close() d.prev.Close() return nil } // Detect performs the motion detection on a frame. It returns true // if motion is detected. func (d *Diff) Detect(img *gocv.Mat) bool { if d.prev.Empty() { d.prev = img.Clone() return false } imgDelta := gocv.NewMat() defer imgDelta.Close() // Seperate foreground and background. gocv.AbsDiff(*img, d.prev, &imgDelta) gocv.CvtColor(imgDelta, &imgDelta, gocv.ColorBGRToGray) mean := imgDelta.Mean().Val1 // Update History. d.prev = img.Clone() // Draw debug information. d.debugging.show(*img, imgDelta, mean > d.thresh, nil, fmt.Sprintf("Mean: %f", mean), fmt.Sprintf("Threshold: %f", d.thresh)) // Return if there is motion. return mean > d.thresh }