diff --git a/filter/basic.go b/filter/basic.go index 366a7713..a4f8d5a5 100644 --- a/filter/basic.go +++ b/filter/basic.go @@ -40,34 +40,30 @@ type pixel struct{ r, g, b uint32 } // Basic is a filter that provides basic motion detection via a difference // method. type Basic struct { - debugFile - dst io.WriteCloser - img image.Image - bg [][]pixel - thresh int - pix int - w int - h int - motion int + debugging debugFile + dst io.WriteCloser + img image.Image + bg [][]pixel + thresh int + pix int + w int + h int + motion int } // NewBasic returns a pointer to a new Basic filter struct. func NewBasic(dst io.WriteCloser, t, p int) *Basic { - bf := &Basic{ - dst: dst, - thresh: t, - pix: p, + return &Basic{ + dst: dst, + thresh: t, + pix: p, + debugging: newDebugFile(), } - err := bf.newDebugFile() - if err != nil { - panic(fmt.Sprintf("could not create debug file: %w", err)) - } - return bf } // Implements io.Closer. func (bf *Basic) Close() error { - return bf.closeDebugFile() + return bf.debugging.close() } // Implements io.Writer. @@ -87,7 +83,7 @@ func (bf *Basic) Write(f []byte) (int, error) { bf.w = bounds.Max.X bf.h = bounds.Max.Y - bf.resetDebugFileFrame(bf.w, bf.h) + bf.debugging.resetFrame(bf.w, bf.h) bf.bg = make([][]pixel, bf.h) for j, _ := range bf.bg { @@ -119,7 +115,7 @@ func (bf *Basic) Write(f []byte) (int, error) { } // Will save a video of where motion is detected in motion.mjpeg (in the current folder). - err = bf.saveFrame(bf.motion, bf.pix) + err = bf.debugging.saveFrame(bf.motion, bf.pix) if err != nil { return len(f), fmt.Errorf("image can't be encoded for debug video: %w", err) } @@ -148,9 +144,9 @@ func (bf *Basic) process(j int, wg *sync.WaitGroup) { if diff > bf.thresh { bf.motion++ - bf.drawToDebugFile(i, j, 0xff) + bf.debugging.draw(i, j, 0xff) } else { - bf.drawToDebugFile(i, j, 0x00) + bf.debugging.draw(i, j, 0x00) } // Update backgound image. diff --git a/filter/debug.go b/filter/debug.go index eaff77eb..34af5aab 100644 --- a/filter/debug.go +++ b/filter/debug.go @@ -47,16 +47,22 @@ type debugFile struct { } // newDebugFile creates a file for saving debugging frames to. -func (d *debugFile) newDebugFile() error { +func newDebugFile() debugFile { const debugfile = "motion.mjpeg" - d.bwImg = image.NewRGBA(image.Rect(0, 0, 0, 0)) - var err error - d.file, err = os.Create(debugfile) - return err + + file, err := os.Create(debugfile) + if err != nil { + panic(fmt.Sprintf("could not create debug file: %w", err)) + } + + return debugFile{ + bwImg: image.NewRGBA(image.Rect(0, 0, 0, 0)), + file: file, + } } -// closeDebugFile closes files used for debugging purposes. -func (d *debugFile) closeDebugFile() error { +// close closes files used for debugging purposes. +func (d *debugFile) close() error { err := d.file.Close() if err != nil { return fmt.Errorf("file cannot be closed: %w", err) @@ -64,8 +70,8 @@ func (d *debugFile) closeDebugFile() error { return nil } -// drawToDebugFile draws debugging information to a frame. -func (d *debugFile) drawToDebugFile(i, j int, val uint8) { +// draw draws debugging information to a frame. +func (d *debugFile) draw(i, j int, val uint8) { d.bwImg.SetRGBA(i, j, color.RGBA{val, val, val, 0xff}) } @@ -90,7 +96,7 @@ func (d *debugFile) saveFrame(motion, pix int) error { return jpeg.Encode(d.file, d.bwImg, nil) } -// resetDebugFileFrame makes an image of given dimensions. -func (d *debugFile) resetDebugFileFrame(w, h int) { +// resetFrame makes an image of given dimensions. +func (d *debugFile) resetFrame(w, h int) { d.bwImg = image.NewRGBA(image.Rect(0, 0, w, h)) } diff --git a/filter/debug_nocircleci.go b/filter/debug_nocircleci.go index a39d6883..87337ad4 100644 --- a/filter/debug_nocircleci.go +++ b/filter/debug_nocircleci.go @@ -39,20 +39,25 @@ type debugWindows struct { windows []*gocv.Window } -// closeWindows frees resources used by gocv. -func (d *debugWindows) closeWindows() { +// close frees resources used by gocv. +func (d *debugWindows) close() { for _, window := range d.windows { window.Close() } } // newWindows creates debugging windows for the motion filter. -func (d *debugWindows) newWindows(name string) { - d.windows = []*gocv.Window{gocv.NewWindow(name + ": Bounding boxes"), gocv.NewWindow(name + ": Motion")} +func newWindows(name string) debugWindows { + return debugWindows{ + windows: []*gocv.Window{ + gocv.NewWindow(name + ": Bounding boxes"), + gocv.NewWindow(name + ": Motion"), + }, + } } -// showDebug displays debug information for the motion filters. -func (d *debugWindows) showDebug(img, imgDelta gocv.Mat, motion bool, contours ...[][]image.Point) { +// show displays debug information for the motion filters. +func (d *debugWindows) show(img, imgDelta gocv.Mat, motion bool, contours ...[][]image.Point) { if len(contours) > 0 { for _, c := range contours[0] { rect := gocv.BoundingRect(c) diff --git a/filter/difference.go b/filter/difference.go index ff3a9751..dfc3fcde 100644 --- a/filter/difference.go +++ b/filter/difference.go @@ -39,21 +39,20 @@ import ( // 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. type Difference struct { - debugWindows - dst io.WriteCloser - thresh float64 - prev gocv.Mat + debugging debugWindows + dst io.WriteCloser + thresh float64 + prev gocv.Mat } // NewDifference returns a pointer to a new Difference struct. func NewDifference(dst io.WriteCloser, threshold float64) *Difference { - d := &Difference{ - dst: dst, - thresh: threshold, - prev: gocv.NewMat(), + return &Difference{ + dst: dst, + thresh: threshold, + prev: gocv.NewMat(), + debugging: newWindows("DIFF"), } - d.newWindows("DIFF") - return d } // Implements io.Closer. @@ -61,7 +60,7 @@ func NewDifference(dst io.WriteCloser, threshold float64) *Difference { // it using c-go. func (d *Difference) Close() error { d.prev.Close() - d.closeWindows() + d.debugging.close() return nil } @@ -97,7 +96,7 @@ func (d *Difference) Write(f []byte) (int, error) { d.prev = img.Clone() // Draw debug information. - d.showDebug(img, imgDelta, mean > d.thresh) + d.debugging.show(img, imgDelta, mean > d.thresh) // Don't write to destination if there is no motion. if mean < d.thresh { diff --git a/filter/knn.go b/filter/knn.go index 1624f6b6..03c7be55 100644 --- a/filter/knn.go +++ b/filter/knn.go @@ -39,32 +39,31 @@ import ( // KNN is a filter that provides basic motion detection. KNN is short for // K-Nearest Neighbours method. type KNN struct { - debugWindows - 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. - 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. + debugging debugWindows + 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. + 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. } // NewKNN returns a pointer to a new KNN filter struct. func NewKNN(dst io.WriteCloser, area, threshold float64, history, kernelSize int, hf int, scaleFactor int) *KNN { bs := gocv.NewBackgroundSubtractorKNNWithParams(history, threshold, false) k := gocv.GetStructuringElement(gocv.MorphRect, image.Pt(kernelSize, kernelSize)) - m := &KNN{ - dst: dst, - area: area, - bs: &bs, - knl: k, - hold: make([][]byte, hf-1), - hf: hf, - scale: 1 / float64(scaleFactor), + return &KNN{ + dst: dst, + area: area, + bs: &bs, + knl: k, + hold: make([][]byte, hf-1), + hf: hf, + scale: 1 / float64(scaleFactor), + debugging: newWindows("KNN"), } - m.newWindows("KNN") - return m } // Implements io.Closer. @@ -73,7 +72,7 @@ func NewKNN(dst io.WriteCloser, area, threshold float64, history, kernelSize int func (m *KNN) Close() error { m.bs.Close() m.knl.Close() - m.closeWindows() + m.debugging.close() return nil } @@ -124,7 +123,7 @@ func (m *KNN) Write(f []byte) (int, error) { } // Draw debug information. - m.showDebug(img, imgDelta, len(contours) > 0, contours) + m.debugging.show(img, imgDelta, len(contours) > 0, contours) // Don't write to destination if there is no motion. if len(contours) == 0 { diff --git a/filter/mog.go b/filter/mog.go index ebd25644..b096e7b3 100644 --- a/filter/mog.go +++ b/filter/mog.go @@ -39,32 +39,31 @@ import ( // MOG is a filter that provides basic motion detection. MoG is short for // Mixture of Gaussians method. type MOG struct { - debugWindows - dst io.WriteCloser // Destination to which motion containing frames go. - area float64 // The minimum area that a contour can be found in. - bs *gocv.BackgroundSubtractorMOG2 // Uses the MOG algorithm to find the difference between the current and background frame. - knl gocv.Mat // Matrix that is used for calculations. - 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. + debugging debugWindows + dst io.WriteCloser // Destination to which motion containing frames go. + area float64 // The minimum area that a contour can be found in. + bs *gocv.BackgroundSubtractorMOG2 // Uses the MOG algorithm to find the difference between the current and background frame. + knl gocv.Mat // Matrix that is used for calculations. + 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, hf int, scaleFactor int) *MOG { bs := gocv.NewBackgroundSubtractorMOG2WithParams(history, threshold, false) k := gocv.GetStructuringElement(gocv.MorphRect, image.Pt(3, 3)) - m := &MOG{ - dst: dst, - area: area, - bs: &bs, - knl: k, - hold: make([][]byte, hf-1), - hf: hf, - scale: 1 / float64(scaleFactor), + return &MOG{ + dst: dst, + area: area, + bs: &bs, + knl: k, + hold: make([][]byte, hf-1), + hf: hf, + scale: 1 / float64(scaleFactor), + debugging: newWindows("MOG"), } - m.newWindows("MOG") - return m } // Implements io.Closer. @@ -73,7 +72,7 @@ func NewMOG(dst io.WriteCloser, area, threshold float64, history int, hf int, sc func (m *MOG) Close() error { m.bs.Close() m.knl.Close() - m.closeWindows() + m.debugging.close() return nil } @@ -124,7 +123,7 @@ func (m *MOG) Write(f []byte) (int, error) { } // Draw debug information. - m.showDebug(img, imgDelta, len(contours) > 0, contours) + m.debugging.show(img, imgDelta, len(contours) > 0, contours) // Don't write to destination if there is no motion. if len(contours) == 0 { diff --git a/filter/release.go b/filter/release.go index 0bf7b3c8..079ecee5 100644 --- a/filter/release.go +++ b/filter/release.go @@ -2,7 +2,7 @@ /* DESCRIPTION - Displays debug information for the motion filters. + Doesn't display debug information for the motion filters. AUTHORS Scott Barnard @@ -30,16 +30,16 @@ package filter type debugFile struct{} // newDebugFile creates a file for saving debugging frames to. -func (d *debugFile) newDebugFile() error { return nil } +func newDebugFile() debugFile { return debugFile{} } -// closeDebugFile closes files used for debugging purposes. -func (d *debugFile) closeDebugFile() error { return nil } +// close closes files used for debugging purposes. +func (d *debugFile) close() error { return nil } -// drawToDebugFile draws debugging information to a frame. -func (d *debugFile) drawToDebugFile(i, j int, val uint8) {} +// draw draws debugging information to a frame. +func (d *debugFile) draw(i, j int, val uint8) {} // saveFrame writes a frame showing motion to a file. func (d *debugFile) saveFrame(motion, pix int) error { return nil } -// resetDebugFileFrame makes an image of given dimensions. -func (d *debugFile) resetDebugFileFrame(w, h int) {} +// resetFrame makes an image of given dimensions. +func (d *debugFile) resetFrame(w, h int) {} diff --git a/filter/release_nocircleci.go b/filter/release_nocircleci.go index 51b1d65e..0276b457 100644 --- a/filter/release_nocircleci.go +++ b/filter/release_nocircleci.go @@ -3,7 +3,7 @@ /* DESCRIPTION - Displays debug information for the motion filters. + Doesn't display debug information for the motion filters. AUTHORS Scott Barnard @@ -36,11 +36,11 @@ import ( // debugWindows is used for displaying debug information for the motion filters. type debugWindows struct{} -// closeWindows frees resources used by gocv. -func (d *debugWindows) closeWindows() {} +// close frees resources used by gocv. +func (d *debugWindows) close() {} // newWindows creates debugging windows for the motion filter. -func (d *debugWindows) newWindows(name string) {} +func newWindows(name string) debugWindows { return debugWindows{} } -// showDebug displays debug information for the motion filters. -func (d *debugWindows) showDebug(img, imgDelta gocv.Mat, motion bool, contours ...[][]image.Point) {} +// show displays debug information for the motion filters. +func (d *debugWindows) show(img, imgDelta gocv.Mat, motion bool, contours ...[][]image.Point) {}