Speaking of face recognition, we first think of the implementation should be Python to do the relevant processing, because the relevant machine learning framework, libraries have been packaged better. However, the implementation method we discussed today is changed to Golang, and Golang is used to do the corresponding processing of face recognition in static images and video streams.
Face recognition in static images
Let’s start with static face recognition, which is relatively rare on Golang’s side compared to the Python community, but there are still some good libraries to work with. Today we’re going to use the Go-Face library. Face recognition is implemented using Dlib, a popular set of machine learning tools that is arguably one of the most used software packages in face recognition. It is widely used in industry and academia, covering robotics, embedded devices, mobile devices and so on. The documentation on its website states that it was able to identify tagged faces with an astonishing 99.4% accuracy in the Wild Benchmark, which explains why it is so widely used.
Before we start coding, we need to install the Dlib. The Windows platform is relatively troublesome, and the specific installation scheme is available on the official website. Here I will introduce the two platforms.
Ubuntu 18.10 +, Debian sid
The latest versions of Ubuntu and Debian both provide suitable dlib packages, so you just need to run them.
# Ubuntu
sudo apt-get install libdlib-dev libblas-dev liblapack-dev libjpeg-turbo8-dev
# Debian
sudo apt-get install libdlib-dev libblas-dev liblapack-dev libjpeg62-turbo-dev
Copy the code
macOS
Make sure Homebrew is installed.
brew install dlib
Copy the code
Project creation and preparation
In the SRC directory of GOPATH, create the project file as follows.
Sudo makedir go-face-test # create main.go sudo touch main.goCopy the code
Then go to the directory and generate the mod file.
sudo go mod init
Copy the code
After the command is executed, the go.mod file should be generated in the go-face-test directory.
Dat, mmod_human_face_detector_detector. Dat, and dlib_face_recognition_resnet_model_v1.dat, Download the corresponding test data in the go-face-test directory.
git clone https://github.com/Kagami/go-face-testdata testdata
Copy the code
The final project structure should be as shown.
Code implementation
First, we use the code to check that the environment is healthy. Initialize the recognizer and release the resource.
Package main import (" FMT ""github.com/Kagami/go-face") const dataDir =" testData" modelDir = dataDir + "/models" imagesDir = dataDir + "/images" ) func main() { fmt.Println("Face Recognition..." ) // Initialize recognizer rec, err := face.NewRecognizer(modelDir) if err! = nil { fmt.Println("Cannot INItialize recognizer") } defer rec.Close() fmt.Println("Recognizer Initialized") }Copy the code
Compile and then run the code.
sudo go run main.go
Copy the code
You should get the following output.
Face Recognition...
Recognizer Initialized
Copy the code
At this point, we’ve successfully set up everything we need.
Detect the number of faces in the image
First, prepare a photo of Lin Junjie and put it in any directory. For demonstration convenience, I put it in the same directory as Main. go.
As you can see, now there’s nothing but a picture, and what we’re going to do is ask the computer to count the faces in the picture.
Package main import (" FMT ""log" "github.com/Kagami/go-face") const dataDir =" testData "// two corresponding directories in the testData directory const ( modelDir = dataDir + "/models" imagesDir = dataDir + "/images" ) func main() { fmt.Println("Face Recognition..." ) // Initialize recognizer rec, err := face.NewRecognizer(modelDir) if err! = nil {fmt.println ("Cannot INItialize Initialized")} defer reco.close () fmt.println (" recognizer Initialized") // Call the method, Incoming path. RecognizeFile("linjunjie.jpeg") returns the number of faces and any wrong faces, err := reco.recognizefile ("linjunjie.jpeg") if err! Fatalf(" unidentifiable: %v", err)} // Println(" Faces: ", len(faces))}Copy the code
The core code is actually a line, go-face encapsulates the identification method, and passes in the image file of the corresponding path. After executing the code, the result is as follows.
Face Recognition... Recognizer Initialized Number of Recognizer faces: 1Copy the code
Clumsy computers can already count faces. That… If there are more than one person in a photo, let’s try to prepare a photo of more than one person.
heyin.jpeg
Let’s replace line 31 with the following.
faces, err := rec.RecognizeFile("heyin.jpeg")
Copy the code
After running the results should be printed (picture face number: 6), then formally look at our face recognition.
Face recognition
First we prepare a group photo, heyin.jpeg as above.
The whole process is roughly divided into the following steps.
1. Map the person in the group photo to a unique ID, and then associate the unique ID with the corresponding person.
var samples []face.Descriptor var peoples []int32 for i, f := range faces { samples = append(samples, F. deccriptor) // Each face unique id peoples = append(peoples, int32(i)) } // Pass samples to the recognizer. rec.SetSamples(samples, peoples)Copy the code
2. Next we package a face recognition method, into the recognizer and photo path, print the corresponding character ID, character name.
func RecognizePeople(rec *face.Recognizer, file string) { people, err := rec.RecognizeSingleFile(file) if err ! = nil {log.fatalf (" unidentifiable: %v", Err)} If people == nil {log.fatalf (" false face ")} peopleID := rec.classify (people.descriptor) if peopleID < 0 { Log.fatalf (" Unrecognizable ")} FMT.Println(peopleID) FMT.Println(peopleID)}Copy the code
3. Finally, we passed in the pictures we want to recognize. So far, we have passed in three pictures.
jay.jpeg
linjunjie.jpeg
taozhe.jpeg
4. Call three times.
RecognizePeople(rec, "jay.jpeg")
RecognizePeople(rec, "linjunjie.jpeg")
RecognizePeople(rec, "taozhe.jpeg")
Copy the code
The following code
Package main import (" FMT ""log" "github.com/Kagami/go-face") const dataDir =" testData "// two corresponding directories in the testData directory Const (modelDir = dataDir + "/models" imagesDir = dataDir + "/images") var labels = []string{" } func main() {FMT.Println("Face Recognition..." ) // Initialize recognizer rec, err := face.NewRecognizer(modelDir) if err! = nil {fmt.println ("Cannot INItialize Initialized")} defer reco.close () fmt.println (" recognizer Initialized") // Call the method, Incoming path. RecognizeFile("heyin.jpeg") returns the number of faces and any wrong faces, err := reco.recognizefile ("heyin.jpeg") if err! Fatalf(" unrecognisable: %v", err)} // Print the number of faces fmt.Println(" Picture number of faces: %v", err) ", len(faces)) var samples []face.Descriptor var peoples []int32 for i, f := range faces { samples = append(samples, F. dexcriptor) // Unique id for each face peoples = append(peoples, int32(I))} // Pass the samples to the recognizer rec.setsamples (samples, peoples) RecognizePeople(rec, "jay.jpeg") RecognizePeople(rec, "linjunjie.jpeg") RecognizePeople(rec, "taozhe.jpeg") } func RecognizePeople(rec *face.Recognizer, file string) { people, err := rec.RecognizeSingleFile(file) if err ! = nil {log.fatalf (" unidentifiable: %v", Err)} If people == nil {log.fatalf (" false face ")} peopleID := rec.classify (people.descriptor) if peopleID < 0 { Log.fatalf (" Unrecognizable ")} FMT.Println(peopleID) FMT.Println(peopleID)}Copy the code
The results
Finally, we run the code.
go build main.go
./main
Copy the code
The results are as follows
Number of faces in pictures: 6 1 Jay Chou 5 Jj Lin 4 Zhe TaoCopy the code
Congratulations, you have successfully identified the three images. At this point, the static image face recognition is complete.
Summary of static face recognition
At this point we have been able to successfully use Go to achieve static face recognition. It is not impossible to use it in the project, but it has many limitations, the use of the scene is relatively single, can only be used in such as user upload face identification, single face recognition and other scenes; Image format is relatively simple, does not support PNG format and other shortcomings.
Video streaming face recognition
background
Static face recognition application scenarios are more limited, can not be put in the more important environment, such as finance, insurance, security and other fields, there is the possibility of counterfeiting. And simple static face recognition, not much meaning. Dynamic video stream has a broader application space, fully used in intelligent security, gesture recognition, beauty and other fields. In the 5G era, many businesses will be carried out around video. How to decouple video business from core business? The RTE component of Sonnet has done a good job.
RTE advantages
1. Application independence
It can be shared between different projects to achieve reuse and avoid the repetitive work of multiple development
2. Platform independence
Widely used in operating systems, programming languages and various fields
3. Rich three-party modules
Can provide such as whiteboard teaching, video beauty, yellow and other modules for developers to use
Code implementation
Here we will realize the video stream related face recognition, before the static recognition is to dynamic video stream face recognition pave the way. Let’s talk about the realization of video stream face recognition ideas, static image face recognition has been completed, and the video is a continuous multiple frames, we only need to extract snippet capture key frames, identify the portrait, after the output of the corresponding associated name.
The preparatory work
Here we use goCV (OpenCV is used at the bottom), here we temporarily skip the specific installation process, according to the official document can be installed.
1. Set the device for capturing videos. The default value is 0
// set to use a video capture device 0 deviceID := 0 // open webcam webcam, err := gocv.OpenVideoCapture(deviceID) if err ! = nil { fmt.Println(err) return } defer webcam.Close()Copy the code
2. Open the display window
// open display window
window := gocv.NewWindow("Face Detect")
defer window.Close()
Copy the code
3. Prepare the image matrix to display the configuration of the rectangular box when the face is detected
// prepare image matrix
img := gocv.NewMat()
defer img.Close()
// color for the rect when faces detected
blue := color.RGBA{0, 0, 255, 0}
Copy the code
4 load face recognition classifier, with an infinite loop, which plus our related recognition services
for { if ok := webcam.Read(&img); ! ok { fmt.Printf("cannot read device %v\n", deviceID) return } if img.Empty() { continue } // detect faces rects := classifier.DetectMultiScale(img) fmt.Printf("found %d faces\n", len(rects)) // draw a rectangle around each face on the original image for _, r := range rects { gocv.Rectangle(&img, r, blue, 3) imgFace := img.Region(r) buff, err:=gocv.IMEncode(".jpg",imgFace) if err ! = nil { fmt.Println("encoding to jpg err:%v", err) break } RecognizePeopleFromMemory(rec, buff) } // show the image in the window, and wait 1 millisecond window.IMShow(img) window.WaitKey(1) }Copy the code
There are several steps that need to be done. For now, GoCV.IMEncode only supports converting captured images into PNG, JPG and GIF formats. The converted byte stream is placed in memory, and then the byte stream is passed into our face recognition function.
// RecognizeSingle returns face if it's the only face on the image or // nil otherwise. Only JPEG format is currently supported. Thread-safe. func (rec *Recognizer) RecognizeSingle(imgData []byte) (face *Face, err error) { faces, err := rec.recognize(0, imgData, 1) if err ! = nil || len(faces) ! = 1 { return } face = &faces[0] return }Copy the code
Matters needing attention
Since Go-Face only supports JPEG format, the frames we capture can only be converted to JPG format
Then simply encapsulate a character stream recognition function. The reason why log.fatal was changed to log.println is that there may be no face in video stream level identification, and the program should be running properly and not exit.
func RecognizePeopleFromMemory(rec *face.Recognizer, img []byte) { people, err := rec.RecognizeSingle(img) if err ! = nil {log.Println(" unrecognized: %v", Err) return} if people == nil {log.println (" image is not a face ") return} peopleID := rec.classify (people.descriptor) if PeopleID < 0 {log.println (" unmarked ") return} ftt.println (peopleID) ftt.println (peopleID) labels[peopleID])}Copy the code
The final complete code is as follows
package main import ( "fmt" "image/color" "log" "github.com/Kagami/go-face" "gocv.io/x/gocv" ) const dataDir = Const (modelDir = dataDir + "/models" imagesDir = dataDir + "/images") // Name of the image Var labels = []string{" xiao ", "Jay "," Unknow ", "Lihom "," Joh ", "Joh "," Joh ", "joh "," joh ", "joh "," joh ", "joh "," joh ",} err := face.NewRecognizer(modelDir) if err ! = nil {fmt.println ("Cannot INItialize Initialized")} defer reco.close () fmt.println (" recognizer Initialized") // Call the method, Incoming path. RecognizeFile("heyin.jpeg") returns the number of faces and any wrong faces, err := reco.recognizefile ("heyin.jpeg") if err! Fatalf(" unrecognisable: %v", err)} // Print the number of faces fmt.Println(" Picture number of faces: %v", err) ", len(faces)) var samples []face.Descriptor var peoples []int32 for i, f := range faces { samples = append(samples, F. deccriptor) // Each face unique id peoples = append(peoples, int32(i)) } // Pass samples to the recognizer. rec.SetSamples(samples, peoples) RecognizePeople(rec, "jay.jpeg") RecognizePeople(rec, "linjunjie.jpeg") RecognizePeople(rec, "taozhe.jpeg") // set to use a video capture device 0 deviceID := 0 // open webcam webcam, err := gocv.OpenVideoCapture(deviceID) if err ! = nil { fmt.Println(err) return } defer webcam.Close() // open display window window := gocv.NewWindow("Face Detect") defer window.Close() // prepare image matrix img := gocv.NewMat() defer img.Close() // color for the rect when faces detected blue := color.RGBA{0, 0, 255, 0} // load classifier to recognize faces classifier := gocv.NewCascadeClassifier() defer classifier.Close() if ! classifier.Load("./haarcascade_frontalface_default.xml") { fmt.Println("Error reading cascade file: data/haarcascade_frontalface_default.xml") return } fmt.Printf("start reading camera device: %v\n", deviceID) for { if ok := webcam.Read(&img); ! ok { fmt.Printf("cannot read device %v\n", deviceID) return } if img.Empty() { continue } // detect faces rects := classifier.DetectMultiScale(img) if len(rects) == 0 { continue } fmt.Printf("found %d faces\n", len(rects)) // draw a rectangle around each face on the original image for _, r := range rects { gocv.Rectangle(&img, r, blue, 3) imgFace := img.Region(r) buff, err:=gocv.IMEncode(".jpg",imgFace) if err ! = nil { fmt.Println("encoding to jpg err:%v", err) break } RecognizePeopleFromMemory(rec, buff) } // show the image in the window, and wait 1 millisecond window.IMShow(img) window.WaitKey(1) } } func RecognizePeople(rec *face.Recognizer, file string) { people, err := rec.RecognizeSingleFile(file) if err ! = nil {log.fatalf (" unidentifiable: %v", Err)} If people == nil {log.fatalf (" false face ")} peopleID := rec.classify (people.descriptor) if peopleID < 0 { The Fatalf (" unable to distinguish between ")} FMT. Println (peopleID) FMT. Println (labels/peopleID)} func RecognizePeopleFromMemory (rec *face.Recognizer, img []byte) { people, err := rec.RecognizeSingle(img) if err ! = nil {log.Println(" unrecognized: %v", Err) return} if people == nil {log.println (" image is not a face ") return} peopleID := rec.classify (people.descriptor) if PeopleID < 0 {log.println (" unmarked ") return} ftt.println (peopleID) ftt.println (peopleID) labels[peopleID])}Copy the code
Next, we run the code, which should be able to pull up the camera. At this time, I hold Lin Junjie’s photo for identification. We can see that the corresponding name has been output in the lower left corner.
Summary of video stream face recognition
At this point, congratulations, you have completed video streaming face recognition. However, it should be noted here that in order to achieve fast, our sample set is relatively small, and the recognition success rate is relatively low. But a simple dynamic facial recognition has been built.
conclusion
Although we have achieved dynamic face recognition, but in more complex application scenarios it is difficult to achieve the corresponding requirements, and there are limitations such as picture format, lack of other modules of face processing, beauty, yellow and other functions. However, the third-party SDK, such as sound network and other platforms, can be used to realize the corresponding requirements. The face recognition, video conference, cloud classroom and other scenes in the park can be set up quickly, and the corresponding access can be completed in just a few lines of code, and the related development of face recognition can be carried out around RTE and other components. To save a lot of time and cost, you can shift the focus of development to more core businesses.