mirror of https://bitbucket.org/ausocean/av.git
KNN filter detects motion on an interval
This commit is contained in:
parent
65bc98efbf
commit
207e96b999
|
@ -40,23 +40,26 @@ import (
|
|||
// KNNFilter is a filter that provides basic motion detection. KNN is short for
|
||||
// K-Nearest Neighbours method.
|
||||
type KNNFilter struct {
|
||||
dst io.WriteCloser
|
||||
area float64
|
||||
bs *gocv.BackgroundSubtractorKNN
|
||||
knl gocv.Mat
|
||||
debug bool
|
||||
windows []*gocv.Window
|
||||
dst io.WriteCloser // Destination to which motion containing frames go.
|
||||
area float64 // The minimum area that a contour can be found in.
|
||||
bs *gocv.BackgroundSubtractorKNN // Uses the KNN algorithm to find the difference between the current and background frame.
|
||||
knl gocv.Mat // Matrix that is used for calculations.
|
||||
debug bool // If true then debug windows with the bounding boxes and difference will be shown on the screen.
|
||||
windows []*gocv.Window // Holds debug windows.
|
||||
hold [][]byte // Will hold all frames up to hf (so only every hf frame is motion detected).
|
||||
hf int // The number of frames to be held.
|
||||
hfCount int // Counter for the hold array.
|
||||
}
|
||||
|
||||
// NewKNNFilter returns a pointer to a new KNNFilter.
|
||||
func NewKNNFilter(dst io.WriteCloser, area, threshold float64, history, kernelSize int, debug bool) *KNNFilter {
|
||||
func NewKNNFilter(dst io.WriteCloser, area, threshold float64, history, kernelSize int, debug bool, hf int) *KNNFilter {
|
||||
bs := gocv.NewBackgroundSubtractorKNNWithParams(history, threshold, false)
|
||||
k := gocv.GetStructuringElement(gocv.MorphRect, image.Pt(kernelSize, kernelSize))
|
||||
var windows []*gocv.Window
|
||||
if debug {
|
||||
windows = []*gocv.Window{gocv.NewWindow("KNN: Bounding boxes"), gocv.NewWindow("KNN: Motion")}
|
||||
}
|
||||
return &KNNFilter{dst, area, &bs, k, debug, windows}
|
||||
return &KNNFilter{dst, area, &bs, k, debug, windows, make([][]byte, hf-1), hf, 0}
|
||||
}
|
||||
|
||||
// Implements io.Closer.
|
||||
|
@ -75,6 +78,13 @@ func (m *KNNFilter) Close() error {
|
|||
// Write applies the motion filter to the video stream. Only frames with motion
|
||||
// are written to the destination encoder, frames without are discarded.
|
||||
func (m *KNNFilter) Write(f []byte) (int, error) {
|
||||
if m.hfCount < (m.hf - 1) {
|
||||
m.hold[m.hfCount] = f
|
||||
m.hfCount++
|
||||
return len(f), nil
|
||||
}
|
||||
m.hfCount = 0
|
||||
|
||||
img, err := gocv.IMDecode(f, gocv.IMReadColor)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("can't decode image: %w", err)
|
||||
|
@ -125,9 +135,16 @@ func (m *KNNFilter) Write(f []byte) (int, error) {
|
|||
|
||||
// Don't write to destination if there is no motion.
|
||||
if len(contours) == 0 {
|
||||
return -1, nil
|
||||
return len(f), nil
|
||||
}
|
||||
|
||||
// Write to destination.
|
||||
// Write to destination, past 4 frames then current frame.
|
||||
for i, h := range m.hold {
|
||||
_, err := m.dst.Write(h)
|
||||
m.hold[i] = nil
|
||||
if err != nil {
|
||||
return len(f), fmt.Errorf("could not write previous frames: %w", err)
|
||||
}
|
||||
}
|
||||
return m.dst.Write(f)
|
||||
}
|
||||
|
|
|
@ -341,7 +341,7 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64) (io.
|
|||
case config.FilterVariableFPS:
|
||||
r.filters[i] = filter.NewVariableFPSFilter(dst, r.cfg.MinFPS, filter.NewMOGFilter(dst, r.cfg.MOGMinArea, r.cfg.MOGThreshold, int(r.cfg.MOGHistory), r.cfg.ShowWindows, r.cfg.MotionInterval))
|
||||
case config.FilterKNN:
|
||||
r.filters[i] = filter.NewKNNFilter(dst, r.cfg.KNNMinArea, r.cfg.KNNThreshold, int(r.cfg.KNNHistory), int(r.cfg.KNNKernel), r.cfg.ShowWindows)
|
||||
r.filters[i] = filter.NewKNNFilter(dst, r.cfg.KNNMinArea, r.cfg.KNNThreshold, int(r.cfg.KNNHistory), int(r.cfg.KNNKernel), r.cfg.ShowWindows, r.cfg.MotionInterval)
|
||||
default:
|
||||
panic("Undefined Filter")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue