mirror of
https://github.com/esimov/pigo.git
synced 2025-10-05 16:16:55 +08:00
Refactor detector function
This commit is contained in:
@@ -2,6 +2,7 @@ package canvas
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"syscall/js"
|
||||
|
||||
"github.com/esimov/pigo/wasm/detector"
|
||||
@@ -17,7 +18,7 @@ type Canvas struct {
|
||||
window js.Value
|
||||
doc js.Value
|
||||
body js.Value
|
||||
windowSize struct{ width, height float64 }
|
||||
windowSize struct{ width, height int }
|
||||
|
||||
// Canvas properties
|
||||
canvas js.Value
|
||||
@@ -37,8 +38,8 @@ func NewCanvas() *Canvas {
|
||||
c.doc = c.window.Get("document")
|
||||
c.body = c.doc.Get("body")
|
||||
|
||||
c.windowSize.width = c.window.Get("innerWidth").Float()
|
||||
c.windowSize.height = c.window.Get("innerHeight").Float()
|
||||
c.windowSize.width = c.window.Get("innerWidth").Int()
|
||||
c.windowSize.height = c.window.Get("innerHeight").Int()
|
||||
|
||||
c.canvas = c.doc.Call("createElement", "canvas")
|
||||
c.canvas.Set("width", c.windowSize.width)
|
||||
@@ -52,27 +53,31 @@ func NewCanvas() *Canvas {
|
||||
|
||||
// Render calls the `requestAnimationFrame` Javascript function in asynchronous mode.
|
||||
func (c *Canvas) Render() {
|
||||
var data = make([]byte, int(c.windowSize.width*c.windowSize.height*4))
|
||||
var data = make([]byte, c.windowSize.width*c.windowSize.height*4)
|
||||
c.done = make(chan struct{})
|
||||
|
||||
det := detector.NewDetector()
|
||||
c.renderer = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
go func() {
|
||||
c.reqID = c.window.Call("requestAnimationFrame", c.renderer)
|
||||
// Draw the webcam frame to the canvas element
|
||||
c.ctx.Call("drawImage", c.video, 0, 0)
|
||||
rgba := c.ctx.Call("getImageData", 0, 0, c.windowSize.width, c.windowSize.height).Get("data")
|
||||
c.Log(rgba.Get("length").Int())
|
||||
if err := det.UnpackCascades(); err == nil {
|
||||
c.renderer = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
go func() {
|
||||
c.reqID = c.window.Call("requestAnimationFrame", c.renderer)
|
||||
// Draw the webcam frame to the canvas element
|
||||
c.ctx.Call("drawImage", c.video, 0, 0)
|
||||
width, height := c.windowSize.width, c.windowSize.height
|
||||
rgba := c.ctx.Call("getImageData", 0, 0, width, height).Get("data")
|
||||
//c.Log(rgba.Get("length").Int())
|
||||
|
||||
uint8Arr := js.Global().Get("Uint8Array").New(rgba)
|
||||
js.CopyBytesToGo(data, uint8Arr)
|
||||
res := det.FindFaces(data)
|
||||
fmt.Println(res)
|
||||
}()
|
||||
return nil
|
||||
})
|
||||
c.window.Call("requestAnimationFrame", c.renderer)
|
||||
<-c.done
|
||||
uint8Arr := js.Global().Get("Uint8Array").New(rgba)
|
||||
js.CopyBytesToGo(data, uint8Arr)
|
||||
pixels := c.rgbaToGrayscale(data)
|
||||
res := det.DetectFaces(pixels, width, height)
|
||||
fmt.Println(res)
|
||||
}()
|
||||
return nil
|
||||
})
|
||||
c.window.Call("requestAnimationFrame", c.renderer)
|
||||
<-c.done
|
||||
}
|
||||
}
|
||||
|
||||
// Stop stops the rendering.
|
||||
@@ -146,6 +151,31 @@ func (c *Canvas) StartWebcam() (*Canvas, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Canvas) rgbaToGrayscale(data []uint8) []uint8 {
|
||||
rows, cols := c.windowSize.width, c.windowSize.height
|
||||
|
||||
// for i := 0; i < rows*cols; i++ {
|
||||
// r := data[i*4+0]
|
||||
// g := data[i*4+1]
|
||||
// b := data[i*4+2]
|
||||
// var gray = uint8(math.Round(0.2126*float64(r) + 0.7152*float64(g) + 0.0722*float64(b)))
|
||||
// data[i*4+0] = gray
|
||||
// data[i*4+1] = gray
|
||||
// data[i*4+2] = gray
|
||||
// }
|
||||
|
||||
for r := 0; r < rows; r++ {
|
||||
for c := 0; c < cols; c++ {
|
||||
// gray = 0.2*red + 0.7*green + 0.1*blue
|
||||
data[r*cols+c] = uint8(math.Round(
|
||||
0.2126*float64(data[r*4*cols+4*c+0]) +
|
||||
0.7152*float64(data[r*4*cols+4*c+1]) +
|
||||
0.0722*float64(data[r*4*cols+4*c+2])))
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// Log calls the `console.log` Javascript function
|
||||
func (c *Canvas) Log(args ...interface{}) {
|
||||
c.window.Get("console").Call("log", args...)
|
||||
|
@@ -1,7 +1,8 @@
|
||||
package detector
|
||||
|
||||
import (
|
||||
"log"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
pigo "github.com/esimov/pigo/core"
|
||||
)
|
||||
@@ -27,8 +28,42 @@ var (
|
||||
mouthCascade = []string{"lp93", "lp84", "lp82", "lp81"}
|
||||
)
|
||||
|
||||
func (d *Detector) FindFaces(pixels []uint8) [][]int {
|
||||
results := d.clusterDetection(pixels, 480, 640)
|
||||
func (d *Detector) UnpackCascades() error {
|
||||
p := pigo.NewPigo()
|
||||
|
||||
cascade, err = d.FetchCascade("https://raw.githubusercontent.com/esimov/pigo/master/cascade/facefinder")
|
||||
if err != nil {
|
||||
return errors.New("error reading the facefinder cascade file")
|
||||
}
|
||||
// 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.
|
||||
faceClassifier, err = p.Unpack(cascade)
|
||||
if err != nil {
|
||||
return errors.New("error unpacking the facefinder cascade file")
|
||||
}
|
||||
|
||||
plc := pigo.NewPuplocCascade()
|
||||
|
||||
puplocCascade, err = d.FetchCascade("https://raw.githubusercontent.com/esimov/pigo/master/cascade/puploc")
|
||||
if err != nil {
|
||||
return errors.New("error reading the puploc cascade file")
|
||||
}
|
||||
|
||||
puplocClassifier, err = plc.UnpackCascade(puplocCascade)
|
||||
if err != nil {
|
||||
return errors.New("error unpacking the puploc cascade file")
|
||||
}
|
||||
|
||||
flpcs, err = d.parseCascadeFiles("https://raw.githubusercontent.com/esimov/pigo/master/cascade/lps/")
|
||||
if err != nil {
|
||||
return errors.New("error unpacking the facial landmark points detection cascades")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Detector) DetectFaces(pixels []uint8, width, height int) [][]int {
|
||||
results := d.clusterDetection(pixels, width, height)
|
||||
fmt.Println(results)
|
||||
dets := make([][]int, len(results))
|
||||
|
||||
for i := 0; i < len(results); i++ {
|
||||
@@ -92,56 +127,21 @@ func (d *Detector) FindFaces(pixels []uint8) [][]int {
|
||||
|
||||
// clusterDetection runs Pigo face detector core methods
|
||||
// and returns a cluster with the detected faces coordinates.
|
||||
func (d *Detector) clusterDetection(pixels []uint8, rows, cols int) []pigo.Detection {
|
||||
det := NewDetector()
|
||||
func (d *Detector) clusterDetection(pixels []uint8, width, height int) []pigo.Detection {
|
||||
imgParams = &pigo.ImageParams{
|
||||
Pixels: pixels,
|
||||
Rows: rows,
|
||||
Cols: cols,
|
||||
Dim: cols,
|
||||
Rows: width,
|
||||
Cols: height,
|
||||
Dim: height,
|
||||
}
|
||||
cParams := pigo.CascadeParams{
|
||||
MinSize: 60,
|
||||
MaxSize: 600,
|
||||
MinSize: 100,
|
||||
MaxSize: 1200,
|
||||
ShiftFactor: 0.1,
|
||||
ScaleFactor: 1.1,
|
||||
ImageParams: *imgParams,
|
||||
}
|
||||
|
||||
// Ensure that the face detection classifier is loaded only once.
|
||||
if len(cascade) == 0 {
|
||||
cascade, err = det.FetchCascade("https://raw.githubusercontent.com/esimov/pigo/master/cascade/facefinder")
|
||||
if err != nil {
|
||||
det.Log("Error reading the cascade file: %v", err)
|
||||
}
|
||||
p := 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.
|
||||
faceClassifier, err = p.Unpack(cascade)
|
||||
if err != nil {
|
||||
log.Fatalf("Error unpacking the cascade file: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that we load the pupil localization cascade only once
|
||||
if len(puplocCascade) == 0 {
|
||||
puplocCascade, err = det.FetchCascade("https://raw.githubusercontent.com/esimov/pigo/master/cascade/puploc")
|
||||
if err != nil {
|
||||
det.Log("Error reading the puploc cascade file: %v", err)
|
||||
}
|
||||
|
||||
puplocClassifier, err = puplocClassifier.UnpackCascade(puplocCascade)
|
||||
if err != nil {
|
||||
log.Fatalf("Error unpacking the puploc cascade file: %s", err)
|
||||
}
|
||||
|
||||
flpcs, err = d.parseCascadeFiles("https://raw.githubusercontent.com/esimov/pigo/master/cascade/lps/")
|
||||
if err != nil {
|
||||
log.Fatalf("Error unpacking the facial landmark detection cascades: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 := faceClassifier.RunCascade(cParams, 0.0)
|
||||
|
@@ -34,6 +34,7 @@ func (d *Detector) FetchCascade(url string) ([]byte, error) {
|
||||
response.Call("arrayBuffer").Call("then", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
go func() {
|
||||
buffer := args[0]
|
||||
fmt.Println(buffer.Get("byteLength").Int())
|
||||
uint8Array := js.Global().Get("Uint8Array").New(buffer)
|
||||
|
||||
jsbuf := make([]byte, uint8Array.Get("length").Int())
|
||||
|
Reference in New Issue
Block a user