commit 58e49c66d9061813536f09825e5c3ea34d879284 Author: danil_e71 Date: Mon Oct 11 16:06:58 2021 +0300 Init repo diff --git a/README.md b/README.md new file mode 100644 index 0000000..31c7195 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# go-face examples + +## Requirements + +To compile face you need to have [go-face](github.com/Danile71/go-face) and [gocv](gocv.io/x/gocv) + +### [face](face/) + +### [plate](plate/) + +### [tracking](tracking/) \ No newline at end of file diff --git a/face/.gitignore b/face/.gitignore new file mode 100644 index 0000000..e51b43a --- /dev/null +++ b/face/.gitignore @@ -0,0 +1,2 @@ +/models/*dat +face diff --git a/face/README.md b/face/README.md new file mode 100644 index 0000000..aa7691b --- /dev/null +++ b/face/README.md @@ -0,0 +1,11 @@ +# go-face examples + +## Requirements + +To compile face you need to have [go-face](github.com/Danile71/go-face) and [gocv](gocv.io/x/gocv) + +![screen](./images/screen.jpg) + +1. cd models && ./download_models.sh +2. go build -tags gocv +3. ./face diff --git a/face/go.mod b/face/go.mod new file mode 100644 index 0000000..73213fc --- /dev/null +++ b/face/go.mod @@ -0,0 +1,9 @@ +module github.com/Danile71/go-face-examples/face + +go 1.16 + +require ( + github.com/Danile71/go-face v0.1.1 + github.com/Danile71/go-logger v0.1.2 // indirect + gocv.io/x/gocv v0.28.0 // indirect +) diff --git a/face/go.sum b/face/go.sum new file mode 100644 index 0000000..aee1014 --- /dev/null +++ b/face/go.sum @@ -0,0 +1,9 @@ +github.com/Danile71/go-face v0.1.1 h1:lNaSNTOIJQ7YoGxD/d2nkiBChvSaE0gvrxJC/DTXHt8= +github.com/Danile71/go-face v0.1.1/go.mod h1:C83Krj1aVVsvlaIcyjn5hUZYYBIgX0BYvW6PMqzh1/Q= +github.com/Danile71/go-logger v0.1.2 h1:7RdHu2QntvvGJvdVaekiVGDL3FhkeUFiG90OTtY8wQU= +github.com/Danile71/go-logger v0.1.2/go.mod h1:saFCu/TU1L2Ypl48em66PQcFGy9lHz8lzn42bulF7W4= +github.com/Kagami/go-face v0.0.0-20200825065730-3dd2d74dccfb/go.mod h1:9wdDJkRgo3SGTcFwbQ7elVIQhIr2bbBjecuY7VoqmPU= +github.com/hybridgroup/mjpeg v0.0.0-20140228234708-4680f319790e/go.mod h1:eagM805MRKrioHYuU7iKLUyFPVKqVV6um5DAvCkUtXs= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +gocv.io/x/gocv v0.28.0 h1:hweRS9Js60YEZPZzjhU5I+0E2ngazquLlO78zwnrFvY= +gocv.io/x/gocv v0.28.0/go.mod h1:oc6FvfYqfBp99p+yOEzs9tbYF9gOrAQSeL/dyIPefJU= diff --git a/face/images/face.jpg b/face/images/face.jpg new file mode 100644 index 0000000..61db266 Binary files /dev/null and b/face/images/face.jpg differ diff --git a/face/images/faces.jpg b/face/images/faces.jpg new file mode 100644 index 0000000..a5b6fa9 Binary files /dev/null and b/face/images/faces.jpg differ diff --git a/face/images/screen.jpg b/face/images/screen.jpg new file mode 100644 index 0000000..21bb8f8 Binary files /dev/null and b/face/images/screen.jpg differ diff --git a/face/main.go b/face/main.go new file mode 100644 index 0000000..97827d6 --- /dev/null +++ b/face/main.go @@ -0,0 +1,165 @@ +package main + +import ( + "fmt" + "image" + "image/color" + + "github.com/Danile71/go-face" + "github.com/Danile71/go-logger" + "gocv.io/x/gocv" +) + +const ( + cnnModel = "models/mmod_human_face_detector.dat" + + shapeModel = "models/shape_predictor_68_face_landmarks.dat" // "models/shape_predictor_5_face_landmarks.dat" + descrModel = "models/dlib_face_recognition_resnet_model_v1.dat" + ageModel = "models/dnn_age_predictor_v1.dat" + genderModel = "models/dnn_gender_classifier_v1.dat" + + faceImage = "images/face.jpg" + facesImage = "images/faces.jpg" +) + +var ( + greenColor = color.RGBA{0, 255, 0, 255} + redColor = color.RGBA{255, 0, 0, 255} +) + +func init() { + logger.SetLevel(logger.DEBUG) +} + +func main() { + // try to find him + var descriptor face.Descriptor + + // craete window + w := gocv.NewWindow("example") + defer w.Close() + + // Init recognizer + rec, err := face.NewRecognizer() + if logger.OnError(err) { + return + } + // close it + defer rec.Close() + + // Load shape model + if err = rec.SetShapeModel(shapeModel); logger.OnError(err) { + return + } + + // Load description model + if err = rec.SetDescriptorModel(descrModel); logger.OnError(err) { + return + } + + // Load age model + if err = rec.SetAgeModel(ageModel); logger.OnError(err) { + return + } + + // Load gener model + if err = rec.SetGenderModel(genderModel); logger.OnError(err) { + return + } + + // Load CNN model + if err = rec.SetCNNModel(cnnModel); logger.OnError(err) { + return + } + + // load first image + img1 := gocv.IMRead(faceImage, gocv.IMReadUnchanged) + defer img1.Close() + + // load second image + img2 := gocv.IMRead(facesImage, gocv.IMReadUnchanged) + defer img2.Close() + + // copy bg to draw + background := img2.Clone() + defer background.Close() + + // try detect faces + faces, err := rec.DetectFromMatCNN(img1) + if logger.OnError(err) { + return + } + + for _, f := range faces { + defer f.Close() + + // get face description + if err = rec.Recognize(&f); err != nil { + return + } + + // predict face age + rec.GetAge(&f) + + // predict face gender + rec.GetGender(&f) + + // set descriptor + descriptor = f.Descriptor + + // draw rect + gocv.Rectangle(&img1, f.Rectangle, greenColor, 2) + + gocv.PutText(&img1, fmt.Sprintf("%s:%d y.o.", f.Gender, f.Age), image.Point{f.Rectangle.Min.X - 20, f.Rectangle.Min.Y - 5}, gocv.FontHersheyPlain, 1, redColor, 1) + + } + gocv.PutText(&img1, "press any key...", image.Point{0, img1.Cols() - 30}, gocv.FontHersheyPlain, 1, redColor, 1) + + w.IMShow(img1) + + fmt.Println("press any key to continue...") + + for { + if key := w.WaitKey(1000); key != -1 { + break + } + } + + faces, err = rec.DetectFromMatCNN(img2) + if logger.OnError(err) { + return + } + + for _, f := range faces { + defer f.Close() + + if err = rec.Recognize(&f); err != nil { + return + } + + rec.GetAge(&f) + rec.GetGender(&f) + gocv.Rectangle(&background, f.Rectangle, greenColor, 2) + + gocv.PutText(&background, fmt.Sprintf("%s:%d y.o.", f.Gender, f.Age), image.Point{f.Rectangle.Min.X - 20, f.Rectangle.Min.Y - 5}, gocv.FontHersheyPlain, 1, redColor, 1) + + dist := face.SquaredEuclideanDistance(f.Descriptor, descriptor) + + c := redColor + if dist < 0.1 { + c = greenColor + } + + gocv.PutText(&background, fmt.Sprintf("%f", dist), image.Point{f.Rectangle.Min.X, f.Rectangle.Max.Y}, gocv.FontHersheyPlain, 1, c, 1) + } + + w.IMShow(background) + + fmt.Println("press any key to exit...") + + for { + if key := w.WaitKey(1000); key != -1 { + return + } + } +} diff --git a/face/models/download_models.sh b/face/models/download_models.sh new file mode 100755 index 0000000..a662deb --- /dev/null +++ b/face/models/download_models.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +if [ ! -f "shape_predictor_5_face_landmarks.dat" ]; then + wget https://github.com/davisking/dlib-models/raw/master/shape_predictor_5_face_landmarks.dat.bz2 + bunzip2 shape_predictor_5_face_landmarks.dat.bz2 +fi + +if [ ! -f "shape_predictor_68_face_landmarks.dat" ]; then + wget https://github.com/davisking/dlib-models/raw/master/shape_predictor_68_face_landmarks.dat.bz2 + bunzip2 shape_predictor_68_face_landmarks.dat.bz2 +fi + +if [ ! -f "dlib_face_recognition_resnet_model_v1.dat" ]; then + wget https://github.com/davisking/dlib-models/raw/master/dlib_face_recognition_resnet_model_v1.dat.bz2 + bunzip2 dlib_face_recognition_resnet_model_v1.dat.bz2 +fi + +if [ ! -f "mmod_human_face_detector.dat" ]; then + wget https://github.com/davisking/dlib-models/raw/master/mmod_human_face_detector.dat.bz2 + bunzip2 mmod_human_face_detector.dat.bz2 +fi + +if [ ! -f "dnn_age_predictor_v1.dat" ]; then + wget https://github.com/davisking/dlib-models/raw/master/age-predictor/dnn_age_predictor_v1.dat.bz2 + bunzip2 dnn_age_predictor_v1.dat.bz2 +fi + +if [ ! -f "dnn_gender_classifier_v1.dat" ]; then + wget https://github.com/davisking/dlib-models/raw/master/gender-classifier/dnn_gender_classifier_v1.dat.bz2 + bunzip2 dnn_gender_classifier_v1.dat.bz2 +fi diff --git a/plate/.gitignore b/plate/.gitignore new file mode 100644 index 0000000..2bfebf1 --- /dev/null +++ b/plate/.gitignore @@ -0,0 +1 @@ +plate diff --git a/plate/README.md b/plate/README.md new file mode 100644 index 0000000..869370a --- /dev/null +++ b/plate/README.md @@ -0,0 +1,11 @@ +# go-face examples +## Russian plate numbers + +## Requirements + +To compile face you need to have [go-face](github.com/Danile71/go-face) and [gocv](gocv.io/x/gocv) + +![screen](./images/screen.jpg) + +1. go build -tags gocv +2. ./plate diff --git a/plate/go.mod b/plate/go.mod new file mode 100644 index 0000000..151dedf --- /dev/null +++ b/plate/go.mod @@ -0,0 +1,9 @@ +module github.com/Danile71/go-face-examples/plate + +go 1.16 + +require ( + github.com/Danile71/go-face v0.1.1 + github.com/Danile71/go-logger v0.1.2 // indirect + gocv.io/x/gocv v0.28.0 // indirect +) diff --git a/plate/go.sum b/plate/go.sum new file mode 100644 index 0000000..aee1014 --- /dev/null +++ b/plate/go.sum @@ -0,0 +1,9 @@ +github.com/Danile71/go-face v0.1.1 h1:lNaSNTOIJQ7YoGxD/d2nkiBChvSaE0gvrxJC/DTXHt8= +github.com/Danile71/go-face v0.1.1/go.mod h1:C83Krj1aVVsvlaIcyjn5hUZYYBIgX0BYvW6PMqzh1/Q= +github.com/Danile71/go-logger v0.1.2 h1:7RdHu2QntvvGJvdVaekiVGDL3FhkeUFiG90OTtY8wQU= +github.com/Danile71/go-logger v0.1.2/go.mod h1:saFCu/TU1L2Ypl48em66PQcFGy9lHz8lzn42bulF7W4= +github.com/Kagami/go-face v0.0.0-20200825065730-3dd2d74dccfb/go.mod h1:9wdDJkRgo3SGTcFwbQ7elVIQhIr2bbBjecuY7VoqmPU= +github.com/hybridgroup/mjpeg v0.0.0-20140228234708-4680f319790e/go.mod h1:eagM805MRKrioHYuU7iKLUyFPVKqVV6um5DAvCkUtXs= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +gocv.io/x/gocv v0.28.0 h1:hweRS9Js60YEZPZzjhU5I+0E2ngazquLlO78zwnrFvY= +gocv.io/x/gocv v0.28.0/go.mod h1:oc6FvfYqfBp99p+yOEzs9tbYF9gOrAQSeL/dyIPefJU= diff --git a/plate/images/numbers.jpg b/plate/images/numbers.jpg new file mode 100644 index 0000000..07626d7 Binary files /dev/null and b/plate/images/numbers.jpg differ diff --git a/plate/images/screen.jpg b/plate/images/screen.jpg new file mode 100644 index 0000000..c663a26 Binary files /dev/null and b/plate/images/screen.jpg differ diff --git a/plate/main.go b/plate/main.go new file mode 100644 index 0000000..7cd480b --- /dev/null +++ b/plate/main.go @@ -0,0 +1,71 @@ +package main + +import ( + "fmt" + "image/color" + + "github.com/Danile71/go-face" + "github.com/Danile71/go-logger" + "gocv.io/x/gocv" +) + +const ( + cnnModel = "models/mmod_plate_detector.dat" + + plateImage = "images/numbers.jpg" +) + +var ( + greenColor = color.RGBA{0, 255, 0, 255} + redColor = color.RGBA{255, 0, 0, 255} +) + +func init() { + logger.SetLevel(logger.DEBUG) +} + +func main() { + // create window + w := gocv.NewWindow("example") + defer w.Close() + + // Init recognizer + rec, err := face.NewRecognizer() + if logger.OnError(err) { + return + } + // close it + defer rec.Close() + + // Load CNN model + if err = rec.SetCNNModel(cnnModel); logger.OnError(err) { + return + } + + // load first image + img := gocv.IMRead(plateImage, gocv.IMReadUnchanged) + defer img.Close() + + // try detect plates + plates, err := rec.DetectFromMatCNN(img) + if logger.OnError(err) { + return + } + + for _, p := range plates { + defer p.Close() + + // draw rect + gocv.Rectangle(&img, p.Rectangle, greenColor, 2) + } + + w.IMShow(img) + + fmt.Println("press any key to exit...") + + for { + if key := w.WaitKey(1000); key != -1 { + return + } + } +} diff --git a/plate/models/mmod_plate_detector.dat b/plate/models/mmod_plate_detector.dat new file mode 100644 index 0000000..b694c61 Binary files /dev/null and b/plate/models/mmod_plate_detector.dat differ diff --git a/tracking/.gitignore b/tracking/.gitignore new file mode 100644 index 0000000..e7a19e7 --- /dev/null +++ b/tracking/.gitignore @@ -0,0 +1 @@ +tracking diff --git a/tracking/README.md b/tracking/README.md new file mode 100644 index 0000000..e58285f --- /dev/null +++ b/tracking/README.md @@ -0,0 +1,13 @@ +# go-face examples +## Russian plate numbers + +## Requirements + +To compile face you need to have [go-face](github.com/Danile71/go-face) and [gocv](gocv.io/x/gocv) + +![screen](./images/screen.jpg) +[youtube](https://youtu.be/JFRfxLJ9CIM) + + +1. go build -tags gocv +2. ./plate diff --git a/tracking/go.mod b/tracking/go.mod new file mode 100644 index 0000000..a120acc --- /dev/null +++ b/tracking/go.mod @@ -0,0 +1,9 @@ +module github.com/Danile71/go-face-examples/tracking + +go 1.16 + +require ( + github.com/Danile71/go-face v0.1.1 + github.com/Danile71/go-logger v0.1.2 // indirect + gocv.io/x/gocv v0.28.0 // indirect +) diff --git a/tracking/go.sum b/tracking/go.sum new file mode 100644 index 0000000..aee1014 --- /dev/null +++ b/tracking/go.sum @@ -0,0 +1,9 @@ +github.com/Danile71/go-face v0.1.1 h1:lNaSNTOIJQ7YoGxD/d2nkiBChvSaE0gvrxJC/DTXHt8= +github.com/Danile71/go-face v0.1.1/go.mod h1:C83Krj1aVVsvlaIcyjn5hUZYYBIgX0BYvW6PMqzh1/Q= +github.com/Danile71/go-logger v0.1.2 h1:7RdHu2QntvvGJvdVaekiVGDL3FhkeUFiG90OTtY8wQU= +github.com/Danile71/go-logger v0.1.2/go.mod h1:saFCu/TU1L2Ypl48em66PQcFGy9lHz8lzn42bulF7W4= +github.com/Kagami/go-face v0.0.0-20200825065730-3dd2d74dccfb/go.mod h1:9wdDJkRgo3SGTcFwbQ7elVIQhIr2bbBjecuY7VoqmPU= +github.com/hybridgroup/mjpeg v0.0.0-20140228234708-4680f319790e/go.mod h1:eagM805MRKrioHYuU7iKLUyFPVKqVV6um5DAvCkUtXs= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +gocv.io/x/gocv v0.28.0 h1:hweRS9Js60YEZPZzjhU5I+0E2ngazquLlO78zwnrFvY= +gocv.io/x/gocv v0.28.0/go.mod h1:oc6FvfYqfBp99p+yOEzs9tbYF9gOrAQSeL/dyIPefJU= diff --git a/tracking/images/screen.jpg b/tracking/images/screen.jpg new file mode 100644 index 0000000..b05ee9a Binary files /dev/null and b/tracking/images/screen.jpg differ diff --git a/tracking/main.go b/tracking/main.go new file mode 100644 index 0000000..808d8b4 --- /dev/null +++ b/tracking/main.go @@ -0,0 +1,116 @@ +package main + +import ( + "fmt" + "image/color" + + "github.com/Danile71/go-face" + "github.com/Danile71/go-logger" + "gocv.io/x/gocv" +) + +const ( + cnnModel = "models/mmod_plate_detector.dat" + + plateVideo = "video/video.mp4" +) + +var ( + greenColor = color.RGBA{0, 255, 0, 255} + redColor = color.RGBA{255, 0, 0, 255} +) + +func init() { + logger.SetLevel(logger.DEBUG) +} + +func main() { + // create window + w := gocv.NewWindow("example") + defer w.Close() + + // Init recognizer + rec, err := face.NewRecognizer() + if logger.OnError(err) { + return + } + // close it + defer rec.Close() + + // Load CNN model + if err = rec.SetCNNModel(cnnModel); logger.OnError(err) { + return + } + + img := gocv.NewMat() + defer img.Close() + + frames, err := gocv.VideoCaptureFile(plateVideo) + if logger.OnError(err) { + return + } + + trackers := make(map[int]*face.Tracker) + + for { + if ok := frames.Read(&img); !ok { + return + } + + if len(trackers) == 0 { + // try detect plates + plates, err := rec.DetectFromMatCNN(img) + if logger.OnError(err) { + return + } + + for _, p := range plates { + tracker, err := face.NewTracker() + if logger.OnError(err) { + return + } + + tracker.StartMat(img, p.Rectangle) + + trackers[len(trackers)] = tracker + + // draw rect + gocv.Rectangle(&img, p.Rectangle, greenColor, 2) + + p.Close() + } + } + + for key, tracker := range trackers { + conf, err := tracker.UpdateMat(img) + if conf < 3 || err != nil { + delete(trackers, key) + continue + } + + position, err := tracker.Position() + if err != nil { + delete(trackers, key) + continue + } + + // draw rect + gocv.Rectangle(&img, position, greenColor, 2) + } + + w.IMShow(img) + + if key := w.WaitKey(1); key != -1 { + return + } + + } + + fmt.Println("press any key to exit...") + + for { + if key := w.WaitKey(1000); key != -1 { + return + } + } +} diff --git a/tracking/models/mmod_plate_detector.dat b/tracking/models/mmod_plate_detector.dat new file mode 100644 index 0000000..b694c61 Binary files /dev/null and b/tracking/models/mmod_plate_detector.dat differ diff --git a/tracking/video/video.mp4 b/tracking/video/video.mp4 new file mode 100644 index 0000000..88b0344 Binary files /dev/null and b/tracking/video/video.mp4 differ