Merged in less-frames-knn (pull request #346)

Less frames knn

Approved-by: Saxon Milton <saxon.milton@gmail.com>
This commit is contained in:
Scott Barnard 2020-01-23 02:28:43 +00:00 committed by Saxon Milton
commit 8ac664f11e
3 changed files with 29 additions and 12 deletions

View File

@ -36,6 +36,6 @@ func NewMOGFilter(dst io.WriteCloser, area, threshold float64, history int, debu
return &NoOp{dst: dst} return &NoOp{dst: dst}
} }
func NewKNNFilter(dst io.WriteCloser, area, threshold float64, history, kernelSize int, debug bool) *NoOp { func NewKNNFilter(dst io.WriteCloser, area, threshold float64, history, kernelSize int, debug bool, hf int) *NoOp {
return &NoOp{dst: dst} return &NoOp{dst: dst}
} }

View File

@ -40,23 +40,26 @@ import (
// KNNFilter is a filter that provides basic motion detection. KNN is short for // KNNFilter is a filter that provides basic motion detection. KNN is short for
// K-Nearest Neighbours method. // K-Nearest Neighbours method.
type KNNFilter struct { type KNNFilter struct {
dst io.WriteCloser dst io.WriteCloser // Destination to which motion containing frames go.
area float64 area float64 // The minimum area that a contour can be found in.
bs *gocv.BackgroundSubtractorKNN bs *gocv.BackgroundSubtractorKNN // Uses the KNN algorithm to find the difference between the current and background frame.
knl gocv.Mat knl gocv.Mat // Matrix that is used for calculations.
debug bool debug bool // If true then debug windows with the bounding boxes and difference will be shown on the screen.
windows []*gocv.Window 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. // 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) bs := gocv.NewBackgroundSubtractorKNNWithParams(history, threshold, false)
k := gocv.GetStructuringElement(gocv.MorphRect, image.Pt(kernelSize, kernelSize)) k := gocv.GetStructuringElement(gocv.MorphRect, image.Pt(kernelSize, kernelSize))
var windows []*gocv.Window var windows []*gocv.Window
if debug { if debug {
windows = []*gocv.Window{gocv.NewWindow("KNN: Bounding boxes"), gocv.NewWindow("KNN: Motion")} 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. // 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 // Write applies the motion filter to the video stream. Only frames with motion
// are written to the destination encoder, frames without are discarded. // are written to the destination encoder, frames without are discarded.
func (m *KNNFilter) Write(f []byte) (int, error) { 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) img, err := gocv.IMDecode(f, gocv.IMReadColor)
if err != nil { if err != nil {
return 0, fmt.Errorf("can't decode image: %w", err) 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. // Don't write to destination if there is no motion.
if len(contours) == 0 { 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) return m.dst.Write(f)
} }

View File

@ -341,7 +341,7 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64) (io.
case config.FilterVariableFPS: 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)) 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: 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: default:
panic("Undefined Filter") panic("Undefined Filter")
} }