Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
2
2021-035-CoviDefender
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
2021-035
2021-035-CoviDefender
Commits
727ddf92
Commit
727ddf92
authored
May 23, 2021
by
Indika NK
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added Heart rate monitor basic functionality
parent
5325cb03
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
425 additions
and
57 deletions
+425
-57
lib/I_GUIDER/i_guider.dart
lib/I_GUIDER/i_guider.dart
+17
-18
lib/assets/images/pulse.gif
lib/assets/images/pulse.gif
+0
-0
lib/main.dart
lib/main.dart
+2
-2
lib/pages/heart_rate/chart.dart
lib/pages/heart_rate/chart.dart
+36
-0
lib/pages/heart_rate/heart_rate_screen.dart
lib/pages/heart_rate/heart_rate_screen.dart
+32
-0
lib/pages/heart_rate/homePage.dart
lib/pages/heart_rate/homePage.dart
+299
-0
lib/pages/mask_detect/invoker.dart
lib/pages/mask_detect/invoker.dart
+28
-35
pubspec.yaml
pubspec.yaml
+11
-2
No files found.
lib/I_GUIDER/i_guider.dart
View file @
727ddf92
import
'package:covidefender/pages/heart_rate/heart_rate_screen.dart'
;
import
'package:covidefender/pages/mask_detect/invoker.dart'
;
import
'package:flutter/cupertino.dart'
;
import
'package:flutter/material.dart'
;
...
...
@@ -18,13 +19,10 @@ class I_guider extends StatelessWidget {
Expanded
(
child:
Container
(
decoration:
BoxDecoration
(
image:
DecorationImage
(
image:
AssetImage
(
'lib/assets/images/hero.gif'
),
fit:
BoxFit
.
cover
)
),
image:
DecorationImage
(
image:
AssetImage
(
'lib/assets/images/hero.gif'
),
fit:
BoxFit
.
cover
)),
height:
300
,
),
),
],
...
...
@@ -66,7 +64,7 @@ class I_guider extends StatelessWidget {
minWidth:
100.0
,
height:
150.0
,
child:
RaisedButton
.
icon
(
color:
Colors
.
red
[
200
]
,
color:
Colors
.
greenAccent
,
icon:
Icon
(
Icons
.
face_unlock_sharp
,
size:
60
,
...
...
@@ -78,7 +76,12 @@ class I_guider extends StatelessWidget {
),
onPressed:
()
{
print
(
'face mask detection'
);
Navigator
.
pushNamed
(
context
,
'/invoker'
);
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
invoker
())
);
// Navigator.pushNamed(context, '/invoker');
},
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
10
)),
...
...
@@ -98,18 +101,20 @@ class I_guider extends StatelessWidget {
minWidth:
100.0
,
height:
150.0
,
child:
RaisedButton
.
icon
(
icon:
Icon
(
Icons
.
notifications_active
,
Icons
.
view_stream_outlined
,
size:
40
,
color:
Colors
.
white
,
),
label:
Text
(
''
,
style:
TextStyle
(
fontWeight:
FontWeight
.
bold
)),
onPressed:
()
{},
onPressed:
()
{
// action when button is pressed route to heart rate measurer
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
HeartRateScreen
()
));
},
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
10
)),
color:
Colors
.
green
Accent
,
color:
Colors
.
red
Accent
,
),
),
),
...
...
@@ -140,12 +145,6 @@ class I_guider extends StatelessWidget {
)
],
),
],
),
);
...
...
lib/assets/images/pulse.gif
0 → 100644
View file @
727ddf92
33 KB
lib/main.dart
View file @
727ddf92
...
...
@@ -9,8 +9,8 @@ void main() => runApp(MaterialApp(
// initialRoute: '/guider',
routes:
{
'/'
:(
context
)
=>
HomeScreen
(),
'/guider'
:(
context
)
=>
I_guider
(),
'/invoker'
:(
context
)
=>
invoker
(),
//
'/guider':(context) => I_guider(),
//
'/invoker':(context) => invoker(),
},
...
...
lib/pages/heart_rate/chart.dart
0 → 100644
View file @
727ddf92
import
'package:charts_flutter/flutter.dart'
as
charts
;
import
'package:flutter/material.dart'
;
class
Chart
extends
StatelessWidget
{
final
List
<
SensorValue
>
_data
;
Chart
(
this
.
_data
);
@override
Widget
build
(
BuildContext
context
)
{
return
new
charts
.
TimeSeriesChart
([
charts
.
Series
<
SensorValue
,
DateTime
>(
id:
'Values'
,
colorFn:
(
_
,
__
)
=>
charts
.
MaterialPalette
.
green
.
shadeDefault
,
domainFn:
(
SensorValue
values
,
_
)
=>
values
.
time
,
measureFn:
(
SensorValue
values
,
_
)
=>
values
.
value
,
data:
_data
,
)
],
animate:
false
,
primaryMeasureAxis:
charts
.
NumericAxisSpec
(
tickProviderSpec:
charts
.
BasicNumericTickProviderSpec
(
zeroBound:
false
),
renderSpec:
charts
.
NoneRenderSpec
(),
),
domainAxis:
new
charts
.
DateTimeAxisSpec
(
renderSpec:
new
charts
.
NoneRenderSpec
()));
}
}
class
SensorValue
{
final
DateTime
time
;
final
double
value
;
SensorValue
(
this
.
time
,
this
.
value
);
}
lib/pages/heart_rate/heart_rate_screen.dart
0 → 100644
View file @
727ddf92
import
'package:covidefender/pages/heart_rate/homePage.dart'
;
import
'package:flutter/cupertino.dart'
;
import
'package:flutter/material.dart'
;
class
HeartRateScreen
extends
StatelessWidget
{
@override
Widget
build
(
BuildContext
context
)
{
return
Scaffold
(
appBar:
AppBar
(
title:
Text
(
'Heart Rate Detector'
),
),
body:
Column
(
children:
[
Padding
(
padding:
const
EdgeInsets
.
all
(
8.0
),
child:
Image
.
asset
(
'lib/assets/images/pulse.gif'
),
),
SizedBox
(
height:
20
),
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
ElevatedButton
(
onPressed:
()
=>
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
HomePage
(),)),
child:
Text
(
'Measure Heart Rate'
),
),
],
),
],
),
);
}
}
lib/pages/heart_rate/homePage.dart
0 → 100644
View file @
727ddf92
import
'dart:async'
;
import
'package:camera/camera.dart'
;
import
'package:flutter/material.dart'
;
import
'package:wakelock/wakelock.dart'
;
import
'chart.dart'
;
class
HomePage
extends
StatefulWidget
{
@override
HomePageView
createState
()
{
return
HomePageView
();
}
}
class
HomePageView
extends
State
<
HomePage
>
with
SingleTickerProviderStateMixin
{
bool
_toggled
=
false
;
// toggle button value
List
<
SensorValue
>
_data
=
List
<
SensorValue
>();
// array to store the values
CameraController
_controller
;
double
_alpha
=
0.3
;
// factor for the mean value
AnimationController
_animationController
;
double
_iconScale
=
1
;
int
_bpm
=
0
;
// beats per minute
int
_fs
=
30
;
// sampling frequency (fps)
int
_windowLen
=
30
*
6
;
// window length to display - 6 seconds
CameraImage
_image
;
// store the last camera image
double
_avg
;
// store the average value during calculation
DateTime
_now
;
// store the now Datetime
Timer
_timer
;
// timer for image processing
@override
void
initState
()
{
super
.
initState
();
_animationController
=
AnimationController
(
duration:
Duration
(
milliseconds:
500
),
vsync:
this
);
_animationController
..
addListener
(()
{
setState
(()
{
_iconScale
=
1.0
+
_animationController
.
value
*
0.4
;
});
});
}
@override
void
dispose
()
{
_timer
?.
cancel
();
_toggled
=
false
;
_disposeController
();
Wakelock
.
disable
();
_animationController
?.
stop
();
_animationController
?.
dispose
();
super
.
dispose
();
}
@override
Widget
build
(
BuildContext
context
)
{
return
Scaffold
(
backgroundColor:
Colors
.
white
,
body:
SafeArea
(
child:
Column
(
children:
<
Widget
>[
Expanded
(
flex:
1
,
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
<
Widget
>[
Expanded
(
flex:
1
,
child:
Padding
(
padding:
EdgeInsets
.
all
(
12
),
child:
ClipRRect
(
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
18
),
),
child:
Stack
(
fit:
StackFit
.
expand
,
alignment:
Alignment
.
center
,
children:
<
Widget
>[
_controller
!=
null
&&
_toggled
?
AspectRatio
(
aspectRatio:
_controller
.
value
.
aspectRatio
,
child:
CameraPreview
(
_controller
),
)
:
Container
(
padding:
EdgeInsets
.
all
(
12
),
alignment:
Alignment
.
center
,
color:
Colors
.
grey
,
),
Container
(
alignment:
Alignment
.
center
,
padding:
EdgeInsets
.
all
(
4
),
child:
Text
(
_toggled
?
"Cover both the camera and the flash with your finger"
:
"Camera feed will display here"
,
style:
TextStyle
(
backgroundColor:
_toggled
?
Colors
.
white
:
Colors
.
transparent
),
textAlign:
TextAlign
.
center
,
),
)
],
),
),
),
),
Expanded
(
flex:
1
,
child:
Center
(
child:
Column
(
mainAxisSize:
MainAxisSize
.
min
,
crossAxisAlignment:
CrossAxisAlignment
.
center
,
children:
<
Widget
>[
Text
(
"Estimated BPM"
,
style:
TextStyle
(
fontSize:
18
,
color:
Colors
.
grey
),
),
Text
(
(
_bpm
>
30
&&
_bpm
<
150
?
_bpm
.
toString
()
:
"--"
),
style:
TextStyle
(
fontSize:
32
,
fontWeight:
FontWeight
.
bold
),
),
],
)),
),
],
)),
Expanded
(
flex:
1
,
child:
Center
(
child:
Transform
.
scale
(
scale:
_iconScale
,
child:
IconButton
(
icon:
Icon
(
_toggled
?
Icons
.
favorite
:
Icons
.
favorite_border
),
color:
Colors
.
red
,
iconSize:
128
,
onPressed:
()
{
if
(
_toggled
)
{
_untoggle
();
}
else
{
_toggle
();
}
},
),
),
),
),
Expanded
(
flex:
1
,
child:
Container
(
margin:
EdgeInsets
.
all
(
12
),
decoration:
BoxDecoration
(
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
18
),
),
color:
Colors
.
black
),
child:
Chart
(
_data
),
),
),
],
),
),
);
}
void
_clearData
()
{
// create array of 128 ~= 255/2
_data
.
clear
();
int
now
=
DateTime
.
now
().
millisecondsSinceEpoch
;
for
(
int
i
=
0
;
i
<
_windowLen
;
i
++)
_data
.
insert
(
0
,
SensorValue
(
DateTime
.
fromMillisecondsSinceEpoch
(
now
-
i
*
1000
~/
_fs
),
128
));
}
void
_toggle
()
{
_clearData
();
_initController
().
then
((
onValue
)
{
Wakelock
.
enable
();
_animationController
?.
repeat
(
reverse:
true
);
setState
(()
{
_toggled
=
true
;
});
// after is toggled
_initTimer
();
_updateBPM
();
});
}
void
_untoggle
()
{
_disposeController
();
Wakelock
.
disable
();
_animationController
?.
stop
();
_animationController
?.
value
=
0.0
;
setState
(()
{
_toggled
=
false
;
});
}
void
_disposeController
()
{
_controller
?.
dispose
();
_controller
=
null
;
}
Future
<
void
>
_initController
()
async
{
try
{
List
_cameras
=
await
availableCameras
();
_controller
=
CameraController
(
_cameras
.
first
,
ResolutionPreset
.
low
);
await
_controller
.
initialize
();
Future
.
delayed
(
Duration
(
milliseconds:
100
)).
then
((
onValue
)
{
// _controller.flash(true);
});
_controller
.
startImageStream
((
CameraImage
image
)
{
_image
=
image
;
});
}
catch
(
Exception
)
{
debugPrint
(
Exception
);
}
}
void
_initTimer
()
{
_timer
=
Timer
.
periodic
(
Duration
(
milliseconds:
1000
~/
_fs
),
(
timer
)
{
if
(
_toggled
)
{
if
(
_image
!=
null
)
_scanImage
(
_image
);
}
else
{
timer
.
cancel
();
}
});
}
void
_scanImage
(
CameraImage
image
)
{
_now
=
DateTime
.
now
();
_avg
=
image
.
planes
.
first
.
bytes
.
reduce
((
value
,
element
)
=>
value
+
element
)
/
image
.
planes
.
first
.
bytes
.
length
;
if
(
_data
.
length
>=
_windowLen
)
{
_data
.
removeAt
(
0
);
}
setState
(()
{
_data
.
add
(
SensorValue
(
_now
,
_avg
));
});
}
void
_updateBPM
()
async
{
// Bear in mind that the method used to calculate the BPM is very rudimentar
// feel free to improve it :)
// Since this function doesn't need to be so "exact" regarding the time it executes,
// I only used the a Future.delay to repeat it from time to time.
// Ofc you can also use a Timer object to time the callback of this function
List
<
SensorValue
>
_values
;
double
_avg
;
int
_n
;
double
_m
;
double
_threshold
;
double
_bpm
;
int
_counter
;
int
_previous
;
while
(
_toggled
)
{
_values
=
List
.
from
(
_data
);
// create a copy of the current data array
_avg
=
0
;
_n
=
_values
.
length
;
_m
=
0
;
_values
.
forEach
((
SensorValue
value
)
{
_avg
+=
value
.
value
/
_n
;
if
(
value
.
value
>
_m
)
_m
=
value
.
value
;
});
_threshold
=
(
_m
+
_avg
)
/
2
;
_bpm
=
0
;
_counter
=
0
;
_previous
=
0
;
for
(
int
i
=
1
;
i
<
_n
;
i
++)
{
if
(
_values
[
i
-
1
].
value
<
_threshold
&&
_values
[
i
].
value
>
_threshold
)
{
if
(
_previous
!=
0
)
{
_counter
++;
_bpm
+=
60
*
1000
/
(
_values
[
i
].
time
.
millisecondsSinceEpoch
-
_previous
);
}
_previous
=
_values
[
i
].
time
.
millisecondsSinceEpoch
;
}
}
if
(
_counter
>
0
)
{
_bpm
=
_bpm
/
_counter
;
print
(
_bpm
);
setState
(()
{
this
.
_bpm
=
((
1
-
_alpha
)
*
this
.
_bpm
+
_alpha
*
_bpm
).
toInt
();
});
}
await
Future
.
delayed
(
Duration
(
milliseconds:
1000
*
_windowLen
~/
_fs
));
// wait for a new set of _data values
}
}
}
lib/pages/mask_detect/invoker.dart
View file @
727ddf92
...
...
@@ -7,44 +7,37 @@ import 'cameara_service.dart';
class
invoker
extends
StatelessWidget
{
@override
Widget
build
(
BuildContext
context
)
{
return
Scaffold
(
appBar:
AppBar
(
title:
Text
(
'Face Mask Detector'
),
),
body:
Column
(
children:
[
Padding
(
padding:
const
EdgeInsets
.
all
(
8.0
),
child:
Image
.
asset
(
'lib/assets/images/wear.gif'
),
return
Scaffold
(
appBar:
AppBar
(
title:
Text
(
'Face Mask Detector'
),
),
SizedBox
(
height:
20
),
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
ElevatedButton
(
onPressed:
()=>
invokeCamera
(),
child:
Text
(
'Detect Mask'
),
),
],
),
],
),
);
body:
Column
(
children:
[
Padding
(
padding:
const
EdgeInsets
.
all
(
8.0
),
child:
Image
.
asset
(
'lib/assets/images/wear.gif'
),
),
SizedBox
(
height:
20
),
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
ElevatedButton
(
onPressed:
()
=>
invokeCamera
(),
child:
Text
(
'Detect Mask'
),
),
],
),
],
),
);
}
Future
<
void
>
invokeCamera
()
async
{
WidgetsFlutterBinding
.
ensureInitialized
();
print
(
await
Tflite
.
loadModel
(
model:
'lib/assets/model.tflite'
,
labels:
"lib/assets/labels.txt"
));
runApp
(
MaskDetectingApp
(
cameras:
await
availableCameras
(),
));
WidgetsFlutterBinding
.
ensureInitialized
();
print
(
await
Tflite
.
loadModel
(
model:
'lib/assets/model.tflite'
,
labels:
"lib/assets/labels.txt"
));
runApp
(
MaskDetectingApp
(
cameras:
await
availableCameras
(),
));
}
}
pubspec.yaml
View file @
727ddf92
...
...
@@ -24,7 +24,7 @@ dependencies:
flutter
:
sdk
:
flutter
flutter_svg
:
^0.22.0
camera
:
^0.5.8+8
#
camera: ^0.5.8+8
tflite
:
^1.1.1
oktoast
:
^2.3.2
...
...
@@ -34,6 +34,14 @@ dependencies:
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons
:
^1.0.2
#add dependencies for heart rate module
charts_flutter
:
^0.9.0
wakelock
:
^0.1.4+1
camera
:
git
:
url
:
http://github.com/indikaNK/plugins.git
path
:
packages/camera/camera
dev_dependencies
:
flutter_test
:
sdk
:
flutter
...
...
@@ -51,6 +59,7 @@ flutter:
assets
:
-
lib/assets/images/top_header.jpg
-
lib/assets/images/hero.gif
-
lib/assets/images/mino.jpg
-
lib/assets/images/boralu.jpg
-
lib/assets/images/map80.png
...
...
@@ -59,7 +68,7 @@ flutter:
-
lib/assets/images/coach80.png
-
lib/assets/images/time80.png
-
lib/assets/images/event80.png
-
lib/assets/images/
-
lib/assets/images/
pulse.gif
-
lib/assets/model.tflite
-
lib/assets/labels.txt
-
assets/
...
...
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