在Android上将实时摄像头与AI危害检测配合使用

79 篇文章 2 订阅
38 篇文章 1 订阅

目录

设置UI

选择正确的相机

图像捕捉会话

获取速度更新

结论


这是有关如何使用AndroidTensorFlow Lite构建实时危害检测系统的系列文章中的第六篇。在之前的文章中,我们准备了一个受过训练的网络模型供Android使用,创建了一个使用TensorFlow Lite的项目,并为该解决方案开发了其他组件。但是直到现在,静态图像仍在开发中。

在此安装中,我们将从使用静态图像切换为使用摄像机的实时供稿。我们编写的大多数代码都可以正常运行而无需修改。如果您按照前面的文章进行操作,则应该已经为应用程序设置了允许访问摄像机的权限。

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />

设置UI

此部分项目的UI将在Android Studio创建的全屏活动中构建。界面的内容将包含几项。布局上的TextureView显示来自摄像机的视频。InfoOverlayView,是在本系列的上一篇文章中创建的视图,用于在视频供稿顶部渲染亮点。

<androidx.constraintlayout.widget.ConstraintLayout

   android:id="@+id/fullscreen_content"

   android:keepScreenOn="true">
   <TextureView android:id="@+id/camera_preview" />
   <net.j2i.drivinghazards.InfoOverlayView />
</androidx.constraintlayout.widget.ConstraintLayout>

TextureView不会自动显示的视频提要。相反,我们必须编写代码以使用来自摄像机的图像对其进行更新。当TextureView更新时,我们可以检索Bitmap为正在显示的帧,并传递到Detector。当TextureView准备好显示的内容,它通知SurfaceTextureListener。我们进行SurfaceTextureListener选择,然后打开相机。SurfaceTextureListener的界面如下所示。

SurfaceTextureListener {
   fun onSurfaceTextureAvailable(
       surface: SurfaceTexture, width: Int, height: Int
   )

   fun onSurfaceTextureSizeChanged(
       surface: SurfaceTexture, width: Int, height: Int
   )

   override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean

   override fun onSurfaceTextureUpdated(surface: SurfaceTexture)
}

函数onSurfaceTextureAvailableonSurfaceTextureUpdated是最受关注的函数。我们打开相机onSurfaceTextureAvailable并在onSurfaceTextureUpdated中接收更新。

选择正确的相机

onSurfaceTextureAvailable的简化实现中,应用程序获取一列照相机ID,并一次检查一个ID,直到找到不是正面照相机的照相机。对于大多数设备,只有两个摄像头。某些设备支持使用USB将第三个相机连接到手机。如果我们想在支持一台摄像机的设备上使用一台外部摄像机,而忽略内置摄像机,则可以更改选择逻辑以过滤LENS_FACING属性值为LENS_FACING_FRONT的摄像机。该函数openCamera是我们在代码中定义的函数,稍后将详细介绍。

override fun onSurfaceTextureAvailable(
   surface: SurfaceTexture,
   width: Int,
   height: Int
) {
   val cm = getSystemService(CAMERA_SERVICE) as CameraManager
   for (cameraID in cm.cameraIdList) {
      val characteristics = cm.getCameraCharacteristics(cameraID!!)
      if (characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT) {
          continue //Skip front facing camera
      }
      mCameraID = cameraID
      openCamera()
      return
   }
}

openCamera函数中,我们使用CameraManager打开选定的硬件摄像机。用户界面布局中TextViewSurfaceTexture对象被分配了大小。我们还将为预览构建配置,为预览设置宽度、高度和方向。

val manager = getSystemService(CAMERA_SERVICE) as CameraManager
manager.openCamera(mCameraID!!, mCameraStateCallback!!, mBackgroundHandler)
val texture = camera_preview!!.surfaceTexture
texture!!.setDefaultBufferSize(previewSize!!.width, previewSize!!.height)
val previewSurface = Surface(texture)
mPreviewCaptureRequestBuilder =
   mCameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
mPreviewCaptureRequestBuilder!!.set(CaptureRequest.JPEG_ORIENTATION, mCameraOrientation)
mPreviewCaptureRequestBuilder!!.addTarget(previewSurface)

图像捕捉会话

完成配置后,我们可以开始捕获会话。相机将启动,我们将开始从中接收更新的图像帧。

mCameraDevice!!.createCaptureSession(
   Arrays.asList(previewSurface),
   object : CameraCaptureSession.StateCallback() {
       override fun onConfigured(session: CameraCaptureSession) {
           if (mCameraDevice == null) return
           mPreviewCaptureRequest = mPreviewCaptureRequestBuilder!!.build()
           mCameraCaptureSession = session
           mCameraCaptureSession!!.setRepeatingRequest(
                mPreviewCaptureRequest!!,
                mSessionCaptureCallback,
                mBackgroundHandler
           )
       }
   }, null
)

更新的帧将传递回先前声明的SurfaceTextureListener。在它的onSurfceTextureUpdated方法中,仅需几行代码,就可以获取帧的Bitmap。这个BitMap可以被传递给检测器来寻找危险。

覆盖fun onSurfaceTextureUpdatedsurfaceSurfaceTexture{

override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {
   val bitmap = Bitmap.createBitmap(
       camera_preview!!.width,
       camera_preview!!.height,
       Bitmap.Config.ARGB_8888
   )
   camera_preview!!.getBitmap(bitmap)
}

获取速度更新

在本系列的较早部分中,我们提到过,我们不希望检测器在车辆不行驶时检测到危险时发送警报。该Detector实例必须接收当前速度的更新。在以下代码中,声明了一个LocationListener,仅更新检测器的速度。然后,使用位置提供程序来请求将位置更新发送到我们的位置监听器。

fun requestLocation() {
   locationListener = LocationListener { location ->
       detector.currentSpeedMPS = location.speed
   }

   val locationManager = this.getSystemService(LOCATION_SERVICE) as LocationManager
   val provider = locationManager.getProvider(LocationManager.GPS_PROVIDER)
   val criteria = Criteria()
   criteria.accuracy = Criteria.ACCURACY_FINE
   val providerName = locationManager.getBestProvider(criteria, true)
   val isProviderEnabled = locationManager.isProviderEnabled(providerName!!)
   if (isProviderEnabled) locationManager.requestLocationUpdates(
       providerName,
       1000,
       1f,
       locationListener!!
   )
}

结论

有了这个,我们现在有了一个工作中的危险探测器。危险检测器代码的开发工作相对较少。通过扩展检测到的数据集,仍有改进检测器的空间。这样做需要在标记的数据集中添加大量危害的照片(请参阅针对Android训练TensorFlow神经网络”)。

创建此数据集需要更多的工作,因为您必须将照片区域标记为包含感兴趣的对象。您可能通过完成诸如识别所有人行横道、交通信号或道路图片中的其他对象之类的任务而在不知情的情况下为这项工作做出了贡献。完成这些测试有助于构建大量带有标签的数据集,以开发自动驾驶汽车和汽车安全系统。

完成此项目后,您已经构建了一个应用程序,其中包含您在自动驾驶汽车中会发现的一些功能!

https://www.codeproject.com/Articles/5291393/Using-the-Live-Camera-with-AI-Hazard-Detection-on

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值