Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
F
face
Project
Overview
Details
Activity
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
Иван Кубота
face
Commits
5b215ad6
Commit
5b215ad6
authored
Jul 16, 2018
by
vincent
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
mtcnn face recognition + face alignment examples
parent
930f85b0
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
409 additions
and
14 deletions
+409
-14
commons.js
examples/public/commons.js
+8
-0
server.js
examples/server.js
+2
-0
faceAlignment.html
examples/views/faceAlignment.html
+65
-10
mtcnnFaceDetectionWebcam.html
examples/views/mtcnnFaceDetectionWebcam.html
+1
-4
mtcnnFaceRecognition.html
examples/views/mtcnnFaceRecognition.html
+194
-0
mtcnnFaceRecognitionWebcam.html
examples/views/mtcnnFaceRecognitionWebcam.html
+139
-0
No files found.
examples/public/commons.js
View file @
5b215ad6
...
...
@@ -127,6 +127,14 @@ function renderNavBar(navbarId, exampleUri) {
name
:
'MTCNN Face Detection Webcam'
},
{
uri
:
'mtcnn_face_recognition'
,
name
:
'MTCNN Face Recognition'
},
{
uri
:
'mtcnn_face_recognition_webcam'
,
name
:
'MTCNN Face Recognition Webcam'
},
{
uri
:
'batch_face_landmarks'
,
name
:
'Batch Face Landmarks'
},
...
...
examples/server.js
View file @
5b215ad6
...
...
@@ -27,6 +27,8 @@ app.get('/detect_and_recognize_faces', (req, res) => res.sendFile(path.join(view
app
.
get
(
'/mtcnn_face_detection'
,
(
req
,
res
)
=>
res
.
sendFile
(
path
.
join
(
viewsDir
,
'mtcnnFaceDetection.html'
)))
app
.
get
(
'/mtcnn_face_detection_video'
,
(
req
,
res
)
=>
res
.
sendFile
(
path
.
join
(
viewsDir
,
'mtcnnFaceDetectionVideo.html'
)))
app
.
get
(
'/mtcnn_face_detection_webcam'
,
(
req
,
res
)
=>
res
.
sendFile
(
path
.
join
(
viewsDir
,
'mtcnnFaceDetectionWebcam.html'
)))
app
.
get
(
'/mtcnn_face_recognition'
,
(
req
,
res
)
=>
res
.
sendFile
(
path
.
join
(
viewsDir
,
'mtcnnFaceRecognition.html'
)))
app
.
get
(
'/mtcnn_face_recognition_webcam'
,
(
req
,
res
)
=>
res
.
sendFile
(
path
.
join
(
viewsDir
,
'mtcnnFaceRecognitionWebcam.html'
)))
app
.
get
(
'/batch_face_landmarks'
,
(
req
,
res
)
=>
res
.
sendFile
(
path
.
join
(
viewsDir
,
'batchFaceLandmarks.html'
)))
app
.
get
(
'/batch_face_recognition'
,
(
req
,
res
)
=>
res
.
sendFile
(
path
.
join
(
viewsDir
,
'batchFaceRecognition.html'
)))
...
...
examples/views/faceAlignment.html
View file @
5b215ad6
...
...
@@ -50,11 +50,17 @@
<i
class=
"material-icons left"
>
+
</i>
</button>
</div>
<div
class=
"row"
>
<p>
<input
type=
"checkbox"
id=
"drawLinesCheckbox"
onchange=
"onChangeUseMtcnn(event)"
/>
<label
for=
"drawLinesCheckbox"
>
Use Mtcnn
</label>
</p>
</div>
</div>
<script>
let
minConfidence
=
0.7
let
drawLines
=
tru
e
let
useMtcnn
=
fals
e
function
onIncreaseMinConfidence
()
{
minConfidence
=
Math
.
min
(
faceapi
.
round
(
minConfidence
+
0.1
),
1.0
)
...
...
@@ -68,26 +74,54 @@
updateResults
()
}
function
onChangeUseMtcnn
(
e
)
{
useMtcnn
=
$
(
e
.
target
).
prop
(
'checked'
)
updateResults
()
}
async
function
loadImageFromUrl
(
url
)
{
const
img
=
await
requestExternalImage
(
$
(
'#imgUrlInput'
).
val
())
$
(
'#inputImg'
).
get
(
0
).
src
=
img
.
src
updateResults
()
}
async
function
updateResults
()
{
const
inputImgEl
=
$
(
'#inputImg'
).
get
(
0
)
const
{
width
,
height
}
=
inputImgEl
const
canvas
=
$
(
'#overlay'
).
get
(
0
)
canvas
.
width
=
width
canvas
.
height
=
height
async
function
locateAndAlignFacesWithMtcnn
(
inputImgEl
)
{
const
input
=
await
faceapi
.
toNetInput
(
inputImgEl
,
// dispose input manually
false
,
// keep canvases (required for mtcnn)
true
)
const
results
=
await
faceapi
.
mtcnn
(
input
,
{
minFaceSize
:
100
})
const
unalignedFaceImages
=
await
faceapi
.
extractFaces
(
input
.
inputs
[
0
],
results
.
map
(
res
=>
res
.
faceDetection
))
const
alignedFaceBoxes
=
results
.
filter
(
res
=>
res
.
faceDetection
.
score
>
minConfidence
)
.
map
(
res
=>
res
.
faceLandmarks
.
align
())
const
alignedFaceImages
=
await
faceapi
.
extractFaces
(
input
.
inputs
[
0
],
alignedFaceBoxes
)
// free memory for input tensors
input
.
dispose
()
return
{
unalignedFaceImages
,
alignedFaceImages
}
}
async
function
locateAndAlignFacesWithSSD
(
inputImgEl
)
{
const
input
=
await
faceapi
.
toNetInput
(
inputImgEl
)
const
locations
=
await
faceapi
.
locateFaces
(
input
,
minConfidence
)
const
f
aceImages
=
await
faceapi
.
extractFaces
(
input
.
inputs
[
0
],
locations
)
const
unalignedF
aceImages
=
await
faceapi
.
extractFaces
(
input
.
inputs
[
0
],
locations
)
// detect landmarks and get the aligned face image bounding boxes
const
alignedFaceBoxes
=
await
Promise
.
all
(
f
aceImages
.
map
(
const
alignedFaceBoxes
=
await
Promise
.
all
(
unalignedF
aceImages
.
map
(
async
(
faceCanvas
,
i
)
=>
{
const
faceLandmarks
=
await
faceapi
.
detectLandmarks
(
faceCanvas
)
return
faceLandmarks
.
align
(
locations
[
i
])
...
...
@@ -98,8 +132,28 @@
// free memory for input tensors
input
.
dispose
()
return
{
unalignedFaceImages
,
alignedFaceImages
}
}
async
function
updateResults
()
{
const
inputImgEl
=
$
(
'#inputImg'
).
get
(
0
)
const
{
width
,
height
}
=
inputImgEl
const
canvas
=
$
(
'#overlay'
).
get
(
0
)
canvas
.
width
=
width
canvas
.
height
=
height
const
{
unalignedFaceImages
,
alignedFaceImages
}
=
useMtcnn
?
await
locateAndAlignFacesWithMtcnn
(
inputImgEl
)
:
await
locateAndAlignFacesWithSSD
(
inputImgEl
)
$
(
'#facesContainer'
).
empty
()
f
aceImages
.
forEach
(
async
(
faceCanvas
,
i
)
=>
{
unalignedF
aceImages
.
forEach
(
async
(
faceCanvas
,
i
)
=>
{
$
(
'#facesContainer'
).
append
(
faceCanvas
)
$
(
'#facesContainer'
).
append
(
alignedFaceImages
[
i
])
})
...
...
@@ -114,6 +168,7 @@
async
function
run
()
{
await
faceapi
.
loadFaceDetectionModel
(
'/'
)
await
faceapi
.
loadFaceLandmarkModel
(
'/'
)
await
faceapi
.
loadMtcnnModel
(
'/'
)
$
(
'#loader'
).
hide
()
onSelectionChanged
(
$
(
'#selectList select'
).
val
())
}
...
...
examples/views/mtcnnFaceDetectionWebcam.html
View file @
5b215ad6
...
...
@@ -84,10 +84,7 @@
minFaceSize
}
const
c
=
faceapi
.
createCanvas
({
width
:
width
,
height
:
height
})
c
.
getContext
(
'2d'
).
drawImage
(
videoEl
,
0
,
0
)
const
{
results
,
stats
}
=
await
faceapi
.
nets
.
mtcnn
.
forwardWithStats
(
c
,
mtcnnParams
)
const
{
results
,
stats
}
=
await
faceapi
.
nets
.
mtcnn
.
forwardWithStats
(
videoEl
,
mtcnnParams
)
updateTimeStats
(
stats
.
total
)
if
(
results
)
{
...
...
examples/views/mtcnnFaceRecognition.html
0 → 100644
View file @
5b215ad6
<!DOCTYPE html>
<html>
<head>
<script
src=
"face-api.js"
></script>
<script
src=
"commons.js"
></script>
<link
rel=
"stylesheet"
href=
"styles.css"
>
<link
rel=
"stylesheet"
href=
"https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.css"
>
<script
type=
"text/javascript"
src=
"https://code.jquery.com/jquery-2.1.1.min.js"
></script>
<script
src=
"https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"
></script>
</head>
<body>
<div
id=
"navbar"
></div>
<div
class=
"center-content page-container"
>
<div
class=
"progress"
id=
"loader"
>
<div
class=
"indeterminate"
></div>
</div>
<div
style=
"position: relative"
class=
"margin"
>
<img
id=
"inputImg"
src=
""
style=
"max-width: 800px;"
/>
<canvas
id=
"overlay"
/>
</div>
<div
class=
"row side-by-side"
>
<div
id=
"selectList"
></div>
<div
class=
"row"
>
<label
for=
"imgUrlInput"
>
Get image from URL:
</label>
<input
id=
"imgUrlInput"
type=
"text"
class=
"bold"
>
</div>
<button
class=
"waves-effect waves-light btn"
onclick=
"loadImageFromUrl()"
>
Ok
</button>
</div>
<div
class=
"row side-by-side"
>
<div
class=
"row side-by-side"
>
<div
class=
"row"
>
<label
for=
"minFaceSize"
>
Minimum Face Size:
</label>
<input
disabled
value=
"40"
id=
"minFaceSize"
type=
"text"
class=
"bold"
>
</div>
<button
class=
"waves-effect waves-light btn"
onclick=
"onDecreaseMinFaceSize()"
>
<i
class=
"material-icons left"
>
-
</i>
</button>
<button
class=
"waves-effect waves-light btn"
onclick=
"onIncreaseMinFaceSize()"
>
<i
class=
"material-icons left"
>
+
</i>
</button>
</div>
<div
class=
"row"
>
<label
for=
"minConfidence"
>
Min Confidence:
</label>
<input
disabled
value=
"0.7"
id=
"minConfidence"
type=
"text"
class=
"bold"
>
</div>
<button
class=
"waves-effect waves-light btn button-sm"
onclick=
"onDecreaseMinConfidence()"
>
<i
class=
"material-icons left"
>
-
</i>
</button>
<button
class=
"waves-effect waves-light btn button-sm"
onclick=
"onIncreaseMinConfidence()"
>
<i
class=
"material-icons left"
>
+
</i>
</button>
<div
class=
"row"
>
<label
for=
"maxDistance"
>
Max Descriptor Distance:
</label>
<input
disabled
value=
"0.6"
id=
"maxDistance"
type=
"text"
class=
"bold"
>
</div>
<button
class=
"waves-effect waves-light btn button-sm"
onclick=
"onDecreaseMaxDistance()"
>
<i
class=
"material-icons left"
>
-
</i>
</button>
<button
class=
"waves-effect waves-light btn button-sm"
onclick=
"onIncreaseMaxDistance()"
>
<i
class=
"material-icons left"
>
+
</i>
</button>
</div>
</div>
<script>
let
maxDistance
=
0.6
let
minConfidence
=
0.7
let
minFaceSize
=
40
let
trainDescriptorsByClass
=
[]
function
onIncreaseMinFaceSize
()
{
minFaceSize
=
Math
.
min
(
faceapi
.
round
(
minFaceSize
+
20
),
200
)
$
(
'#minFaceSize'
).
val
(
minFaceSize
)
}
function
onDecreaseMinFaceSize
()
{
minFaceSize
=
Math
.
max
(
faceapi
.
round
(
minFaceSize
-
20
),
20
)
$
(
'#minFaceSize'
).
val
(
minFaceSize
)
}
function
onIncreaseMinConfidence
()
{
minConfidence
=
Math
.
min
(
faceapi
.
round
(
minConfidence
+
0.1
),
1.0
)
$
(
'#minConfidence'
).
val
(
minConfidence
)
updateResults
()
}
function
onDecreaseMinConfidence
()
{
minConfidence
=
Math
.
max
(
faceapi
.
round
(
minConfidence
-
0.1
),
0.1
)
$
(
'#minConfidence'
).
val
(
minConfidence
)
updateResults
()
}
function
onIncreaseMaxDistance
()
{
maxDistance
=
Math
.
min
(
faceapi
.
round
(
maxDistance
+
0.1
),
1.0
)
$
(
'#maxDistance'
).
val
(
maxDistance
)
updateResults
()
}
function
onDecreaseMaxDistance
()
{
maxDistance
=
Math
.
max
(
faceapi
.
round
(
maxDistance
-
0.1
),
0.1
)
$
(
'#maxDistance'
).
val
(
maxDistance
)
updateResults
()
}
async
function
loadImageFromUrl
(
url
)
{
const
img
=
await
requestExternalImage
(
$
(
'#imgUrlInput'
).
val
())
$
(
'#inputImg'
).
get
(
0
).
src
=
img
.
src
updateResults
()
}
async
function
updateResults
()
{
const
inputImgEl
=
$
(
'#inputImg'
).
get
(
0
)
const
{
width
,
height
}
=
inputImgEl
const
canvas
=
$
(
'#overlay'
).
get
(
0
)
canvas
.
width
=
width
canvas
.
height
=
height
const
mtcnnParams
=
{
minFaceSize
}
const
fullFaceDescriptions
=
(
await
faceapi
.
allFacesMtcnn
(
inputImgEl
,
mtcnnParams
))
.
map
(
fd
=>
fd
.
forSize
(
width
,
height
))
fullFaceDescriptions
.
forEach
(({
detection
,
landmarks
,
descriptor
})
=>
{
faceapi
.
drawDetection
(
'overlay'
,
[
detection
],
{
withScore
:
false
})
faceapi
.
drawLandmarks
(
'overlay'
,
landmarks
,
{
lineWidth
:
4
,
color
:
'red'
})
const
bestMatch
=
getBestMatch
(
trainDescriptorsByClass
,
descriptor
)
const
text
=
`
${
bestMatch
.
distance
<
maxDistance
?
bestMatch
.
className
:
'unkown'
}
(
${
bestMatch
.
distance
}
)`
const
{
x
,
y
,
height
:
boxHeight
}
=
detection
.
getBox
()
faceapi
.
drawText
(
canvas
.
getContext
(
'2d'
),
x
,
y
+
boxHeight
,
text
,
Object
.
assign
(
faceapi
.
getDefaultDrawOptions
(),
{
color
:
'red'
,
fontSize
:
16
})
)
})
}
async
function
onSelectionChanged
(
uri
)
{
const
imgBuf
=
await
fetchImage
(
uri
)
$
(
`#inputImg`
).
get
(
0
).
src
=
(
await
faceapi
.
bufferToImage
(
imgBuf
)).
src
updateResults
()
}
async
function
run
()
{
await
faceapi
.
loadMtcnnModel
(
'/'
)
await
faceapi
.
loadFaceRecognitionModel
(
'/'
)
trainDescriptorsByClass
=
await
initTrainDescriptorsByClass
(
faceapi
.
recognitionNet
,
1
)
$
(
'#loader'
).
hide
()
onSelectionChanged
(
$
(
'#selectList select'
).
val
())
}
$
(
document
).
ready
(
function
()
{
renderNavBar
(
'#navbar'
,
'mtcnn_face_recognition'
)
renderImageSelectList
(
'#selectList'
,
async
(
uri
)
=>
{
await
onSelectionChanged
(
uri
)
},
'bbt1.jpg'
)
run
()
})
</script>
</body>
</html>
\ No newline at end of file
examples/views/mtcnnFaceRecognitionWebcam.html
0 → 100644
View file @
5b215ad6
<!DOCTYPE html>
<html>
<head>
<script
src=
"face-api.js"
></script>
<script
src=
"commons.js"
></script>
<link
rel=
"stylesheet"
href=
"styles.css"
>
<link
rel=
"stylesheet"
href=
"https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.css"
>
<script
type=
"text/javascript"
src=
"https://code.jquery.com/jquery-2.1.1.min.js"
></script>
<script
src=
"https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"
></script>
</head>
<body>
<div
id=
"navbar"
></div>
<div
class=
"center-content page-container"
>
<div
class=
"progress"
id=
"loader"
>
<div
class=
"indeterminate"
></div>
</div>
<div
style=
"position: relative"
class=
"margin"
>
<video
onplay=
"onPlay(this)"
id=
"inputVideo"
autoplay
muted
></video>
<canvas
id=
"overlay"
/>
</div>
<div
class=
"row side-by-side"
>
<div
class=
"row"
>
<label
for=
"minFaceSize"
>
Minimum Face Size:
</label>
<input
disabled
value=
"200"
id=
"minFaceSize"
type=
"text"
class=
"bold"
>
</div>
<button
class=
"waves-effect waves-light btn"
onclick=
"onDecreaseMinFaceSize()"
>
<i
class=
"material-icons left"
>
-
</i>
</button>
<button
class=
"waves-effect waves-light btn"
onclick=
"onIncreaseMinFaceSize()"
>
<i
class=
"material-icons left"
>
+
</i>
</button>
</div>
<div
class=
"row side-by-side"
>
<div
class=
"row"
>
<label
for=
"time"
>
Time:
</label>
<input
disabled
value=
"-"
id=
"time"
type=
"text"
class=
"bold"
>
</div>
<div
class=
"row"
>
<label
for=
"fps"
>
Estimated Fps:
</label>
<input
disabled
value=
"-"
id=
"fps"
type=
"text"
class=
"bold"
>
</div>
</div>
</div>
<script>
let
modelLoaded
=
false
let
minFaceSize
=
200
let
maxDistance
=
0.6
let
minConfidence
=
0.9
let
forwardTimes
=
[]
function
onIncreaseMinFaceSize
()
{
minFaceSize
=
Math
.
min
(
faceapi
.
round
(
minFaceSize
+
50
),
300
)
$
(
'#minFaceSize'
).
val
(
minFaceSize
)
}
function
onDecreaseMinFaceSize
()
{
minFaceSize
=
Math
.
max
(
faceapi
.
round
(
minFaceSize
-
50
),
50
)
$
(
'#minFaceSize'
).
val
(
minFaceSize
)
}
function
updateTimeStats
(
timeInMs
)
{
forwardTimes
=
[
timeInMs
].
concat
(
forwardTimes
).
slice
(
0
,
30
)
const
avgTimeInMs
=
forwardTimes
.
reduce
((
total
,
t
)
=>
total
+
t
)
/
forwardTimes
.
length
$
(
'#time'
).
val
(
`
${
Math
.
round
(
avgTimeInMs
)}
ms`
)
$
(
'#fps'
).
val
(
`
${
faceapi
.
round
(
1000
/
avgTimeInMs
)}
`
)
}
async
function
onPlay
(
videoEl
)
{
if
(
videoEl
.
paused
||
videoEl
.
ended
||
!
modelLoaded
)
return
false
const
{
width
,
height
}
=
faceapi
.
getMediaDimensions
(
videoEl
)
const
canvas
=
$
(
'#overlay'
).
get
(
0
)
canvas
.
width
=
width
canvas
.
height
=
height
const
mtcnnParams
=
{
minFaceSize
}
const
ts
=
Date
.
now
()
const
fullFaceDescriptions
=
(
await
faceapi
.
allFacesMtcnn
(
videoEl
,
mtcnnParams
))
.
map
(
fd
=>
fd
.
forSize
(
width
,
height
))
updateTimeStats
(
Date
.
now
()
-
ts
)
fullFaceDescriptions
.
forEach
(({
detection
,
landmarks
,
descriptor
})
=>
{
faceapi
.
drawDetection
(
'overlay'
,
[
detection
],
{
withScore
:
false
})
faceapi
.
drawLandmarks
(
'overlay'
,
landmarks
.
forSize
(
width
,
height
),
{
lineWidth
:
4
,
color
:
'red'
})
const
bestMatch
=
getBestMatch
(
trainDescriptorsByClass
,
descriptor
)
const
text
=
`
${
bestMatch
.
distance
<
maxDistance
?
bestMatch
.
className
:
'unkown'
}
(
${
bestMatch
.
distance
}
)`
const
{
x
,
y
,
height
:
boxHeight
}
=
detection
.
getBox
()
faceapi
.
drawText
(
canvas
.
getContext
(
'2d'
),
x
,
y
+
boxHeight
,
text
,
Object
.
assign
(
faceapi
.
getDefaultDrawOptions
(),
{
color
:
'red'
,
fontSize
:
16
})
)
})
setTimeout
(()
=>
onPlay
(
videoEl
))
}
async
function
run
()
{
await
faceapi
.
loadMtcnnModel
(
'/'
)
await
faceapi
.
loadFaceRecognitionModel
(
'/'
)
// init reference data, e.g. compute a face descriptor for each class
trainDescriptorsByClass
=
await
initTrainDescriptorsByClass
(
faceapi
.
recognitionNet
)
modelLoaded
=
true
// try to access users webcam and stream the images
// to the video element
const
videoEl
=
$
(
'#inputVideo'
).
get
(
0
)
navigator
.
getUserMedia
(
{
video
:
{}
},
stream
=>
videoEl
.
srcObject
=
stream
,
err
=>
console
.
error
(
err
)
)
$
(
'#loader'
).
hide
()
}
$
(
document
).
ready
(
function
()
{
renderNavBar
(
'#navbar'
,
'mtcnn_face_recognition_webcam'
)
run
()
})
</script>
</body>
</html>
\ No newline at end of file
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