2022-01-05 06:44:22 +03:00
|
|
|
//go:build !nocv
|
2021-05-17 04:21:50 +03:00
|
|
|
// +build !nocv
|
2019-12-31 04:56:35 +03:00
|
|
|
|
2019-12-16 05:17:43 +03:00
|
|
|
// What it does:
|
|
|
|
//
|
|
|
|
// This example detects motion using a delta threshold from the first frame,
|
|
|
|
// and then finds contours to determine where the object is located.
|
|
|
|
//
|
|
|
|
// Very loosely based on Adrian Rosebrock code located at:
|
|
|
|
// http://www.pyimagesearch.com/2015/06/01/home-surveillance-and-motion-detection-with-the-raspberry-pi-python-and-opencv/
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"image"
|
|
|
|
"image/color"
|
|
|
|
"os"
|
|
|
|
"strconv"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"gocv.io/x/gocv"
|
|
|
|
)
|
|
|
|
|
|
|
|
const MinimumArea = 1000
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
if len(os.Args) < 2 {
|
|
|
|
fmt.Println("How to run:\n\tmotion-detect [camera ID]")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// parse args
|
|
|
|
deviceID := os.Args[1]
|
|
|
|
minArea, _ := strconv.Atoi(os.Args[2])
|
|
|
|
|
|
|
|
webcam, err := gocv.OpenVideoCapture(deviceID)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("Error opening video capture device: %v\n", deviceID)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer webcam.Close()
|
|
|
|
|
|
|
|
window1 := gocv.NewWindow("Motion Window")
|
|
|
|
defer window1.Close()
|
|
|
|
|
|
|
|
window2 := gocv.NewWindow("Threshold window")
|
|
|
|
defer window2.Close()
|
|
|
|
|
|
|
|
time.Sleep(2 * time.Second)
|
|
|
|
|
|
|
|
img := gocv.NewMat()
|
|
|
|
defer img.Close()
|
|
|
|
|
|
|
|
imgDelta := gocv.NewMat()
|
|
|
|
defer imgDelta.Close()
|
|
|
|
|
|
|
|
imgThresh := gocv.NewMat()
|
|
|
|
defer imgThresh.Close()
|
|
|
|
|
|
|
|
mog2 := gocv.NewBackgroundSubtractorMOG2()
|
|
|
|
defer mog2.Close()
|
|
|
|
|
|
|
|
status := "Ready"
|
|
|
|
|
|
|
|
fmt.Printf("Start reading device: %v\n", deviceID)
|
|
|
|
for {
|
|
|
|
if ok := webcam.Read(&img); !ok {
|
|
|
|
fmt.Printf("Device closed: %v\n", deviceID)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if img.Empty() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
status = "READY"
|
|
|
|
statusColor := color.RGBA{0, 255, 0, 0}
|
|
|
|
|
|
|
|
// first phase of cleaning up image, obtain foreground only
|
|
|
|
mog2.Apply(img, &imgDelta)
|
|
|
|
|
|
|
|
// remaining cleanup of the image to use for finding contours.
|
|
|
|
// first use threshold
|
|
|
|
gocv.Threshold(imgDelta, &imgThresh, 25, 255, gocv.ThresholdBinary)
|
|
|
|
|
|
|
|
// then dilate
|
|
|
|
kernel := gocv.GetStructuringElement(gocv.MorphRect, image.Pt(3, 3))
|
|
|
|
defer kernel.Close()
|
|
|
|
|
|
|
|
// Erode
|
|
|
|
gocv.Erode(imgThresh, &imgThresh, kernel)
|
|
|
|
// Dilate
|
|
|
|
gocv.Dilate(imgThresh, &imgThresh, kernel)
|
|
|
|
|
|
|
|
// now find contours
|
|
|
|
contours := gocv.FindContours(imgThresh, gocv.RetrievalExternal, gocv.ChainApproxSimple)
|
2022-01-05 06:44:22 +03:00
|
|
|
for i := 0; i < contours.Size(); i++ {
|
|
|
|
area := gocv.ContourArea(contours.At(i))
|
2019-12-16 05:17:43 +03:00
|
|
|
if area < float64(minArea) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
status = "MOTION DETECTED"
|
|
|
|
statusColor = color.RGBA{255, 0, 0, 0}
|
|
|
|
|
|
|
|
//gocv.DrawContours(&img, contours, i, statusColor, 2)
|
|
|
|
|
2022-01-05 06:44:22 +03:00
|
|
|
rect := gocv.BoundingRect(contours.At(i))
|
2019-12-16 05:17:43 +03:00
|
|
|
gocv.Rectangle(&img, rect, color.RGBA{0, 0, 255, 0}, 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
gocv.PutText(&img, status, image.Pt(10, 20), gocv.FontHersheyPlain, 1.2, statusColor, 2)
|
|
|
|
|
|
|
|
window1.IMShow(img)
|
|
|
|
window2.IMShow(imgThresh)
|
|
|
|
if window1.WaitKey(1) == 27 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|