Coder Social home page Coder Social logo

esimov / pigo Goto Github PK

View Code? Open in Web Editor NEW
4.3K 102.0 305.0 14.39 MB

Fast face detection, pupil/eyes localization and facial landmark points detection library in pure Go.

License: MIT License

Go 75.08% Makefile 0.38% Shell 0.92% Python 16.66% C 6.24% HTML 0.62% CSS 0.09%
face-detection computer-vision machine-learning golang opencv pixel-intensity-comparison pupil-detection eye-detection facial-landmarks wasm

pigo's Introduction

pigo-logo

CI Go Report Card go.dev reference license release pigo

Pigo is a pure Go face detection, pupil/eyes localization and facial landmark points detection library based on the Pixel Intensity Comparison-based Object detection paper.

Rectangle face marker Circle face marker
rectangle circle

Motivation

The reason why Pigo has been developed is because almost all of the currently existing solutions for face detection in the Go ecosystem are purely bindings to some C/C++ libraries like OpenCV or dlib, but calling a C program through cgo introduces huge latencies and implies a significant trade-off in terms of performance. Also, in many cases installing OpenCV on various platforms is cumbersome.

The Pigo library does not require any additional modules or third party applications to be installed, although you might need to install Python and OpenCV if you wish to run the library in a real time desktop application. Head over to this subtopic for more details.

Key features

  • Does not require OpenCV or any 3rd party modules to be installed
  • High processing speed
  • There is no need for image preprocessing prior to detection
  • There is no need for the computation of integral images, image pyramid, HOG pyramid or any other similar data structure
  • The face detection is based on pixel intensity comparison encoded in the binary file tree structure
  • Fast detection of in-plane rotated faces
  • The library can detect even faces with eyeglasses
  • Pupils/eyes localization
  • Facial landmark points detection
  • Webassembly support πŸŽ‰

Todo

  • Object detection and description

The library can also detect in plane rotated faces. For this reason a new -angle parameter has been included into the command line utility. The command below will generate the following result (see the table below for all the supported options).

$ pigo -in input.jpg -out output.jpg -cf cascade/facefinder -angle=0.8 -iou=0.01
Input file Output file
input output

Note: In case of in plane rotated faces the angle value should be adapted to the provided image.

Pupils / eyes localization

Starting from v1.2.0 Pigo offers pupils/eyes localization capabilities. The implementation is based on Eye pupil localization with an ensemble of randomized trees.

Check out this example for a realtime demo: https://github.com/esimov/pigo/tree/master/examples/puploc

puploc

Facial landmark points detection

v1.3.0 marks a new milestone in the library evolution, Pigo being able to detect facial landmark points. The implementation is based on Fast Localization of Facial Landmark Points.

Check out this example for a realtime demo: https://github.com/esimov/pigo/tree/master/examples/facial_landmark

flp_example

Install

Install Go, set your GOPATH, and make sure $GOPATH/bin is on your PATH.

$ go install github.com/esimov/pigo/cmd/pigo@latest

Binary releases

In case you do not have installed or do not wish to install Go, you can obtain the binary file from the releases folder.

The library can be accessed as a snapcraft function too.

snapcraft pigo

API

Below is a minimal example of using the face detection API.

First, you need to load and parse the binary classifier, then convert the image to grayscale mode, and finally run the cascade function which returns a slice containing the row, column, scale and the detection score.

cascadeFile, err := ioutil.ReadFile("/path/to/cascade/file")
if err != nil {
	log.Fatalf("Error reading the cascade file: %v", err)
}

src, err := pigo.GetImage("/path/to/image")
if err != nil {
	log.Fatalf("Cannot open the image file: %v", err)
}

pixels := pigo.RgbToGrayscale(src)
cols, rows := src.Bounds().Max.X, src.Bounds().Max.Y

cParams := pigo.CascadeParams{
	MinSize:     20,
	MaxSize:     1000,
	ShiftFactor: 0.1,
	ScaleFactor: 1.1,

	ImageParams: pigo.ImageParams{
		Pixels: pixels,
		Rows:   rows,
		Cols:   cols,
		Dim:    cols,
	},
}

pigo := pigo.NewPigo()
// Unpack the binary file. This will return the number of cascade trees,
// the tree depth, the threshold and the prediction from tree's leaf nodes.
classifier, err := pigo.Unpack(cascadeFile)
if err != nil {
	log.Fatalf("Error reading the cascade file: %s", err)
}

angle := 0.0 // cascade rotation angle. 0.0 is 0 radians and 1.0 is 2*pi radians

// Run the classifier over the obtained leaf nodes and return the detection results.
// The result contains quadruplets representing the row, column, scale and detection score.
dets := classifier.RunCascade(cParams, angle)

// Calculate the intersection over union (IoU) of two clusters.
dets = classifier.ClusterDetections(dets, 0.2)

A note about imports: in order to decode the generated image you have to import image/jpeg or image/png (depending on the provided image type) as in the following example, otherwise you will get a "Image: Unknown format" error.

import (
    _ "image/jpeg"
    pigo "github.com/esimov/pigo/core"
)

Usage

A command line utility is bundled into the library.

$ pigo -in input.jpg -out out.jpg -cf cascade/facefinder

Supported flags:

$ pigo --help

β”Œβ”€β”β”¬β”Œβ”€β”β”Œβ”€β”
β”œβ”€β”˜β”‚β”‚ ┬│ β”‚
β”΄  β”΄β””β”€β”˜β””β”€β”˜

Go (Golang) Face detection library.
    Version: 1.4.2

  -angle float
    	0.0 is 0 radians and 1.0 is 2*pi radians
  -cf string
    	Cascade binary file
  -flpc string
    	Facial landmark points cascade directory
  -in string
    	Source image (default "-")
  -iou float
    	Intersection over union (IoU) threshold (default 0.2)
  -json string
    	Output the detection points into a json file
  -mark
    	Mark detected eyes (default true)
  -marker string
    	Detection marker: rect|circle|ellipse (default "rect")
  -max int
    	Maximum size of face (default 1000)
  -min int
    	Minimum size of face (default 20)
  -out string
    	Destination image (default "-")
  -plc string
    	Pupils/eyes localization cascade file
  -scale float
    	Scale detection window by percentage (default 1.1)
  -shift float
    	Shift detection window by percentage (default 0.1)

Important notice: In case you also wish to run the pupil/eyes localization, then you need to use the plc flag and provide a valid path to the pupil localization cascade file. The same applies for facial landmark points detection, only that this time the parameter accepted by the flpc flag is a directory pointing to the facial landmark points cascade files found under cascades/lps.

CLI command examples

You can also use the stdin and stdout pipe commands:

$ cat input/source.jpg | pigo > -in - -out - >out.jpg -cf=/path/to/cascade

in and out default to - so you can also use:

$ cat input/source.jpg | pigo >out.jpg -cf=/path/to/cascade
$ pigo -out out.jpg < input/source.jpg -cf=/path/to/cascade

Using the empty string as value for the -out flag will skip the image generation part. This, combined with the -json flag will encode the detection results into the specified json file. You can also use the pipe - value combined with the -json flag to output the detection coordinates to the standard (stdout) output.

Real time face detection (running as a shared object)

If you wish to test the library's real time face detection capabilities, the examples folder contains a few demos written in Python.

But why Python you might ask? Because the Go ecosystem is (still) missing a cross platform and system independent library for accessing the webcam.

In the Python program we access the webcam and transfer the pixel data as a byte array through cgo as a shared object to the Go program where the core face detection is happening. But as you can imagine this operation is not cost effective, resulting in lower frame rates than the library is capable of.

WASM (Webassembly) support πŸŽ‰

Important note: In order to run the Webassembly demos at least Go 1.13 is required!

Starting from version v1.4.0 the library has been ported to WASM. This proves the library's real time face detection capabilities, constantly producing ~60 FPS.

WASM demo

To run the wasm demo select the wasm folder and type make.

For more details check the subpage description: https://github.com/esimov/pigo/tree/master/wasm.

Benchmark results

Below are the benchmark results obtained running Pigo against GoCV using the same conditions.

    BenchmarkGoCV-4   	       3	 414122553 ns/op	     704 B/op	       1 allocs/op
    BenchmarkPIGO-4   	      10	 173664832 ns/op	       0 B/op	       0 allocs/op
    PASS
    ok  	github.com/esimov/gocv-test	4.530s

The code used for the above test can be found under the following link: https://github.com/esimov/pigo-gocv-benchmark

Author

License

Copyright Β© 2019 Endre Simo

This software is distributed under the MIT license. See the LICENSE file for the full license text.

pigo's People

Contributors

artob avatar cgxeiji avatar davidkuridza avatar esimov avatar facundomedica avatar imikod avatar jpozdena avatar leobeosab avatar mudassirnoor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pigo's Issues

Detect rotated faces

The number of faces in this image should be 4 rectangles, so why get -out file is 3 rectangles (-iou 0.1 or -iou 0.2)
duogeren

-iou 0.1

outduogeren

-iou 0.2
outduogeren

Too many false detections

I'm using pigo in my realtime app and observing many false detections. How can i reduce amount of them? Does pigo have some parameters to adjust?

WASM Demo features toggled with keys fail

The demo documentation declares that there are supported keys:
s - Show/hide pupils
c - Circle through the detection shape types (rectangle|circle|ellipse)
f - Show/hide facial landmark points (hidden by default)

On my local machine, the webcam streaming works and the fps is shown but the keys when pressed don't toggle the features mapped to them.

go version go1.17.2 linux/amd64
Browser: Firefox & Chrome

panic error

$> ./pigo -in input.jpg -out output.jpg -cf data/facefinder
Processing... -panic: runtime error: index out of range

goroutine 1 [running]:
github.com/esimov/pigo/core.(*Pigo).Unpack(0xc4206a8d50, 0xc420672000, 0x0, 0x200, 0x200, 0x0, 0x0)
        /home/esimov/Projects/Go/src/github.com/esimov/pigo/core/pigo.go:66 +0xc5e
main.(*faceDetector).detectFaces(0xc4206a8f40, 0x7ffe8b90d545, 0x2d, 0x3, 0x3, 0x1, 0x50a920, 0xc42007e0c0)
        /home/esimov/Projects/Go/src/github.com/esimov/pigo/cmd/pigo/main.go:164 +0x23b
main.main()
        /home/esimov/Projects/Go/src/github.com/esimov/pigo/cmd/pigo/main.go:95 +0x296

pigo v1.1.0

What am I missing?

Feat request : no output, JSON output

Hi,

I'm starting to use the Pigo command, and while it's pretty good at detecting faces, its usage is a bit weird. Before that, I've tried some other applications like face_detection and facedetect.
Both can output the coordinates of the faces directly to the console (which is pretty useful to retrieve these infos from PHP).
But Pigo forces to create a PNG file (which is useless for what I want to do), and writes the JSON data to output.json in the current directory. If two calls are made in parallel, it could be a problem.

Would it be possible to:

  • make the -out parameter optional?
  • output -json to the console if no file is specified, or to the specified file instead of 'output.json'?

Save detected images differently

Hi,
Thanks for the great work here.

Is it possible to use pigo to extract faces from a photo and save the extracted faces individually.

Return bounding box coordinates from command line?

Thanks for sharing this awesome project!

Is it possible to get bounding box coordinates outputted to the command line? I'd like to use pigo on my raspberry pi 3 to automatically crop images captured by the raspberry pi camera.

Also, would this work with people who are wearing glasses?

Many thanks!

face compare ?

there is two image with same person in it, can this library find and compare face from that two image ?, thankyou

fd struct pops out of nowhere in README.md

cParams := pigo.CascadeParams{
	MinSize:     fd.minSize,
	MaxSize:     fd.maxSize,
	ShiftFactor: fd.shiftFactor,
	ScaleFactor: fd.scaleFactor,
	
	ImageParams: pigo.ImageParams{
		Pixels: pixels,
		Rows:   rows,
		Cols:   cols,
		Dim:    cols,
	},
}

It never appears in README.md apart from these four lines.

Unable to detect the face

I tried running pigo with various values for -angle and -scale but couldn't detect the face. Would appreciate any help!

Invalid Face Detected

Issue

The image attached passes facial detection.

API related bug

The images should not be detected as a face
detection

Expected behaviour

No Face Detected
face

Other Information

  • Go version - go version go1.17.1 darwin/amd64

Observation

This image also passes default android face detection but I belive pigo should be better

Eye/Facial Coordinates in JSON?

Hi there, is it possible to print/output the Facial Coordinates/Pupil Localization pointers in the JSON file with -json itself? Or any work around for the same?

or any other way to print the exact coordinates of the pupils or the other facial features?

Adding jaw line facial landmarks

Would you be able to explain how you went and generated the facial landmark / density tree files that are used in the implementation of the Fast Localization of Facial Landmark Points? I would be keen to contribute, or ask if you can, the jaw line to the list of supported facial landmarks

json export of face coordinates is empty

I got the face detection working (thanks for your help in #12) but when I specify -json, I see output.json getting created but empty.

./pigo -cf data/facefinder -in in.jpg -out out.png -angle=0.3 -json

web example

Hi,

If I run your web example than I get this error:
2020/04/24 21:51:38 [ERROR] reading next part multipart: NextPart: EOF
I must admit that I don't meet the requirements for this example. My python is python3 and my opencv is 4.2. OS is Ubuntu 20.04LTS.
I tested as follows

  1. Run: go run main.go -cf "../../cascade/facefinder"
  2. Open URL: localhost:8081/cam in browser
  3. Then this error appears
    Any ideas? Thanks

x / y values are backwards in json output

For some reason the x isn't really x but it's the y value, and vice versa. Weirdly they seem backwards in the json output.

I tested this by opening the image in photoshop and seeing where the x / y sits as compared to the values reported by pigo. They are accurate, just backwards. Unless I've clearly done something nooby πŸ˜•

On the CLI, -flpc flag doesn't work without -plc.

Describe the bug

-fplc flag doesn't seem to work if -plc isn't specified.

This command works fine:
$ pigo -in image.jpg -out output.jpg -cf ../pigo/cascade/facefinder -plc ../pigo/cascade/puploc -flpc ../pigo/cascade/lps

But running the following only detects the face but not its facial landmarks:
$ pigo -in image.jpg -out output.jpg -cf ../pigo/cascade/facefinder -flpc ../pigo/cascade/lps

Expected behavior

-flpc should work without -plc as per the screenshot https://user-images.githubusercontent.com/883386/66802771-3b0cc880-ef26-11e9-9ee3-7e9e981ef3f7.png

Is there a way to create new landmark point definitions?

Hi. I'm trying to implement webcam based facial motion capture with with library.

The current set of face and retina landmarks is quite good, but I'm wondering if it's possible to extend the landmark regions that the PICO process can identify.

Specifically:

Option 1: adding new face landmarks

I'm assuming that new facial landmark locations would require defining new cascade files. Did the paper authors mentioned any recommendations on collecting and tagging example training data, or the training process itself?

facial landmarks

Option 2: adding simple paint based landmarks

Perhaps a simpler option would be to somehow define cascades for recognizing simple shapes like dot marks, or cross marks placed in an actor's face where the missing facial landmark points are needed.

paint marks

Let me know if I missed anything.

Thanks!

Resources

AutoDesk SoftImage - The Motion Capture Process

Use webcam via GoCV

Webcam can be used from Go with GoCV. Resulting mat can then be encoded to jpg if needed.

examples/delaunay fails to build

github.com/esimov/pigo/examples/delaunay
src/github.com/esimov/pigo/examples/delaunay/pigo.go:82:24: assignment mismatch: 4 variables but 3 values
src/github.com/esimov/pigo/examples/delaunay/pigo.go:82:35: cannot use subImg (type image.Image) as type io.Reader in argument to tri.Draw:
	image.Image does not implement io.Reader (missing Read method)
src/github.com/esimov/pigo/examples/delaunay/pigo.go:82:35: cannot use false (type bool) as type io.Writer in argument to tri.Draw:
	bool does not implement io.Writer (missing Write method)

The use of log.Fatal

First, thanks for this, this is very much appreciated, and the code looks solid.

I have one small request, which I think is needed for this to be used as a library. And that is to replace the log.Fatal (which does an Β΄os.Exit` I don't think is even possible to catch in a client):

https://github.com/esimov/pigo/blob/master/core/pigo.go#L67

I would suggest just returning an error. This may be "this should never happen errors", and then a panic may be in order.

What are the bounds of the score?

Is your feature request related to a problem? Please describe.

This library is used in PhotoPrism: photoprism/photoprism#22 (comment)

PhotoPrism allows to define a threshold for the score.

While trying to document the value of that threshold, I wonder what are the possible values.

Describe the solution you'd like

Define the minimal and maximal values for the score.

Describe alternatives you've considered

According to this article:

An image region is considered being face if the detection score average is above a certain threshold (in general around 0.995).

The score goes from 0 to 1?

Additional context

.

Q&A article on pigo

Hi Endre (@esimov),

We would like to write a short piece about Pigo for our audience of developers and would like to do a Q&A with you. Article would be published on infoq.com. Last article on wasm was about a desktop game editor ported to WebAssembly. Let me know if that is of any interest to you.

Passing output value via a variable (Python)

Hi there! I'm trying to pass the values for the eyes separately using the blinkdet example, but seems like it outputs the values for both the eyes together and not separately (just outputting max_radius)

Is there a way to output the values that I get using -json via a particular variable or just output the values (max_radius) of both the eyes separately?

Match a face

Can this detect a face from a group of given a face to match with ?

Use case is video conferencing and Identification of a user for authentication

Likeliness between faces

First off, just want to appreciate and thank you for this cool project you're working on.
I was wondering if you could add the feature to compare two faces and describe how likely they are.

NewPigo + Unpack overhead?

I was wondering why func Unpack() (*Pigo, error) needs to be a method of the struct Pigo if that struct is never used inside the method. I think making Unpack() a method of the package, instead of the struct, would have less overhead when initializing the classifier.

What do you think?

Comparison of two face

I use a stream of images and one of the tasks is to group faces, could you recommend a method for comparing faces.

Infinite loop

This particular line is a possible (an in fact, experienced) infinite loop:

scale = int(float64(scale) * cp.ScaleFactor)

I've figured it out from the stack trace:

github.com/esimov/pigo/core.(*Pigo).classifyRegion(0xc0001a40a0, 0x42, 0x36, 0x9, 0xc00068e000, 0x238c, 0x238c, 0x5b, 0xbf800000)

The gorutine track trace parameters are as follows:

  • 0xc0001a40a0 (the receiver)
  • 0x42 row (constantly modified)
  • 0x36 col (constantly modified)
  • 0x9 scale (!!does not change!!)
  • other params (do not change)

The issue comes from a rounding /casting error. The main readme (as well as my code) sets the cascade parameters scale factor as 1.1. When the scale is 9, the factor would come up with 9.9, which again becomes 9 because of the int() conversion.

The particular issue is that the source image was 91x100 (don't even ask), and I've calculated the face min/max size as 10% and 50% of the image width respectively. The minimum face size thus becomes 9 and with the scale ratio of 1.1 = infinite loop.

Possible fixes:

  • Clamp the minimum value for a face size where it wouldn't cause problems (10px)
  • Better main loop for this stuff to avoid rounding errors

Bug on demo

Hello, I had a bug when I execute demo. It's nothing bad ;) .

github.com/esimov/pigo/examples/facedet #Β python2 demo.py
Traceback (most recent call last):
File "demo.py", line 66, in
cv2.circle(frame, (int(det[1]), int(det[0])), int(det[2]/2.0), (0, 0, 255), 2)
OverflowError: signed integer is greater than maximum

oval shape

Is it possible to use oval shape instead of square or circle?

what is the mean of iouThreshold

First Tks for your nice project.
I am a bit confuse of the mean of iou parameter and it impact the result of the detection, and i use this lib for face detection, I'm wonder of how to set iouThreshold value correctly.

Got exit code 1073741819 (0xC0000005) from python demo

Hi there,
I try to exec demo with Python 3.9 on Windows, sometimes got unexpected exit, with code -1073741819 (0xC0000005) , that err from C shared lib I think, and that because of index out of range usually.
I'm not good at Golang and not founded the true reason from code, give me some advice to fix it please, thx.

Realtime Performance

A quick view of an example I found this happening per frame:

pigo/examples/web/main.go

Lines 131 to 137 in 747334f

pigo := pigo.NewPigo()
// Unpack the binary file. This will return the number of cascade trees,
// the tree depth, the threshold and the prediction from tree's leaf nodes.
classifier, err := pigo.Unpack(cascadeFile)
if err != nil {
log.Fatalf("Error reading the cascade file: %s", err)
}

Why create the object and rerun that same unpack logic every time on the same source bytes. Should there be a Clone on the Pigo struct that just copies everything to a new struct to be better performing when running over and over?

Pigo Wasm demo crashes after certain time

Bug with Webassembly (WASM) version:

$ go version
go version go1.16.6 darwin/amd64

Running the Wasm demo after certain time the browser crashes because of Out of memory error. Checking the
memory consumption this increases rapidly.

Screenshots

image

Additional context

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.