Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
F
face-api.js
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
allan
face-api.js
Commits
4205fc29
Commit
4205fc29
authored
May 03, 2019
by
vincent
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
allow face alignment before classification
parent
256ee654
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
89 additions
and
33 deletions
+89
-33
FaceLandmarks.ts
src/classes/FaceLandmarks.ts
+23
-5
ComputeFaceDescriptorsTasks.ts
src/globalApi/ComputeFaceDescriptorsTasks.ts
+9
-9
DetectFaceLandmarksTasks.ts
src/globalApi/DetectFaceLandmarksTasks.ts
+12
-1
DetectFacesTasks.ts
src/globalApi/DetectFacesTasks.ts
+3
-3
PredictFaceExpressionsTask.ts
src/globalApi/PredictFaceExpressionsTask.ts
+27
-14
minBbox.ts
src/minBbox.ts
+12
-0
TinyXception.ts
src/xception/TinyXception.ts
+3
-1
No files found.
src/classes/FaceLandmarks.ts
View file @
4205fc29
import
{
Dimensions
,
getCenterPoint
,
IDimensions
,
Point
,
Rect
}
from
'tfjs-image-recognition-base'
;
import
{
Box
,
Dimensions
,
getCenterPoint
,
IBoundingBox
,
IDimensions
,
IRect
,
Point
,
Rect
}
from
'tfjs-image-recognition-base'
;
import
{
minBbox
}
from
'../minBbox'
;
import
{
FaceDetection
}
from
'./FaceDetection'
;
// face alignment constants
...
...
@@ -71,16 +72,28 @@ export class FaceLandmarks implements IFaceLandmarks {
* @returns The bounding box of the aligned face.
*/
public
align
(
detection
?:
FaceDetection
|
Rect
):
Rect
{
detection
?:
FaceDetection
|
IRect
|
IBoundingBox
|
null
,
options
:
{
useDlibAlignment
?:
boolean
,
minBoxPadding
?:
number
}
=
{
}
):
Box
{
if
(
detection
)
{
const
box
=
detection
instanceof
FaceDetection
?
detection
.
box
.
floor
()
:
detection
:
new
Box
(
detection
)
return
this
.
shiftBy
(
box
.
x
,
box
.
y
).
align
()
return
this
.
shiftBy
(
box
.
x
,
box
.
y
).
align
(
null
,
options
)
}
const
{
useDlibAlignment
,
minBoxPadding
}
=
Object
.
assign
({},
{
useDlibAlignment
:
false
,
minBoxPadding
:
0.2
},
options
)
if
(
useDlibAlignment
)
{
return
this
.
alignDlib
()
}
return
this
.
alignMinBbox
(
minBoxPadding
)
}
private
alignDlib
():
Box
{
const
centers
=
this
.
getRefPointsForAlignment
()
const
[
leftEyeCenter
,
rightEyeCenter
,
mouthCenter
]
=
centers
...
...
@@ -97,6 +110,11 @@ export class FaceLandmarks implements IFaceLandmarks {
return
new
Rect
(
x
,
y
,
Math
.
min
(
size
,
this
.
imageWidth
+
x
),
Math
.
min
(
size
,
this
.
imageHeight
+
y
))
}
private
alignMinBbox
(
padding
:
number
):
Box
{
const
box
=
minBbox
(
this
.
positions
)
return
box
.
pad
(
box
.
width
*
padding
,
box
.
height
*
padding
)
}
protected
getRefPointsForAlignment
():
Point
[]
{
throw
new
Error
(
'getRefPointsForAlignment not implemented by base class'
)
}
...
...
src/globalApi/ComputeFaceDescriptorsTasks.ts
View file @
4205fc29
...
...
@@ -25,17 +25,17 @@ export class ComputeAllFaceDescriptorsTask<
const
parentResults
=
await
this
.
parentTask
const
alignedRects
=
parentResults
.
map
(({
alignedRect
})
=>
alignedRect
)
const
a
lignedFaces
:
Array
<
HTMLCanvasElement
|
tf
.
Tensor3D
>
=
this
.
input
instanceof
tf
.
Tensor
?
await
extractFaceTensors
(
this
.
input
,
a
lignedRects
)
:
await
extractFaces
(
this
.
input
,
a
lignedRects
)
const
dlibAlignedRects
=
parentResults
.
map
(({
landmarks
})
=>
landmarks
.
align
(
null
,
{
useDlibAlignment
:
true
})
)
const
dlibA
lignedFaces
:
Array
<
HTMLCanvasElement
|
tf
.
Tensor3D
>
=
this
.
input
instanceof
tf
.
Tensor
?
await
extractFaceTensors
(
this
.
input
,
dlibA
lignedRects
)
:
await
extractFaces
(
this
.
input
,
dlibA
lignedRects
)
const
results
=
await
Promise
.
all
(
parentResults
.
map
(
async
(
parentResult
,
i
)
=>
{
const
descriptor
=
await
nets
.
faceRecognitionNet
.
computeFaceDescriptor
(
a
lignedFaces
[
i
])
as
Float32Array
const
descriptor
=
await
nets
.
faceRecognitionNet
.
computeFaceDescriptor
(
dlibA
lignedFaces
[
i
])
as
Float32Array
return
extendWithFaceDescriptor
<
TSource
>
(
parentResult
,
descriptor
)
}))
a
lignedFaces
.
forEach
(
f
=>
f
instanceof
tf
.
Tensor
&&
f
.
dispose
())
dlibA
lignedFaces
.
forEach
(
f
=>
f
instanceof
tf
.
Tensor
&&
f
.
dispose
())
return
results
}
...
...
@@ -52,10 +52,10 @@ export class ComputeSingleFaceDescriptorTask<
return
}
const
{
alignedRect
}
=
parentResult
const
dlibAlignedRect
=
parentResult
.
landmarks
.
align
(
null
,
{
useDlibAlignment
:
true
})
const
alignedFaces
:
Array
<
HTMLCanvasElement
|
tf
.
Tensor3D
>
=
this
.
input
instanceof
tf
.
Tensor
?
await
extractFaceTensors
(
this
.
input
,
[
a
lignedRect
])
:
await
extractFaces
(
this
.
input
,
[
a
lignedRect
])
?
await
extractFaceTensors
(
this
.
input
,
[
dlibA
lignedRect
])
:
await
extractFaces
(
this
.
input
,
[
dlibA
lignedRect
])
const
descriptor
=
await
nets
.
faceRecognitionNet
.
computeFaceDescriptor
(
alignedFaces
[
0
])
as
Float32Array
alignedFaces
.
forEach
(
f
=>
f
instanceof
tf
.
Tensor
&&
f
.
dispose
())
...
...
src/globalApi/DetectFaceLandmarksTasks.ts
View file @
4205fc29
...
...
@@ -10,7 +10,10 @@ import { extendWithFaceLandmarks, WithFaceLandmarks } from '../factories/WithFac
import
{
ComposableTask
}
from
'./ComposableTask'
;
import
{
ComputeAllFaceDescriptorsTask
,
ComputeSingleFaceDescriptorTask
}
from
'./ComputeFaceDescriptorsTasks'
;
import
{
nets
}
from
'./nets'
;
import
{
PredictAllFaceExpressionsTask
,
PredictSingleFaceExpressionTask
}
from
'./PredictFaceExpressionsTask'
;
import
{
PredictAllFaceExpressionsWithFaceAlignmentTask
,
PredictSingleFaceExpressionsWithFaceAlignmentTask
,
}
from
'./PredictFaceExpressionsTask'
;
export
class
DetectFaceLandmarksTaskBase
<
TReturn
,
TParentReturn
>
extends
ComposableTask
<
TReturn
>
{
constructor
(
...
...
@@ -52,6 +55,10 @@ export class DetectAllFaceLandmarksTask<
)
}
withFaceExpressions
():
PredictAllFaceExpressionsWithFaceAlignmentTask
<
WithFaceLandmarks
<
TSource
>>
{
return
new
PredictAllFaceExpressionsWithFaceAlignmentTask
<
WithFaceLandmarks
<
TSource
>>
(
this
,
this
.
input
)
}
withFaceDescriptors
():
ComputeAllFaceDescriptorsTask
<
WithFaceLandmarks
<
TSource
>>
{
return
new
ComputeAllFaceDescriptorsTask
<
WithFaceLandmarks
<
TSource
>>
(
this
,
this
.
input
)
}
...
...
@@ -80,6 +87,10 @@ export class DetectSingleFaceLandmarksTask<
return
extendWithFaceLandmarks
<
TSource
>
(
parentResult
,
landmarks
)
}
withFaceExpressions
():
PredictSingleFaceExpressionsWithFaceAlignmentTask
<
WithFaceLandmarks
<
TSource
>>
{
return
new
PredictSingleFaceExpressionsWithFaceAlignmentTask
<
WithFaceLandmarks
<
TSource
>>
(
this
,
this
.
input
)
}
withFaceDescriptor
():
ComputeSingleFaceDescriptorTask
<
WithFaceLandmarks
<
TSource
>>
{
return
new
ComputeSingleFaceDescriptorTask
<
WithFaceLandmarks
<
TSource
>>
(
this
,
this
.
input
)
}
...
...
src/globalApi/DetectFacesTasks.ts
View file @
4205fc29
...
...
@@ -8,7 +8,7 @@ import { TinyFaceDetectorOptions } from '../tinyFaceDetector/TinyFaceDetectorOpt
import
{
ComposableTask
}
from
'./ComposableTask'
;
import
{
DetectAllFaceLandmarksTask
,
DetectSingleFaceLandmarksTask
}
from
'./DetectFaceLandmarksTasks'
;
import
{
nets
}
from
'./nets'
;
import
{
PredictAllFaceExpressionsTask
,
PredictSingleFaceExpressionTask
}
from
'./PredictFaceExpressionsTask'
;
import
{
PredictAllFaceExpressionsTask
,
PredictSingleFaceExpression
s
Task
}
from
'./PredictFaceExpressionsTask'
;
import
{
FaceDetectionOptions
}
from
'./types'
;
export
class
DetectFacesTaskBase
<
TReturn
>
extends
ComposableTask
<
TReturn
>
{
...
...
@@ -101,8 +101,8 @@ export class DetectSingleFaceTask extends DetectFacesTaskBase<FaceDetection | un
)
}
withFaceExpressions
():
PredictSingleFaceExpressionTask
<
WithFaceDetection
<
{}
>>
{
return
new
PredictSingleFaceExpressionTask
<
WithFaceDetection
<
{}
>>
(
withFaceExpressions
():
PredictSingleFaceExpression
s
Task
<
WithFaceDetection
<
{}
>>
{
return
new
PredictSingleFaceExpression
s
Task
<
WithFaceDetection
<
{}
>>
(
this
.
runAndExtendWithFaceDetection
(),
this
.
input
)
...
...
src/globalApi/PredictFaceExpressionsTask.ts
View file @
4205fc29
...
...
@@ -5,8 +5,9 @@ import { extractFaces, extractFaceTensors } from '../dom';
import
{
FaceExpressions
}
from
'../faceExpressionNet/FaceExpressions'
;
import
{
WithFaceDetection
}
from
'../factories/WithFaceDetection'
;
import
{
extendWithFaceExpressions
,
WithFaceExpressions
}
from
'../factories/WithFaceExpressions'
;
import
{
isWithFaceLandmarks
,
WithFaceLandmarks
}
from
'../factories/WithFaceLandmarks'
;
import
{
ComposableTask
}
from
'./ComposableTask'
;
import
{
DetectAllFaceLandmarksTask
,
DetectSingleFaceLandmarksTask
}
from
'./DetectFaceLandmark
sTasks'
;
import
{
ComputeAllFaceDescriptorsTask
,
ComputeSingleFaceDescriptorTask
}
from
'./ComputeFaceDescriptor
sTasks'
;
import
{
nets
}
from
'./nets'
;
export
class
PredictFaceExpressionsTaskBase
<
TReturn
,
TParentReturn
>
extends
ComposableTask
<
TReturn
>
{
...
...
@@ -26,10 +27,12 @@ export class PredictAllFaceExpressionsTask<
const
parentResults
=
await
this
.
parentTask
const
detections
=
parentResults
.
map
(
parentResult
=>
parentResult
.
detection
)
const
faceBoxes
=
parentResults
.
map
(
parentResult
=>
isWithFaceLandmarks
(
parentResult
)
?
parentResult
.
alignedRect
:
parentResult
.
detection
)
const
faces
:
Array
<
HTMLCanvasElement
|
tf
.
Tensor3D
>
=
this
.
input
instanceof
tf
.
Tensor
?
await
extractFaceTensors
(
this
.
input
,
detection
s
)
:
await
extractFaces
(
this
.
input
,
detection
s
)
?
await
extractFaceTensors
(
this
.
input
,
faceBoxe
s
)
:
await
extractFaces
(
this
.
input
,
faceBoxe
s
)
const
faceExpressionsByFace
=
await
Promise
.
all
(
faces
.
map
(
face
=>
nets
.
faceExpressionNet
.
predictExpressions
(
face
)
...
...
@@ -41,13 +44,9 @@ export class PredictAllFaceExpressionsTask<
(
parentResult
,
i
)
=>
extendWithFaceExpressions
<
TSource
>
(
parentResult
,
faceExpressionsByFace
[
i
])
)
}
withFaceLandmarks
():
DetectAllFaceLandmarksTask
<
WithFaceExpressions
<
TSource
>>
{
return
new
DetectAllFaceLandmarksTask
(
this
,
this
.
input
,
false
)
}
}
export
class
PredictSingleFaceExpressionTask
<
export
class
PredictSingleFaceExpression
s
Task
<
TSource
extends
WithFaceDetection
<
{}
>
>
extends
PredictFaceExpressionsTaskBase
<
WithFaceExpressions
<
TSource
>
|
undefined
,
TSource
|
undefined
>
{
...
...
@@ -58,10 +57,10 @@ export class PredictSingleFaceExpressionTask<
return
}
const
{
detection
}
=
parentResult
const
faceBox
=
isWithFaceLandmarks
(
parentResult
)
?
parentResult
.
alignedRect
:
parentResult
.
detection
const
faces
:
Array
<
HTMLCanvasElement
|
tf
.
Tensor3D
>
=
this
.
input
instanceof
tf
.
Tensor
?
await
extractFaceTensors
(
this
.
input
,
[
detection
])
:
await
extractFaces
(
this
.
input
,
[
detection
])
?
await
extractFaceTensors
(
this
.
input
,
[
faceBox
])
:
await
extractFaces
(
this
.
input
,
[
faceBox
])
const
faceExpressions
=
await
nets
.
faceExpressionNet
.
predictExpressions
(
faces
[
0
])
as
FaceExpressions
...
...
@@ -69,8 +68,22 @@ export class PredictSingleFaceExpressionTask<
return
extendWithFaceExpressions
(
parentResult
,
faceExpressions
)
}
}
export
class
PredictAllFaceExpressionsWithFaceAlignmentTask
<
TSource
extends
WithFaceLandmarks
<
WithFaceDetection
<
{}
>>
>
extends
PredictAllFaceExpressionsTask
<
TSource
>
{
withFaceDescriptors
():
ComputeAllFaceDescriptorsTask
<
WithFaceLandmarks
<
TSource
>>
{
return
new
ComputeAllFaceDescriptorsTask
<
WithFaceLandmarks
<
TSource
>>
(
this
,
this
.
input
)
}
}
export
class
PredictSingleFaceExpressionsWithFaceAlignmentTask
<
TSource
extends
WithFaceLandmarks
<
WithFaceDetection
<
{}
>>
>
extends
PredictSingleFaceExpressionsTask
<
TSource
>
{
withFace
Landmarks
():
DetectSingleFaceLandmarksTask
<
WithFaceExpression
s
<
TSource
>>
{
return
new
DetectSingleFaceLandmarksTask
(
this
,
this
.
input
,
false
)
withFace
Descriptor
():
ComputeSingleFaceDescriptorTask
<
WithFaceLandmark
s
<
TSource
>>
{
return
new
ComputeSingleFaceDescriptorTask
<
WithFaceLandmarks
<
TSource
>>
(
this
,
this
.
input
)
}
}
\ No newline at end of file
src/minBbox.ts
0 → 100644
View file @
4205fc29
import
{
BoundingBox
,
IPoint
}
from
'tfjs-image-recognition-base'
;
export
function
minBbox
(
pts
:
IPoint
[]):
BoundingBox
{
const
xs
=
pts
.
map
(
pt
=>
pt
.
x
)
const
ys
=
pts
.
map
(
pt
=>
pt
.
y
)
const
minX
=
xs
.
reduce
((
min
,
x
)
=>
x
<
min
?
x
:
min
,
Infinity
)
const
minY
=
ys
.
reduce
((
min
,
y
)
=>
y
<
min
?
y
:
min
,
Infinity
)
const
maxX
=
xs
.
reduce
((
max
,
x
)
=>
max
<
x
?
x
:
max
,
0
)
const
maxY
=
ys
.
reduce
((
max
,
y
)
=>
max
<
y
?
y
:
max
,
0
)
return
new
BoundingBox
(
minX
,
minY
,
maxX
,
maxY
)
}
src/xception/TinyXception.ts
View file @
4205fc29
...
...
@@ -10,6 +10,7 @@ import {
}
from
'tfjs-image-recognition-base'
;
import
{
depthwiseSeparableConv
}
from
'../common/depthwiseSeparableConv'
;
import
{
bgrToRgbTensor
}
from
'../mtcnn/bgrToRgbTensor'
;
import
{
extractParams
}
from
'./extractParams'
;
import
{
extractParamsFromWeigthMap
}
from
'./extractParamsFromWeigthMap'
;
import
{
MainBlockParams
,
ReductionBlockParams
,
TinyXceptionParams
}
from
'./types'
;
...
...
@@ -54,8 +55,9 @@ export class TinyXception extends NeuralNetwork<TinyXceptionParams> {
return
tf
.
tidy
(()
=>
{
const
batchTensor
=
input
.
toBatchTensor
(
112
,
true
)
const
batchTensorRgb
=
bgrToRgbTensor
(
batchTensor
)
const
meanRgb
=
[
122.782
,
117.001
,
104.298
]
const
normalized
=
normalize
(
batchTensor
,
meanRgb
).
div
(
tf
.
scalar
(
255
))
as
tf
.
Tensor4D
const
normalized
=
normalize
(
batchTensor
Rgb
,
meanRgb
).
div
(
tf
.
scalar
(
256
))
as
tf
.
Tensor4D
let
out
=
tf
.
relu
(
conv
(
normalized
,
params
.
entry_flow
.
conv_in
,
[
2
,
2
]))
out
=
reductionBlock
(
out
,
params
.
entry_flow
.
reduction_block_0
,
false
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment