为了避免不必要地提醒用户,将创建一个应生成警报的对象的白名单。在TensorFlow Lite模型和标签文件旁边,添加了一个名为concerns.txt
的新文件。concerns.txt
的每一行都包含了从labels.txt
复制的一行,这是检测器将发出警报的某个对象的标签。检测器以与加载标签相同的方式加载这些标签。
声音是提醒用户的一种选择。如果设备有立体声扬声器,可以利用它们通过左扬声器、右扬声器或两个扬声器播放声音,以快速指示危险的大致方向。为了实现这一点,制作了三个声音文件,并将它们添加到项目资源中。这些声音文件被放置在app/src/res/raw
文件夹中。声音文件被添加到资源中,以便在代码中引用。定义了一些常量来保存声音文件的ID,以便更容易地引用它们。还需要一个变量来引用MediaPlayer
。MediaPlayer
将负责播放声音。
为了防止在驾驶员没有移动时发送警报,用户必须超过一个最小速度。如果用户的速度低于这个速度,就不会生成声音警报。Android的位置服务以米/秒返回速度。当想到驾驶速度时,更倾向于以公里/小时来思考。为了设置最小速度,定义了一个常量来设置最小公里/小时,另一个常量使用这个第一个常量来表示相同的速度(以米/秒为单位)。
检测器将接收到车辆当前速度的更新。对于用于调试和测试的测试界面,速度将在代码中设置,而不是依赖于车辆的实际移动。
为了不让用户持续收到关于危险的警报,有一个冷却时间,在另一个警报发出之前。当尝试发出警报时,首先检查是否有一个警报还没有过期。如果过期时间还没有过去,那么警报就不会发出。尝试发出警报也会重置冷却时间。
现在,应用程序所需的大部分功能已经到位。最后要添加的几件事是碰撞检测和紧急警报,以及让应用程序使用实时摄像头流而不是用户选择的图像。在本系列的下一篇文章中,将探讨碰撞检测和通知。
if (concernList.size() == 0) {
InputStream concernStream = context.getAssets().open("concerns.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(concernStream));
String line;
while ((line = br.readLine()) != null) {
Log.i(TAG, String.format("Concern: %s", line));
concernList.add(line);
}
}
val MIN_ALERT_KMPH: Float = 10.0f
val MIN_ALERT_MPS: Float = MIN_ALERT_KMPH * 1000.0f / (60.0f * 60.0f)
var coolDownExpiry: Long = 0
val COOL_DOWN_TIME = 10000
fun resetCooldown() {
coolDownExpiry = Date().time + COOL_DOWN_TIME
}
fun hasCooldownExpired(): Boolean {
val now = Date().time
return now > coolDownExpiry
}
fun alert(direction: Int) {
if (hasCooldownExpired() && currentSpeedMPS > MIN_ALERT_MPS) {
when (direction) {
ALARM_CENTER, ALARM_RIGHT, ALARM_LEFT -> {
soundPlayer = MediaPlayer.create(context, direction)
soundPlayer!!.start()
}
}
}
resetCooldown()
}