На недавнем собрании компании поднималась проблема сортировки мусора. В то время как все соглашались с необходимостью надлежащей переработки, существовала проблема с классификацией того, какой мусор должен попадать в какой мусорный бак. Например, искусственная упаковка горячих блюд из ресторанов на вынос может сбивать с толку. Здесь могут помочь компьютерное зрение и машинное обучение. В этой статье мы рассмотрим, как использовать библиотеку React Native для создания приложения для распознавания мусора, которое может классифицировать различные типы отходов и продвигать надлежащую переработку.

Начиная

Следующее руководство подготовлено для людей, имеющих хотя бы минимальный опыт работы с React Native. Если вы только начинаете свое приключение по написанию мобильных приложений на этом фреймворке, пожалуйста, ознакомьтесь с инструкцией по подготовке среды, прежде чем создавать собственное приложение.

Первым шагом в подготовке нашего приложения будет создание пустого проекта React Native с изящным названием: Office Cleaner. Для этого выполните в терминале следующую команду:

npx react-native@latest init OfficeCleaner

Как только у нас будет готова рабочая среда, мы можем приступить к установке необходимых зависимостей. Что нам абсолютно необходимо, так это библиотека для использования камеры устройства, куда мы установим наше приложение. Камера React Native Vision — лучший выбор для этого. Для этого переходим в директорию нашего проекта и выполняем команды:

npm install --save react-native-vision-camera
npx pod-install # to install CocoaPods for iOS app 

Теперь мы можем перейти к кодированию! Откройте файл App.tsx и реализуйте использование камеры, как показано ниже:

import React from 'react';
import { StyleSheet } from 'react-native';
import { Camera, useCameraDevices } from 'react-native-vision-camera';

export default function App() {
  const devices = useCameraDevices('wide-angle-camera');
  const device = devices.back;

  return (
    <Camera
      style={StyleSheet.absoluteFill}
      device={device}
      isActive={true}
    />
  );
}

…и готово! Мы только что подготовили приложение, которое отображает предварительный просмотр в реальном времени с камеры вашего смартфона! Теперь перейдем к созданию модели обнаружения объектов!

Если вы запустите свое приложение в этот момент, вы, вероятно, ничего не увидите из-за разрешений приложения на доступ к камере. Я намеренно пропустил эту часть, чтобы не растягивать статью до бесконечности. Если вы не знаете, как получить разрешения для своего приложения, обратитесь к документации react-native-permission library.

Построение модели TensorFlow Lite

Для классификации элемента нам понадобится модель TensorFlow Lite. Существует множество предварительно обученных моделей для разных типов объектов, и вы также можете обучать свои собственные модели. Для этого примера создадим предварительно обученную модель, которая может классифицировать бумагу, пластик, стекло и металл. Нам понадобится еще один тип данных (назовем его просто trash) для элементов, которые не соответствуют ни одному из вышеперечисленных критериев.

Создать набор данных

Первым шагом будет создание набора данных для обучения нашей модели. Для этого мы должны собрать как можно больше изображений (в формате JPG) объектов, которые мы хотим распознать. Важно, чтобы на фотографиях эти объекты были показаны с разных ракурсов и при разном освещении, чтобы мы могли лучше распознать наши объекты. Мы ограничим наш набор данных мусором, который чаще всего встречается в офисных помещениях (таким как стеклянные и пластиковые бутылки, банки, пищевая упаковка, кусочки бумаги и пищевые отходы).

Если у нас уже есть готовые фотографии, пришло время их пометить. Для этого мы будем использовать инструмент labelImg. Точную инструкцию по установке для вашей операционной системы вы можете найти здесь. Если вы готовы, просто откройте конец инструмента, выполнив следующие шаги:

  1. Нажмите Открыть каталог и выберите каталог с набором ваших изображений. Если вы выбрали правильный каталог, список ваших файлов будет виден в правом нижнем углу программы.
  2. Нажмите Изменить каталог сохранения и выберите каталог, в котором будут храниться файлы аннотаций.
  3. Убедитесь, что выбран формат PascalVOC.
  4. Нажмите Создать RectBox и пометьте объекты на фотографии. После перетаскивания формы вы увидите окно с пробелом для описания объекта. Вы можете создавать ярлыки по своему вкусу, но не забывайте использовать одни и те же ярлыки для описания одинаковых предметов.

После пометки всех ваших изображений файловая структура должна выглядеть примерно так:

|-- dataset
    |-- images
        |-- image_0001.jpg
        |-- image_0001.jpg
        |-- image_0001.jpg
        ...
        |-- image_0971.jpg
    |-- annotations
        |-- image_0001.xml
        |-- image_0001.xml
        |-- image_0001.xml
        ...
        |-- image_0971.xml

Переобучить модель обнаружения объектов с помощью TensorFlow Lite Model Maker

Теперь, когда у нас подготовлен набор данных, пришло время создать модель TensorFlow Lite. Запакуйте папку набора данных в архив, а затем следуйте инструкциям, которые я подготовил специально для вас в Google Colab. Таким образом, вам не нужно (но можно) устанавливать всю среду и все зависимости на свой компьютер. Пройдя все пошаговые инструкции, вы должны получить файл с расширением .tflite. Это наш файл модели, который мы будем использовать в качестве источника для правильного обнаружения объектов в нашем приложении.

Создание приложения для распознавания мусора

Когда у нас есть модель, мы можем использовать нативную библиотеку react, чтобы загрузить модель и выполнить обнаружение объектов в результатах камеры. Библиотека вернет список объектов, обнаруженных на изображении, вместе с их показателями достоверности. Затем мы можем использовать эту информацию для классификации отходов и отображения соответствующей мусорной корзины.

Установить зависимости

Вернитесь в наш репозиторий кода и в терминале введите команду:

npm install --save vision-camera-realtime-object-detection react-native-reanimated
npx pod-install # to install CocoaPods for iOS app

Первая из этих библиотек используется для обнаружения объектов с использованием модели TensorFlow Lite. По сути, это мост между уровнем JS приложения и собственным использованием библиотек TensorFlow Lite Task Vision для iOS и Android. Вторая библиотека — известная библиотека для использования анимаций. Но нам понадобятся не анимации, а особый их функционал, а именно — Worklets. С их помощью мы можем перемещать небольшие части кода JavaScript непосредственно в поток пользовательского интерфейса и, таким образом, достигать нативной производительности без единой строки нативного кода. Но вернемся к настройке нашего приложения. К основному файлуindex.js в нашем репозитории добавим импорт в самом верху:

import 'react-native-reanimated'

и добавьте плагин в свой babel.config.js

module.exports = {
  plugins: [
    [
      'react-native-reanimated/plugin',
      {
        globals: ['__detectObjects'],
      },
    ]
    // ...

Стоит отметить, что вы должны перезапустить metro-bundler, чтобы изменения в файле babel.config.js вступили в силу.

Ссылка на файл модели

Чтобы добавить модель TensorFlow Lite в свое приложение, скопируйте файл efficientdet-waste-model.tflite в каталог asset/model

...
|-- assets
    |-- images
    |-- fonts
    |-- model
        |-- efficientdet-waste-model.tflite
|-- src
    |-- App.tsx
...

и свяжите его как с Android, так и с iOS командой:

npx react-native-asset

Реализовать решение

Теперь, когда все готово, мы можем перейти к реализации нашей задачи. Во-первых, давайте объявим и используем Frame Processor для обнаружения объектов в нашем App.tsx:

const windowDimensions = useWindowDimensions();
const [objects, setObjects] = useState<DetectedObject[]>([]);

const frameProcessorConfig: FrameProcessorConfig = {
  modelFile: 'efficientdet-waste-model.tflite'
};

const frameProcessor = useFrameProcessor((frame) => {
  'worklet';

  const detectedObjects = detectObjects(frame, frameProcessorConfig);
      runOnJS(setObjects)(
        detectedObjects.map((obj) => ({
          ...obj,
          top: obj.top * windowDimensions.height,
          left: obj.left * windowDimensions.width,
          width: obj.width * windowDimensions.width,
          height: obj.height * windowDimensions.height,
        }))
      );
}, []);

return (
    <View style={StyleSheet.absoluteFill}>
      <Camera
        frameProcessorFps={5}
        frameProcessor={frameProcessor}
        style={{ flex: 1, width: "100% }}
        device={device}
        isActive={true}
      />
      {objects?.map(
        (
          { top, left, width, height, labels }: DetectedObject,
          index: number
        ) => (
          <View
            key={`${index}`}
            style={[styles.detectionFrame, { top, left, width, height }]}
          >
            <Text style={styles.detectionFrameLabel}>
              {labels
                .map((label) => `${label.label} (${label.confidence})`)
                .join(',')}
            </Text>
          </View>
        )
      )}
    </View>
);

Стоит отметить, что DetectionObject возвращает положение и размер кадра относительно размера полученного изображения (например, значение top:0.25 означает, что кадр обнаруженного объекта начинается с четверти высоты изображения) , чтобы было легко вычислить, где рендерить кадр в приложении. В нашем случае это было тривиально из-за того, что изображение, испускаемое камерой, занимает всю площадь экрана, поэтому мы могли использовать размеры окна.

Второе, что стоит отметить, это то, что мы не можем выполнять все действия в UI-потоке с помощью Worklets. Пример тому — изменение состояния компонента, где нам на помощь приходит функция runOnJS из библиотеки react-native-reanimated.

И последнее, но не менее важное — это объект конфигурации нашего процессора кадров. В коде его не видно, но мы можем передать в нем больше информации, чем имя нашей модели. Мы можем контролировать минимально допустимую точность или количество потоков, используемых для обнаружения объектов, но я оставлю вам возможность проверить, как это работает! Вы можете найти документацию библиотеки здесь.

Заключение

Создание приложения для распознавания мусора с использованием React Native и TensorFlow Lite Vision — отличный способ способствовать надлежащей переработке и сокращению отходов. С помощью машинного обучения мы можем классифицировать различные виды отходов и предоставлять информацию о том, как правильно их перерабатывать. Нативная библиотека react позволяет легко интегрировать обнаружение объектов в ваше приложение, а возможности безграничны.