filter: add option to reduce resolution of frames for MOG motion filter

A new netsender variable, FilterDownscaling is used for reducing the resolution of frames within the MOG motion filter.
This does not affect the resolution of the video output, it is only used to speed up calculations.
A FilterDownscaling factor of 2 is equivalent to skipping every 2nd pixel in the image.
This commit is contained in:
Scott 2020-01-31 10:21:23 +10:30
parent c90cc40949
commit 10bfc296be
4 changed files with 83 additions and 62 deletions

View File

@ -32,7 +32,7 @@ import (
)
// NewMOG returns a pointer to a new NoOp struct for testing purposes only.
func NewMOG(dst io.WriteCloser, area, threshold float64, history int, debug bool, hf int) *NoOp {
func NewMOG(dst io.WriteCloser, area, threshold float64, history int, debug bool, hf int, downscalingFactor int) *NoOp {
return &NoOp{dst: dst}
}

View File

@ -49,17 +49,18 @@ type MOG struct {
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.
scale float64 // The factor that frames will be downscaled by for motion detection.
}
// NewMOG returns a pointer to a new MOG filter struct.
func NewMOG(dst io.WriteCloser, area, threshold float64, history int, debug bool, hf int) *MOG {
func NewMOG(dst io.WriteCloser, area, threshold float64, history int, debug bool, hf int, downscalingFactor int) *MOG {
bs := gocv.NewBackgroundSubtractorMOG2WithParams(history, threshold, false)
k := gocv.GetStructuringElement(gocv.MorphRect, image.Pt(3, 3))
var windows []*gocv.Window
if debug {
windows = []*gocv.Window{gocv.NewWindow("MOG: Bounding boxes"), gocv.NewWindow("MOG: Motion")}
}
return &MOG{dst, area, &bs, k, debug, windows, make([][]byte, hf-1), hf, 0}
return &MOG{dst, area, &bs, k, debug, windows, make([][]byte, hf-1), hf, 0, 1 / float64(downscalingFactor)}
}
// Implements io.Closer.
@ -94,6 +95,9 @@ func (m *MOG) Write(f []byte) (int, error) {
imgDelta := gocv.NewMat()
defer imgDelta.Close()
// Downsize image to speed up calculations.
gocv.Resize(img, &img, image.Point{}, m.scale, m.scale, gocv.InterpolationNearestNeighbor)
// Seperate foreground and background.
m.bs.Apply(img, &imgDelta)

View File

@ -85,7 +85,6 @@ const (
defaultClipDuration = 0
defaultAudioInputCodec = codecutil.ADPCM
defaultPSITime = 2
defaultMotionInterval = 5
defaultFileFPS = 0
// Ring buffer defaults.
@ -95,6 +94,8 @@ const (
// Motion filter parameter defaults.
defaultMinFPS = 1.0
defaultMotionDownscaling = 1
defaultMotionInterval = 1
// KNN filter parameter defaults.
defaultKNNMinArea = 25.0
@ -283,7 +284,6 @@ type Config struct {
HorizontalFlip bool // HorizontalFlip flips video horizontally for Raspivid input.
VerticalFlip bool // VerticalFlip flips video vertically for Raspivid input.
Filters []int // Defines the methods of filtering to be used in between lexing and encoding.
MotionInterval int // Sets the number of frames that are held before the filter is used (on the nth frame)
PSITime int // Sets the time between a packet being sent.
// Ring buffer parameters.
@ -293,6 +293,8 @@ type Config struct {
// Motion filter parameters.
MinFPS float64 // The reduced framerate of the video when there is no motion.
MotionInterval int // Sets the number of frames that are held before the filter is used (on the nth frame)
MotionDownscaling int // Downscaling factor of frames used for motion detection.
// KNN filter parameters.
KNNMinArea float64 // Used to ignore small areas of motion detection.
@ -303,8 +305,12 @@ type Config struct {
// MOG filter parameters.
MOGMinArea float64 // Used to ignore small areas of motion detection.
MOGThreshold float64 // Intensity value from the KNN motion detection algorithm that is considered motion.
MOGHistory uint // Length of MOG filter's history
MOGHistory uint // Length of MOG filter's history.
// Difference filter parameters.
DiffThreshold float64 // Intensity value from the Difference motion detection algorithm that is considered motion.
// Basic filter parameters.
BasicThreshold int
BasicPixels int
@ -313,8 +319,6 @@ type Config struct {
// Defines the rate at which frames from a file source are processed.
FileFPS int
// Difference filter parameters.
DiffThreshold float64 // Intensity value from the Difference motion detection algorithm that is considered motion.
}
// TypeData contains information about all of the variables that
@ -353,6 +357,7 @@ var TypeData = map[string]string{
"MOGHistory": "uint",
"MOGMinArea": "float",
"MOGThreshold": "float",
"MotionDownscaling": "uint",
"MotionInterval": "int",
"Output": "enum:File,Http,Rtmp,Rtp",
"OutputPath": "string",
@ -544,6 +549,11 @@ func (c *Config) Validate() error {
c.BasicPixels = defaultBasicPixels
}
if c.MotionDownscaling <= 0 {
c.logInvalidField("MotionDownscaling", defaultMotionDownscaling)
c.MotionDownscaling = defaultMotionDownscaling
}
if c.ShowWindows {
os, err := osName()
if err != nil {

View File

@ -341,9 +341,9 @@ func (r *Revid) setupPipeline(mtsEnc func(dst io.WriteCloser, rate float64) (io.
case config.FilterNoOp:
r.filters[i] = filter.NewNoOp(dst)
case config.FilterMOG:
r.filters[i] = filter.NewMOG(dst, r.cfg.MOGMinArea, r.cfg.MOGThreshold, int(r.cfg.MOGHistory), r.cfg.ShowWindows, r.cfg.MotionInterval)
r.filters[i] = filter.NewMOG(dst, r.cfg.MOGMinArea, r.cfg.MOGThreshold, int(r.cfg.MOGHistory), r.cfg.ShowWindows, r.cfg.MotionInterval, r.cfg.MotionDownscaling)
case config.FilterVariableFPS:
r.filters[i] = filter.NewVariableFPS(dst, r.cfg.MinFPS, filter.NewMOG(dst, r.cfg.MOGMinArea, r.cfg.MOGThreshold, int(r.cfg.MOGHistory), r.cfg.ShowWindows, r.cfg.MotionInterval))
r.filters[i] = filter.NewVariableFPS(dst, r.cfg.MinFPS, filter.NewMOG(dst, r.cfg.MOGMinArea, r.cfg.MOGThreshold, int(r.cfg.MOGHistory), r.cfg.ShowWindows, r.cfg.MotionInterval, r.cfg.MotionDownscaling))
case config.FilterKNN:
r.filters[i] = filter.NewKNN(dst, r.cfg.KNNMinArea, r.cfg.KNNThreshold, int(r.cfg.KNNHistory), int(r.cfg.KNNKernel), r.cfg.ShowWindows, r.cfg.MotionInterval)
case config.FilterDifference:
@ -904,6 +904,13 @@ func (r *Revid) Update(vars map[string]string) error {
if value == "Loop" {
r.cfg.Loop = true
}
case "MotionDownscaling":
v, err := strconv.Atoi(value)
if err != nil {
r.cfg.Logger.Log(logger.Warning, pkg+"invalid MotionDownscaling var", "value", value)
break
}
r.cfg.MotionDownscaling = v
}
}
r.cfg.Logger.Log(logger.Info, pkg+"revid config changed", "config", fmt.Sprintf("%+v", r.cfg))