Phát hiện đối tượng với Android

Hướng dẫn này chỉ cho bạn cách xây dựng một ứng dụng Android bằng TensorFlow Lite để liên tục phát hiện các đối tượng trong khung được camera của thiết bị chụp. Ứng dụng này được thiết kế cho một thiết bị Android vật lý. Nếu bạn đang cập nhật một dự án hiện có, bạn có thể sử dụng mẫu mã làm tài liệu tham khảo và bỏ qua phần hướng dẫn sửa đổi dự án của mình .

Bản demo hoạt hình phát hiện đối tượng

Tổng quan về phát hiện đối tượng

Phát hiện đối tượng là nhiệm vụ học máy nhằm xác định sự hiện diện và vị trí của nhiều lớp đối tượng trong một hình ảnh. Một mô hình phát hiện đối tượng được huấn luyện trên tập dữ liệu chứa một tập hợp các đối tượng đã biết.

Mô hình được đào tạo nhận các khung hình ảnh làm đầu vào và cố gắng phân loại các mục trong hình ảnh từ tập hợp các lớp đã biết mà nó được đào tạo để nhận dạng. Đối với mỗi khung hình, mô hình phát hiện đối tượng đưa ra danh sách các đối tượng mà nó phát hiện được, vị trí của hộp giới hạn cho từng đối tượng và điểm cho biết độ tin cậy của đối tượng được phân loại chính xác.

Mô hình và tập dữ liệu

Hướng dẫn này sử dụng các mô hình đã được đào tạo bằng bộ dữ liệu COCO . COCO là bộ dữ liệu phát hiện đối tượng quy mô lớn chứa 330K hình ảnh, 1,5 triệu phiên bản đối tượng và 80 danh mục đối tượng.

Bạn có tùy chọn sử dụng một trong các mô hình được đào tạo trước sau:

  • Hiệu quảDet-Lite0 [Được khuyến nghị] - một mô hình phát hiện đối tượng nhẹ với trình trích xuất tính năng BiFPN, bộ dự đoán hộp dùng chung và mất tiêu cự. MAP (Độ chính xác trung bình trung bình) cho tập dữ liệu xác thực COCO 2017 là 25,69%.

  • Hiệu quảDet-Lite1 - mô hình phát hiện đối tượng Hiệu quảDet cỡ trung bình. MAP cho tập dữ liệu xác thực COCO 2017 là 30,55%.

  • Hiệu quảDet-Lite2 - mô hình phát hiện đối tượng Hiệu quảDet lớn hơn. MAP cho tập dữ liệu xác thực COCO 2017 là 33,97%.

  • MobileNetV1-SSD - một mẫu cực kỳ nhẹ được tối ưu hóa để hoạt động với TensorFlow Lite nhằm phát hiện đối tượng. MAP cho tập dữ liệu xác thực COCO 2017 là 21%.

Đối với hướng dẫn này, mô hình EfficiencyDet-Lite0 tạo ra sự cân bằng tốt giữa kích thước và độ chính xác.

Việc tải xuống, trích xuất và đặt các mô hình vào thư mục nội dung được quản lý tự động bởi tệp download.gradle , tệp này chạy trong thời gian xây dựng. Bạn không cần phải tải các mô hình TFLite vào dự án theo cách thủ công.

Ví dụ thiết lập và chạy

Để thiết lập ứng dụng phát hiện đối tượng, hãy tải mẫu xuống từ GitHub và chạy nó bằng Android Studio . Các phần sau của hướng dẫn này khám phá các phần có liên quan của ví dụ về mã để bạn có thể áp dụng chúng cho ứng dụng Android của riêng mình.

Yêu cầu hệ thống

  • Android Studio phiên bản 2021.1.1 (Bumblebee) trở lên.
  • SDK Android phiên bản 31 trở lên
  • Thiết bị Android có phiên bản hệ điều hành tối thiểu là SDK 24 (Android 7.0 - Nougat) đã bật chế độ nhà phát triển.

Lấy mã ví dụ

Tạo một bản sao cục bộ của mã ví dụ. Bạn sẽ sử dụng mã này để tạo một dự án trong Android Studio và chạy ứng dụng mẫu.

Để sao chép và thiết lập mã ví dụ:

  1. Sao chép kho git
    git clone https://github.com/tensorflow/examples.git
    
  2. Bạn có thể tùy ý định cấu hình phiên bản git của mình để sử dụng tính năng kiểm tra thưa thớt, để bạn chỉ có các tệp cho ứng dụng ví dụ phát hiện đối tượng:
    cd examples
    git sparse-checkout init --cone
    git sparse-checkout set lite/examples/object_detection/android
    

Nhập và chạy dự án

Tạo một dự án từ mã ví dụ đã tải xuống, xây dựng dự án rồi chạy nó.

Để nhập và xây dựng dự án mã ví dụ:

  1. Khởi động Android Studio .
  2. Từ Android Studio, chọn Tệp > Mới > Nhập dự án .
  3. Điều hướng đến thư mục mã ví dụ chứa tệp build.gradle ( .../examples/lite/examples/object_detection/android/build.gradle ) và chọn thư mục đó.
  4. Nếu Android Studio yêu cầu Đồng bộ hóa Gradle, hãy chọn OK.
  5. Đảm bảo rằng thiết bị Android của bạn được kết nối với máy tính và chế độ nhà phát triển được bật. Nhấp vào mũi Run màu xanh lá cây.

Nếu bạn chọn đúng thư mục, Android Studio sẽ tạo một dự án mới và xây dựng nó. Quá trình này có thể mất vài phút, tùy thuộc vào tốc độ máy tính của bạn và liệu bạn có sử dụng Android Studio cho các dự án khác hay không. Khi quá trình xây dựng hoàn tất, Android Studio sẽ hiển thị thông báo BUILD SUCCESSFUL trong bảng trạng thái Build Output .

Tùy chọn: Để sửa lỗi xây dựng bằng cách cập nhật phiên bản plugin Android:

  1. Mở tệp build.gradle trong thư mục dự án.
  2. Thay đổi phiên bản công cụ Android như sau:

    // from: classpath
    'com.android.tools.build:gradle:4.2.2'
    // to: classpath
    'com.android.tools.build:gradle:4.1.2'
    
  3. Đồng bộ hóa dự án bằng cách chọn: File > Sync Project with Gradle Files .

Để chạy dự án:

  1. Từ Android Studio, chạy dự án bằng cách chọn Run > Run… .
  2. Chọn một thiết bị Android được đính kèm có camera để kiểm tra ứng dụng.

Các phần tiếp theo cho bạn thấy những sửa đổi mà bạn cần thực hiện đối với dự án hiện tại của mình để thêm chức năng này vào ứng dụng của riêng bạn, sử dụng ứng dụng mẫu này làm điểm tham chiếu.

Thêm phụ thuộc dự án

Trong ứng dụng của riêng mình, bạn phải thêm các phần phụ thuộc dự án cụ thể để chạy các mô hình máy học TensorFlow Lite và truy cập các chức năng tiện ích giúp chuyển đổi dữ liệu như hình ảnh thành định dạng dữ liệu tensor mà mô hình bạn đang sử dụng có thể xử lý.

Ứng dụng ví dụ sử dụng thư viện TensorFlow Lite Task cho tầm nhìn để cho phép thực thi mô hình học máy phát hiện đối tượng. Hướng dẫn sau đây giải thích cách thêm các phần phụ thuộc thư viện bắt buộc vào dự án ứng dụng Android của riêng bạn.

Hướng dẫn sau đây giải thích cách thêm các phần phụ thuộc mô-đun và dự án bắt buộc vào dự án ứng dụng Android của riêng bạn.

Để thêm phụ thuộc mô-đun:

  1. Trong mô-đun sử dụng TensorFlow Lite, hãy cập nhật tệp build.gradle của mô-đun để bao gồm các phần phụ thuộc sau. Trong mã ví dụ, tệp này nằm ở đây: ...examples/lite/examples/object_detection/android/app/build.gradle ( code reference )

    dependencies {
      ...
      implementation 'org.tensorflow:tensorflow-lite-task-vision:0.4.0'
      // Import the GPU delegate plugin Library for GPU inference
      implementation 'org.tensorflow:tensorflow-lite-gpu-delegate-plugin:0.4.0'
      implementation 'org.tensorflow:tensorflow-lite-gpu:2.9.0'
    }
    

    Dự án phải bao gồm thư viện tác vụ Vision ( tensorflow-lite-task-vision ). Thư viện bộ xử lý đồ họa (GPU) ( tensorflow-lite-gpu-delegate-plugin ) cung cấp cơ sở hạ tầng để chạy ứng dụng trên GPU và Delegate ( tensorflow-lite-gpu ) cung cấp danh sách tương thích.

  2. Trong Android Studio, đồng bộ hóa các phần phụ thuộc của dự án bằng cách chọn: File > Sync Project with Gradle Files .

Khởi tạo mô hình ML

Trong ứng dụng Android, bạn phải khởi tạo mô hình học máy TensorFlow Lite với các tham số trước khi chạy dự đoán bằng mô hình. Các tham số khởi tạo này nhất quán trên các mô hình phát hiện đối tượng và có thể bao gồm các cài đặt như ngưỡng độ chính xác tối thiểu để dự đoán.

Mô hình TensorFlow Lite bao gồm tệp .tflite chứa mã mô hình và thường bao gồm tệp nhãn chứa tên của các lớp được mô hình dự đoán. Trong trường hợp phát hiện đối tượng, các lớp là các đối tượng như người, chó, mèo hoặc ô tô.

Ví dụ này tải xuống một số mô hình được chỉ định trong download_models.gradle và lớp ObjectDetectorHelper cung cấp bộ chọn cho các mô hình:

val modelName =
  when (currentModel) {
    MODEL_MOBILENETV1 -> "mobilenetv1.tflite"
    MODEL_EFFICIENTDETV0 -> "efficientdet-lite0.tflite"
    MODEL_EFFICIENTDETV1 -> "efficientdet-lite1.tflite"
    MODEL_EFFICIENTDETV2 -> "efficientdet-lite2.tflite"
    else -> "mobilenetv1.tflite"
  }

Để khởi tạo mô hình trong ứng dụng của bạn:

  1. Thêm tệp mô hình .tflite vào thư mục src/main/assets của dự án phát triển của bạn, chẳng hạn như: EfficiencyDet-Lite0 .
  2. Đặt biến tĩnh cho tên tệp mô hình của bạn. Trong ứng dụng ví dụ, bạn đặt biến modelName thành MODEL_EFFICIENTDETV0 để sử dụng mô hình phát hiện EfficiencyDet-Lite0.
  3. Đặt các tùy chọn cho mô hình, chẳng hạn như ngưỡng dự đoán, kích thước tập hợp kết quả và tùy chọn, đại biểu tăng tốc phần cứng:

    val optionsBuilder =
      ObjectDetector.ObjectDetectorOptions.builder()
        .setScoreThreshold(threshold)
        .setMaxResults(maxResults)
    
  4. Sử dụng các cài đặt từ đối tượng này để xây dựng đối tượng TensorFlow Lite ObjectDetector có chứa mô hình:

    objectDetector =
      ObjectDetector.createFromFileAndOptions(
        context, modelName, optionsBuilder.build())
    

setupObjectDetector thiết lập các tham số mô hình sau:

  • Ngưỡng phát hiện
  • Số lượng kết quả phát hiện tối đa
  • Số luồng xử lý sẽ sử dụng ( BaseOptions.builder().setNumThreads(numThreads) )
  • Mô hình thực tế ( modelName )
  • Đối tượng ObjectDetector ( objectDetector )

Cấu hình bộ tăng tốc phần cứng

Khi khởi tạo mô hình TensorFlow Lite trong ứng dụng của mình, bạn có thể sử dụng các tính năng tăng tốc phần cứng để tăng tốc độ tính toán dự đoán của mô hình.

Các đại biểu TensorFlow Lite là các mô-đun phần mềm giúp tăng tốc việc thực thi các mô hình học máy bằng cách sử dụng phần cứng xử lý chuyên dụng trên thiết bị di động, chẳng hạn như Bộ xử lý đồ họa (GPU), Bộ xử lý Tensor (TPU) và Bộ xử lý tín hiệu số (DSP). Nên sử dụng đại biểu để chạy các mô hình TensorFlow Lite nhưng không bắt buộc.

Trình phát hiện đối tượng được khởi tạo bằng cách sử dụng các cài đặt hiện tại trên luồng đang sử dụng nó. Bạn có thể sử dụng ủy quyền CPU và NNAPI với các trình phát hiện được tạo trên luồng chính và được sử dụng trên luồng nền, nhưng luồng khởi tạo trình phát hiện phải sử dụng đại biểu GPU.

Các đại biểu được đặt trong hàm ObjectDetectionHelper.setupObjectDetector() :

when (currentDelegate) {
    DELEGATE_CPU -> {
        // Default
    }
    DELEGATE_GPU -> {
        if (CompatibilityList().isDelegateSupportedOnThisDevice) {
            baseOptionsBuilder.useGpu()
        } else {
            objectDetectorListener?.onError("GPU is not supported on this device")
        }
    }
    DELEGATE_NNAPI -> {
        baseOptionsBuilder.useNnapi()
    }
}

Để biết thêm thông tin về cách sử dụng đại biểu tăng tốc phần cứng với TensorFlow Lite, hãy xem Đại biểu TensorFlow Lite .

Chuẩn bị dữ liệu cho mô hình

Trong ứng dụng Android, mã của bạn cung cấp dữ liệu cho mô hình để diễn giải bằng cách chuyển đổi dữ liệu hiện có như khung hình ảnh thành định dạng dữ liệu Tensor mà mô hình của bạn có thể xử lý. Dữ liệu trong Tensor mà bạn truyền vào mô hình phải có kích thước hoặc hình dạng cụ thể phù hợp với định dạng dữ liệu được sử dụng để huấn luyện mô hình.

Mô hình EfficiencyDet-Lite0 được sử dụng trong ví dụ mã này chấp nhận Tensors biểu thị hình ảnh có kích thước 320 x 320, với ba kênh (đỏ, xanh dương và xanh lục) trên mỗi pixel. Mỗi giá trị trong tensor là một byte đơn trong khoảng từ 0 đến 255. Vì vậy, để chạy dự đoán trên hình ảnh mới, ứng dụng của bạn phải chuyển đổi dữ liệu hình ảnh đó thành đối tượng dữ liệu Tensor có kích thước và hình dạng đó. API tầm nhìn thư viện tác vụ TensorFlow Lite xử lý việc chuyển đổi dữ liệu cho bạn.

Ứng dụng sử dụng đối tượng ImageAnalysis để lấy hình ảnh từ máy ảnh. Đối tượng này gọi hàm detectObject bằng bitmap từ máy ảnh. Dữ liệu được ImageProcessor tự động thay đổi kích thước và xoay để đáp ứng yêu cầu dữ liệu hình ảnh của mô hình. Hình ảnh sau đó được dịch sang một đối tượng TensorImage .

Để chuẩn bị dữ liệu từ hệ thống con máy ảnh để mô hình ML xử lý:

  1. Xây dựng đối tượng ImageAnalysis để trích xuất hình ảnh theo định dạng được yêu cầu:

    imageAnalyzer =
        ImageAnalysis.Builder()
            .setTargetAspectRatio(AspectRatio.RATIO_4_3)
            .setTargetRotation(fragmentCameraBinding.viewFinder.display.rotation)
            .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
            .setOutputImageFormat(OUTPUT_IMAGE_FORMAT_RGBA_8888)
            .build()
            ...
    
  2. Kết nối máy phân tích với hệ thống con camera và tạo bộ đệm bitmap để chứa dữ liệu nhận được từ camera:

    .also {
      it.setAnalyzer(cameraExecutor) {
        image -> if (!::bitmapBuffer.isInitialized)
        { bitmapBuffer = Bitmap.createBitmap( image.width, image.height,
        Bitmap.Config.ARGB_8888 ) } detectObjects(image)
        }
      }
    
  3. Trích xuất dữ liệu hình ảnh cụ thể mà mô hình cần và chuyển thông tin xoay hình ảnh:

    private fun detectObjects(image: ImageProxy) {
      //Copy out RGB bits to the shared bitmap buffer
      image.use {bitmapBuffer.copyPixelsFromBuffer(image.planes[0].buffer) }
        val imageRotation = image.imageInfo.rotationDegrees
        objectDetectorHelper.detect(bitmapBuffer, imageRotation)
      }
    
  4. Hoàn thành mọi chuyển đổi dữ liệu cuối cùng và thêm dữ liệu hình ảnh vào đối tượng TensorImage , như được hiển thị trong phương thức ObjectDetectorHelper.detect() của ứng dụng ví dụ:

    val imageProcessor = ImageProcessor.Builder().add(Rot90Op(-imageRotation / 90)).build()
    // Preprocess the image and convert it into a TensorImage for detection.
    val tensorImage = imageProcessor.process(TensorImage.fromBitmap(image))
    

Chạy dự đoán

Trong ứng dụng Android, sau khi tạo đối tượng TensorImage với dữ liệu hình ảnh ở định dạng chính xác, bạn có thể chạy mô hình dựa trên dữ liệu đó để đưa ra dự đoán hoặc suy luận .

Trong lớp fragments/CameraFragment.kt của ứng dụng ví dụ, đối tượng imageAnalyzer trong hàm bindCameraUseCases sẽ tự động chuyển dữ liệu đến mô hình để dự đoán khi ứng dụng được kết nối với máy ảnh.

Ứng dụng sử dụng phương thức cameraProvider.bindToLifecycle() để xử lý bộ chọn camera, cửa sổ xem trước và xử lý mô hình ML. Lớp ObjectDetectorHelper.kt xử lý việc truyền dữ liệu hình ảnh vào mô hình. Để chạy mô hình và tạo dự đoán từ dữ liệu hình ảnh:

  • Chạy dự đoán bằng cách chuyển dữ liệu hình ảnh đến chức năng dự đoán của bạn:

    val results = objectDetector?.detect(tensorImage)
    

Đối tượng TensorFlow Lite Interpreter nhận dữ liệu này, chạy nó dựa trên mô hình và tạo ra danh sách dự đoán. Để mô hình xử lý dữ liệu liên tục, hãy sử dụng phương thức runForMultipleInputsOutputs() để hệ thống không tạo và xóa các đối tượng Phiên dịch sau mỗi lần chạy dự đoán.

Xử lý đầu ra mô hình

Trong ứng dụng Android của bạn, sau khi bạn chạy dữ liệu hình ảnh dựa trên mô hình phát hiện đối tượng, nó sẽ tạo ra một danh sách dự đoán mà mã ứng dụng của bạn phải xử lý bằng cách thực thi logic nghiệp vụ bổ sung, hiển thị kết quả cho người dùng hoặc thực hiện các hành động khác.

Đầu ra của bất kỳ mô hình TensorFlow Lite nhất định nào đều khác nhau về số lượng dự đoán mà nó tạo ra (một hoặc nhiều) và thông tin mô tả cho mỗi dự đoán. Trong trường hợp mô hình phát hiện đối tượng, các dự đoán thường bao gồm dữ liệu cho hộp giới hạn cho biết vị trí phát hiện đối tượng trong ảnh. Trong mã ví dụ, kết quả được chuyển đến hàm onResults trong CameraFragment.kt , hàm này hoạt động như một DetectorListener trong quá trình phát hiện đối tượng.

interface DetectorListener {
  fun onError(error: String)
  fun onResults(
    results: MutableList<Detection>?,
    inferenceTime: Long,
    imageHeight: Int,
    imageWidth: Int
  )
}

Đối với mô hình được sử dụng trong ví dụ này, mỗi dự đoán bao gồm vị trí hộp giới hạn cho đối tượng, nhãn cho đối tượng và điểm dự đoán trong khoảng từ 0 đến 1 dưới dạng Float thể hiện độ tin cậy của dự đoán, với 1 là xếp hạng độ tin cậy cao nhất . Nói chung, những dự đoán có số điểm dưới 50% (0,5) được coi là không thuyết phục. Tuy nhiên, cách bạn xử lý các kết quả dự đoán có giá trị thấp tùy thuộc vào bạn và nhu cầu của ứng dụng của bạn.

Để xử lý kết quả dự đoán mô hình:

  1. Sử dụng mẫu trình nghe để chuyển kết quả tới mã ứng dụng hoặc đối tượng giao diện người dùng của bạn. Ứng dụng ví dụ sử dụng mẫu này để chuyển kết quả phát hiện từ đối tượng ObjectDetectorHelper sang đối tượng CameraFragment :

    objectDetectorListener.onResults(
    // instance of CameraFragment
        results,
        inferenceTime,
        tensorImage.height,
        tensorImage.width)
    
  2. Hành động dựa trên kết quả, chẳng hạn như hiển thị dự đoán cho người dùng. Ví dụ vẽ một lớp phủ trên đối tượng CameraPreview để hiển thị kết quả:

    override fun onResults(
      results: MutableList<Detection>?,
      inferenceTime: Long,
      imageHeight: Int,
      imageWidth: Int
    ) {
        activity?.runOnUiThread {
            fragmentCameraBinding.bottomSheetLayout.inferenceTimeVal.text =
                String.format("%d ms", inferenceTime)
    
            // Pass necessary information to OverlayView for drawing on the canvas
            fragmentCameraBinding.overlay.setResults(
                results ?: LinkedList<Detection>(),
                imageHeight,
                imageWidth
            )
    
            // Force a redraw
            fragmentCameraBinding.overlay.invalidate()
        }
    }
    

Sau khi mô hình trả về kết quả dự đoán, ứng dụng của bạn có thể hành động theo dự đoán đó bằng cách hiển thị kết quả cho người dùng hoặc thực thi logic bổ sung. Trong trường hợp mã ví dụ, ứng dụng sẽ vẽ một khung giới hạn xung quanh đối tượng được xác định và hiển thị tên lớp trên màn hình.

Bước tiếp theo