Skip to content

En el presente repositorio se encuentra el proceso de desarrollo, en fase de prueba de concepto, de un sistema de monitoreo de rapidez y obtención de matrículas de automóviles, dicho proceso se detalla en forma secuencial. Adicional se incluyen los documentos durante el desarrollo y los enlaces a las herramientas necesarias para la elaboración d…

Notifications You must be signed in to change notification settings

DiegoBran16/JetsonNano-Cloud-Edge-Car-speed-plate-monitoring

Repository files navigation

JetsonNano-Cloud-Edge-Car-speed-plate-monitoring

Universidad Rafaél Landívar

Ingeniería Electrónica y Telecomunicaciones

Trabajo de Graduación

En el presente repositorio se encuentra el proceso de desarrollo de un sistema de monitoreo de rapidez y obtención de matrículas de automóviles, dicho proceso se detalla en forma secuencial. Adicional se incluyen los documentos durante el desarrollo y los enlaces a las herramientas necesarias para la elaboración del mismo.

De forma general el sistema detecta automóviles que se mueven en un área delimitada, al mismo se le realiza un seguimiento y se asigna un identificador, luego se obtiene la rapidez que posee en un punto específico, y se captura una imagen del automóvil, tanto el identificador, la rapidez y la imagen del automóvil son enviados a los servicios de Amazon Web Services en donde se abstrae de la imagen los valores de la matrícula y junto al identificador y la rapidez se almacenan en una base de datos. Si el automóvil supera un límite de rapidez establecido se notifica por correo electrónico al infractor.

video.mp4

Las fases para desarrollo del sistema son:

  1. Instalación componentes Hardware complementarios a Jetson Nano
  2. Configuraciones iniciales en la Jetson Nano
  3. Entrenamiento de una red neuronal convolucional profunda
  4. Registro de Jetson Nano en AWS
  5. Configuración de servicios a utilizar en AWS
  6. Elaboración de archivos Car2.py y my-detection3.py
  7. Elaboración de función en servicio Lamnda para integración de servicios de AWS

Intalación componentes Hardware complementarios a Jetson Nano

La primer fase del desarrollo se relaciona con la conexión de los componentes de Hardware auxiliares a la tarjeta Jetson Nano. Estos componentes son:

  • Tarjeta de red
  • Antenas
  • Ventilador

A continuación se detallan los pasos para conectar estos componentes en la tarjeta:

Conexión Tarjeta de Red

PASO 1: Desatornillar los dos tornillos en el disipador de calor y removerlo

image

PASO 2: Conectar el cable de extensión al Wireless-AC8265 en el conector IPEX, apretar la tuerta y la arandela a cada conector SMA

image

PASO 3: Desatornillar el tornillo NIC en el centro

image

PASO 4: Insertar el Wireless-AC8265 en la cuenca M.2 y atornillar nuevamente el tornillo NIC

image

PASO 5: Atornillar nuevamente el disipador de calor

image

Conexión Antenas

PASO 1: Conectar las antenas en el conector IPEX

image

Conexión Ventilador

PASO 1: Conectar el ventilador a la tarjeta Jetson Nano en el puerto correspondiente

image

PASO 2: Atornillar las cuatro esquinas del ventilador

image

Configuraciones iniciales en Jetson Nano

Al finalizar las conexiones Hardware descritas anteriormente,en la segunda fase del desarrollo se monta el JetPack en la Jetson Nano y se realizan sus configuraciones iniciales. Las secciones que incluyen esta fase son:

  • Descarga de JetPack y configuración inicial Ubuntu
  • Configuración ventilador
  • Descarga y configuración contenedor dusty-nv/jetson-inference/
  • Configuración Memoria Swap
  • Instalación Visual Studio Code

Descarga de JetPack y configuración inicial Ubuntu

PASO 1: De la página de NVIDIA se descarga la versión del JetPack compatible con la Jetson Nano; en este caso se descargó la versión 4.6.1. Para la descarga se utilizó el siguiente enlace -->NVIDIA Getting Started with Jetson Nano Developer Kit. Al terminar la descarga se obtiene el siguiente archivo:

jetsonnanoiso

PASO 2: Se descarga el Software Balena Etcher, este se utiliza para montar el JetPack en una tarjeta microSD con un mín de 32 GB. El Software se puede descargar desde aquí

Al abrir el programa se muestra el siguiente menu:

BalenaEtcher01

PASO 3: Se selecciona la opción "Flash from file", y se busca el archivo que se descargó en el paso 2

BalenaEtcher02

PASO 4: Se inserta la tarjeta microSD en la ranura de la computadora y se selecciona en el menú de Balena Etcher la opción "Select Target". Se selecciona la tarjeta microSD y se hace click en "Flash" para montar el JetPack.

BalenaEtcher04

PASO 4.1 Si el paso 4 se esta realizando en Windows aparecerá un mensaje la siguiente notificación de la cual se selecciona "Cancelar"

image

Paso 5: Se conecta la Jetson Nano a corriente con un cable de alimentación que entrega 5V y 4A, adicional se conecta un monitor por medio de display port, y un teclado y mouse a los puertos USB. Finalmente se inserta la tarjeta microSD al puerto corresepondiente.

image image

PASO 6: Al encender por primera vez la tarjeta Jetson Nano, el sistema operativo solicita la configuración inicial tipica de Ubuntu como la zona horaria, el usuario y la contraseña. El usuario establecido fue "tesis"

Configuración Ventilador

PASO 1: Instalar python3-dev en la tarjeta Jetson Nano

apt install python3-dev

PASO 2: Diriguirse al directorio Descargas

cd Descargas

PASO 3: Clonar el repositorio Pyrestone/jetson-fan-ctl-git para la instalación del control automático del ventilador

git clone https://github.com/Pyrestone/jetson-fan-ctl.git

PASO 4: Acceder a directorio jetson-fan-ctl

cd jetson-fan-ctl

PASO 5: Ejecutar archivo install.sh

./install.sh

Descarga y configuración del contenedor dusty-nv/jetson-inference/

A continuación se realiza el setup del contenedor de Docker.

PASO 1: Clonar el repositorio de GitHub dusty-nv/jetson-inference

git clone --recursive https://github.com/dusty-nv/jetson-inference/

PASO 2: Ingresar al directorio jetson-inference

cd jetson-inference/

PASO 3: Iniciar el contenedor

docker/run.sh

PASO 4: Al correr por primera vez el archivo run.sh, se inicia la imagen del contenedor desde Docker Hub, y se solicita la instalación de modelos entrenados y Pytorch para Python3. Se presiona la barra espaciadora en la opción de "Aceptar" para la instalación de los modelos seleccionados por default

image

PASO 5: Salir del contenedor al finalizar la instalación de los modelos

exit

PASO 6: En el directorio home crear un archivo Dockerfile que importa toda la configuración del contenedor dusty-nv/jetson-inference/ y librerías adicionales para el sistema como se muestra a continuación:

FROM dustynv/jetson-inference:r32.7.1

ENV LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libgomp.so.1

RUN pip install AWSIoTPythonSDK
RUN pip3 install --upgrade pip
RUN apt-get update
RUN pip install matplotlib
RUN apt-get install -y python3-tk
RUN pip install sklearn

PASO 7: Se construye el contenedor nuevo en el mismo directorio donde se creó el Dockerfile mencionado en el paso 6

sudo docker build-tag docker-jetson

PASO 8: Cambiar a directorio jetson-inference

cd jetson-inference/

PASO 9: Para la creación del directorio para la configuración y almacenamiento de los archivos con el código. Se crea una carpeta en el directorio home con el nombre "my-detection3"

mkdir my-detection3

PASO 10: Ingresar al directorio my-detection3

cd my-detection3

PASO 11: Crear un archivo vacío denominado my-detection3.py que se modificará posteriormente

touch my-detection3.py

PASO 12: Crear un archivo vacío denominado Car2.py que se modificará posteriormente

touch Car2.py

PASO 13: Ingresar al directorio jetson-inference

cd jetson-inference

PASO 14: Correr y montar carpeta my-detection3 en el nuevo contenedor

docker/run.sh -container docker-jetson:latest -volume~/my-detection3:/my-detection3

Configuración memoria swap

PASO 1: En el directorio root@tesis:~# ejecutar el siguiente comando:

sudo systemctl disable nvzramconfig

PASO 2: Ejecutar el comando fallocate -l que permitirá manipular el espacio en disco SD

sudo fallocate -l 4G /mnt/4GB.swap

PASO 3: Correr el comando mkswap

sudo mkswap /mnt/4GB.swap

PASO 4: Correr el comando swapon

sudo swapon /mnt/4GB.swap

PASO 5: Ingresar al directorio root@tesis:/#

PASO 6: Descargar e instalar nano

apt-get install nano

PASO 7: Ingresara al directorio root@tesis:/etc# y modificar el archivo fstab

nano fstab

image

PASO 8: Guardar los cambios del archivo

Instalación Visual Studio Code

Para la escritura y edición del código en Python se instaló Visual Studio Code con los siguientes pasos:

PASO 1: En el directorio tesis@tesis:~$ Descargar información actualizada de paquetes y actualizar dependencias

sudo apt-get update

PASO 2: Dirigirse al directorio Descargas

cd Descargas

PASO 3: Descargar e instalar curl en el sistema, para descarga de archivos

sudo apt-get install curl

PASO 4: Descargar el archivo .deb con el comando curl -L

curl -L tesis@tesis:~/Descargas$ curl -L https://github.com/toolboc/vscode/releases/download/1.32.3/code-oss_1.32.3-arm64.deb -o code-oss_1.32.3-arm64.deb

PASO 5: Realizar la instalación del paquete .deb con el comando dpkg y la letra -i de install

sudo dpkg -i code-oss_1.32.3-arm64.deb

PASO 6: Abrir la aplicación Code OSS desde el buscador de aplicaciones en el escritorio

image

Entrenamiento de una red neuronal convolucional profunda

Para que el sistema cuente con la capacidad de detectar automóviles que se mueven a lo largo de un área delimitada, se implemento en la tajeta Jetson Nano una red neuronal convolucional, la cual fue re-entrenada en una máquina virtual del proveedor de la nube Azure. A continuación se enlistan las etapas:

  • Aprovisionamiento de una máquina virtual en Azure
  • Configuraciones e instalaciones en la máquina virtual
  • Entrenamiento en la máquina virtual
  • Creacción archivo onnx para traslado del modelo entrenado a Jetson Nano

Aprovisionamiento de una máquina virtual en Azure

Para el aprovisionamiento de la máquina virtual se necesita una cuenta de Azure con una suscripción activa, en el desarrollo del sistema se utilizó la versión de prueba que otorga $200.

PASO 1: En el menú de Azure dentro de la categoría "Servicios de Azure" se selecciona "Máquinas Virtuales"

Azure1

PASO 2: Dar click en "Crear"

Azure2

PASO 3: En la pestaña "Aspectos básicos", seleccionar la suscripción correcta y escribir el nombre para el grupo de recursos.

image

PASO 4: En la sección "Detalles de instancia" escribir el Nombre de la máquina virtual, la Región y Zona de disponibilidad.

image

PASO 5: Adicional en la sección "Detalles de instancia" seleccionar Tipo de seguridad, la Imagen, y el Tamaño.

image

PASO 6: En la sección "Cuenta de administrador" se define el Tipo de autenticación, Nombre de usuario y Contraseña.

image

PASO 7: En la sección "Opciones de disco" seleccionar el tipo de disco del sistema operativo.

image

PASO 8: Seleccionar el tamaño de disco.

image

PASO 9: En la sección de "Crear un disco" se define el Nombre, Tipo de origen y Tamaño seleccionado en el paso 8.

image

image

PASO 10: En la sección de "Interfaz de red" se define la Red Virtual, Subred, e IP pública.

image

PASO 11: Finalmente Configurar el grupo de seguridad de red, y la seleccionar la Opción de equilibrio de carga.

image

image

Configuraciones e instalaciones en la máquina virtual

Durante la configuración de la máquina virtual se utilizó una máquina cliente con sistema operativo MacOS. Si se realizara en Windows, se recomienda utilizar PuTTY

PASO 1: Se realizó una conexión por SSH a la máquina virtual por medio de la IP pública. Para ello se introdujo el siguiente comando en la máquina cliente:

ssh [email protected]

Las 'x' deben reemplazarse por la dirección IP pública de la máquina virtual

PASO 2: Por comodidad se optó por instalar una interfaz gráfica para la máquina virtual, esta configuración se detalla a continuación.

      PASO 2.1: Actualizar los repositorios.

      sudo apt-get update

      PASO 2.2 Instalar los componentes de la interfaz gráfica ejecutando los siguientes comandos:

      sudo DEBIAN_FRONTEND=noninteractive apt-get -y install xfce4

      sudo apt install xfce4-session

      PASO 2.3: Configurar los servicios RDP con los siguientes comandos:

      sudo apt-get -y install xrdp

      sudo systemctl enable xrdp

      echo xfce4-session >~/.xsession

      sudo service xrdp restart

      Para ver el estado del servicio se ejecuta el comando sudo service xrdp status y se observa una salida como la siguiente:

Captura de Pantalla 2022-07-19 a la(s) 19 46 07

      PASO 2.4: Por medio de la aplicación Microsoft Remote Desktop se accedió por RDP a la interfaz gráfica de la máquina virtual.

image

      PASO 2.5: Se escribe la IP pública asignada por Azure, y en la sección "User account" se selecciona "Add User Account"

image

      PASO 2.6: Se agrega el usuario de la máquina virtual, la contraseña y un identificador, luego dar click en "Add" para guardar la configuación del usuario

image image

      PASO 2.7: En la pestaña "Display" se selecciona la resolución de la pantalla y la calidad del color. Y dar click en "Add"

image

      PASO 2.8: Finalmente se puede ingresar a la máquina virtual al darle doble click.

image

PASO 3: Se creó una variable de entorno denominada tesisenv con los siguientes comandos:

apt install python3.8-venv

python3 -m venv tesisenv

source tesisenv/bin/activate

image

Dentro de la variable de entorno se realizan las instalación necesarias para el entrenamiento de la red neuronal.

PASO 4: Instalar Python 3.6 con los siguientes comandos:

sudo add-apt-repository ppa:deadsnakes/ppa

sudo apt-get install python3.6

apt install python3-virtualenv

virtualenv --python=/usr/bin/python3.6 /home/tesis/tesisenv/

PASO 5: Clonar el repositorio jetson-inference

git clone --recursive http://github.com/dusty-nv/jetson-inference/

PASO 6: Ingrear al directorio cd jetson-inference/python/training/detection/ssd

PASO 7: Descargar la red Mobilenet V1 SSD que se utiliza como red base

wget https://nvidia.box.com/shared/static/djf5w54rjvpqocsiztzaandq1m3avr7c.pth -O models/mobilenet-v1-ssd-mp-0_675.pth

PASO 8: Instalar los requerimientos del archivo requirements.txt

pip3 install -v -r requirements.txt

PASO 9: Instalar torch

pip3 install torch

PASO 10: Instalar torchvision

pip3 install torchvision

PASO 11: Instalar Open Cv

pip3 install opencv-python

PASO 12: Instalar Nvidia Cuda Toolkit

apt install nvidia-cuda-toolkit

PASO 13: Instalar Nvidia Cuda Toolkit

apt install nvidia-cuda-toolkit

PASO 14: Instalar Nvidia Cuda Toolkit

apt install nvidia-cuda-toolkit

PASO 15: Instalar cvs

pip3 install cvs

PASO 16: Instalar ONNX

pip3 install onnx

PASO 17: Instalar boto3

pip3 install boto3

PASO 18: Montar el disco para el almacenamiento del set de datos que se descargará para el entrenamiento identificando la etiqueta del disco.

lsblk -o NAME, HCTL, SIZE, MOUNTPOINT | grep -i "sd"

PASO 19: Se formatea el disco.

sudo parted /dev/sda --script mklabel gpt mkpart xfspart xfs 0% 100%

PASO 20: Se monta el disco en la carpeta donde se almacena las imágenes del set de datos.

sudo mount /dev/sda1 /home/tesis/jetson-inference/python/training/detection/ssd/data

Entrenamiento en la máquina virtual

PASO 1: Descargar las imágenes utilizadas para el entrenamiento

python3 open_images_downloader.py --max-images=25000 --class-names "Car" --data=data/Cars

PASO 2: Editar el archivo train.py para que escriba un csv con los valores de pérdida de entrenamiento y validación

image

image

image

image

image

image

De las imágenes anteriores se estableció por Default la red Movilenet V1 SSD, se indica la ruta en dónde se almacena la red base, se importa la librería csv, y se incluye las modificaciones necesarias en el código para almacenar los valores de pérdida de entrenamieto y validación en formato csv.

PASO 3: Correr el archivo train_ssd.py indicando el batch-size, los epochs, el nombre de la carpeta donde se almacenaron las imágenes de la clase Car y el directorio en donde se almacenarán los Checkpoints del modelo.

python3 train_ssd.py --data=data/Car --model-dir=models/Car --batch-size=103 --epochs=60

Creacción archivo onnx para traslado del modelo entrenado a Jetson Nano

PASO 1: En el archivo onnx.py comentar la opción .cuda(), ya que la máquina virtual utilizada no cuenta con GPU NVIDIA.

image

PASO 2: Utilizar el archivo onnx.py para convertir de formato Pythorch a ONNX.

python3 onnx_export.py --models-dir=models/Car

PASO 3: Enviar por correo el archivo onnx, y el archivo labels para descargarlo en la Jetson Nano.

Registro de Jetson Nano en AWS

Para otorgar acceso a los servicios de AWS se realizó el registro de la tarjeta Jetson Nano en IoT Core de AWS.

PASO 1: Inicialmente se debe identificar la región con menor latencia para configurar los servicios. Para esto puede utilizarse la siguiente herramienta Click aquí

Captura de Pantalla 2022-07-22 a la(s) 16 46 33 Captura de Pantalla 2022-07-22 a la(s) 16 45 47

En nuestro caso la región con menor latencia fue US East(Ohio)

PASO 2: Ingresar a la consola de Administración de AWS y buscar el servicio IoT Core

Captura de Pantalla 2022-07-22 a la(s) 17 05 18

PASO 3: Expandir la sección "Manage" , dirigirse a "Things" y hacer click en "Create Things"

Captura de Pantalla 2022-07-22 a la(s) 17 07 56

PASO 4: En la siguiente ventana se seleciona el número de cosas a crear y hacer click en "next"

Captura de Pantalla 2022-07-22 a la(s) 17 11 06

PASO 5: Posteriormente tras definir un nombre al objeto que en este caso se tomo como "JetsonNano-S1-1" se debe de crear un "thing type, thing group y un billing group" para identificar el recurso. Como se observa en la imagen.

Captura de Pantalla 2022-07-22 a la(s) 17 16 02

PASO 6: En la sección "Device Shadow" se selecciona la opción "No shadow" y selecciona "Next"

Captura de Pantalla 2022-07-22 a la(s) 17 22 53

PASO 7: En la sección "Configure device certificate-optional" se selecciona "Auto-generate a new certificate (recommended)" y seleccionar "Next"

Captura de Pantalla 2022-07-22 a la(s) 17 29 21

PASO 8: En la sección "Attach policies to certificate-optional" se selecciona "Create a policy" y se escribe la siguiente política

Captura de Pantalla 2022-07-22 a la(s) 17 32 25

Captura de Pantalla 2022-07-22 a la(s) 17 35 31

PASO 9: Se selecciona la política creada en el paso 8 y se selecciona "Create thing"

imagen

PASO 10: Seguidamente se mostrarán los certificados y llaves del objeto, además del certificado raíz de la entidad certificadora de AWS. Deben de descargarse el certificado del dispositivo, el certificado Amazon Root CA 1 y las llaves pública y privada y dar click en done

imagen

PASO 11: Dirigirse a la sección "Secure", luego en la opción "Certificates" hacer click en el certificado y en "Policies" se selecciona la opción "Attach policies" y se selecciona la política.

Captura de Pantalla 2022-07-22 a la(s) 17 58 50

PASO 12: Dirigirse a la opción "setting"s al final del menú lateral y guardar el "Endpoint" del servicio. Este debe ser indicado en el código que se realizará en la tarjeta.

Captura de Pantalla 2022-07-22 a la(s) 18 23 53

PASO 13 Posicionarse en la opción "Things" que se encuentra dento de la sección "All Devices" de la sección "Manage" y seleccionar el objeto que se creó anteriormente

imagen

PASO 14 Dirigirse a la sección "Device Shadows" y seleccionar "Create Shadow"

Screen Shot 2022-07-27 at 19 33 02

PASO 15 Seleccionar la opción "Named Shadow", colocar un identificador para el tema MQTT y hacer click en_"Create"_, posteriormente se observara el prefijo del tema.

imagen imagen

Configuración de servicios en AWS

Los servicios configurados a continuación son los siguientes:

  • IAM
  • S3
  • DynamoDB
  • Lambda
  • Elaboración de Politicas y roles

Configuración de IAM

Este servico se utilizará para crear un grupo el cual poseerá permisos para colocar objetos en un bucket de S3 y se asignará un usuario, el cual se colocará en el código de la Jetson Nano.

PASO 1: En el servicio IAM colocarse en "User Groups", y hacer click en "Create group" y se selecciona "Create Group"

Screen Shot 2022-07-25 at 19 28 23

ACLARACIÓN: De momento no se creará ninguna política, pues es neceario el ARN de S3.

PASO 2: En la sección "Users" seleccionar "Add Users"

Screen Shot 2022-07-25 at 19 45 14

PASO 3: Se define un nombre de usuario y se marca el checkbox "Access Key-Programmatic Access" ya que se colocara en el codígo de la Jetson Nano y hacer click en "Next:Permissions"

Screen Shot 2022-07-25 at 19 47 59

PASO 4: En "Set permissions" seleccionamos "Add user to group", seleccionar el grupo que se creó en el paso 3 y hacer click en "Next"

Screen Shot 2022-07-25 at 19 46 21

PASO 5: En "Add tags" seleccionamos "Next:Review"

Screen Shot 2022-07-25 at 19 54 48

PASO 6: A continuación se mostrará un resumen y se debe hacer click en "Create User", posteriormente saldrá un mensaje de éxito y los detalles del usuario. En este momento se debe descargar el .CSV ya que es el único momento en el cual se pueden descargar las llaves de acceso, después de esta pantalla no es posible observar la llave de acceso privada. Después de descargar el .CSV hacer click en "Close"

Screen Shot 2022-07-25 at 20 05 49

Configuración del Bucket de S3

PASO 1: Dirigirse a el servicio Amazon Simple Storage Service (S3), en la sección "Buckets" seleccionar la opción "Create Bucket"

Screen Shot 2022-07-25 at 20 10 52

PASO 2: Se coloca un identificador para el "Bucket", la región en la que se creará el "Bucket" y en "Obejcts Ownership" marcar "ACLs disabled (recomended)".

Screen Shot 2022-07-25 at 20 14 47

PASO 3: Seleccionar "Block all public access"

Screen Shot 2022-07-25 at 20 20 54

PASO 4: En "Bucket Versioning" y "Default Encryption" se dejan los valores predeterminados y se da click en "Create bucket"

Screen Shot 2022-07-25 at 20 21 37

Configuración de Dynamo DB

En la elaboración de este proyecto se configuraron dos tablas. Estas se describen a continuación:

  • Detected_Cars_DB: En esta tabla se almacena el registro de automóviles. Incluye los campos ID, timestamp, imageName, Multa, Plate y speed
  • CarOwners: En esta tabla se almacenan los datos de los usuarios que poseen veiculos. Se incluyen los campos Matricula, DriversLicence, Email, FirstName, FirstSurname, SecondName y SecondSurname

Configuración de la tabla Detected_Cars_DB

PASO 1: Dirigirse a el servicio DynamoDB en la consola de AWS, ubicarse en "Tables" y hacer click en "Create Table"

imagen

PASO 2: Se colocá un nombre en la tabla, el parámetro para las llaves de partición y de ordenamiento y por último se debe hacer click en "Create Table"

imagen

Configuración de la tabla CarOwners

PASO 1: Dirigirse a el servicio DynamoDB en la consola de AWS, ubicarse en "Tables" y hacer click en "Create Table"

imagen

PASO 2: Se colocá un nombre en la tabla, el parámetro para la llave de partición (Para esta tabla no es necesario crear una llave de ordenamiento) y por último se debe hacer click en "Create Table"

imagen

Configuración de la función lambda

PASO 1: Dirigirse al servicio "AWS Lambda", ubicarse en "Functions" y hacer click en "Create Function"

imagen

PASO 2: Se seleciona la opción "Author from scratch" para crear la función con un pequeño código de ejemplo, seguidamente se coloca el nombre identificador de la función. En "Runtime" se selecciona el lenguaje en el que se programará la función, en este caso fue Python3.9. En "Architecture" se debe marcar la arquitectura de base para la ejecución de la función. En este caso se marcó la opción x86_64. En "Execution role" se inidca el rol de ejecución de la función en caso de ya poseer una política creada, en caso de no poseerla se puede crear una política nueva o crear la función con una política básica. En este caso se marcó la opción "Create a new role with basic Lambda permissions". Por último se debe hacer click en "Create Function"

imagen

PASO 3: Se debe de hacer click en el nombre de la función y posteriormente seleccionar la opción "Add Triger"

imagen

PASO 4: En "Trigger configuration" debemos seleccionar IoT Core como fuente del desencadenador.

imagen

PASO 5: En "IoT type" se selecciona "Custom IoT rule", en "Rule" se marca la opción "Create a new rule", se coloca el nombre de la regla, la descripción y en "Rule query statement" se debe declarar que en cada publicación en el tema creado se invoque a la función.

imagen

Elaboración de Politicas y Roles

Se crearon las políticas para cada uno de los servicios asignando únicamente los permisos necesarios para la interacción entre estos.

Se crearón las siguientes politicas y roles:

  • Política del grupo JetsonNano-car-traffic-accounts
  • Política del Bucket de S3
  • Rol de Lambda

Política del grupo JetsonNano-car-traffic-accounts

PASO 1: Dirigirse al servicio IAM, ubicarse en "Groups" y selecconar el grupo creado anteriormente

Screen Shot 2022-07-29 at 08 19 09

PASO 2: Ubicarse en la pestaña "Permissions", desplegar las opciónes disponibles de "Attach Permissions" y seleccionar la opción "Attach policies"

Screen Shot 2022-07-29 at 08 41 01

PASO 3: Seguidamente hacer click sobre "Create Policy" y se abriara una nueva ventana.

Screen Shot 2022-07-29 at 08 41 22

PASO 4: Seleccionar la pestaña "JSON", escribir la siguiente política y hacer click en "Next:Tags".

Esta política otorga los permisos necesarios para colocar objetos en el bucket. Esto permite que el usuario utilizado en el codigo de borde coloque las imagenes de los automoviles en el bucket.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::carimages-trafic-jetson-nano-4gb"
        }
    ]
}

PASO 5: En "Add Tags" hacer click en "Next:Review"

Screen Shot 2022-07-29 at 09 02 26

PASO 6: Colocar un nombre para la política y hacer click en "Create Policy"

Screen Shot 2022-07-29 at 09 02 47

PASO 7: Regresar a la pestaña de "Attach permission policies to JetsonNano-car-traffic-accounts", seleccionar la política creada y hacer click en "Add Permissions"

Screen Shot 2022-07-29 at 09 11 12

PASO 8: Posteriormente se observará la política asignada en el grupo.

Screen Shot 2022-07-29 at 09 13 22

Política del Bucket de S3

PASO 1: Dirigirse al servicio S3 y en la sección "Buckets" hacer click sobre el bucket que se creó anteriormente

Screen Shot 2022-07-29 at 08 03 29

PASO 2: Ubicarse en la pestaña "Permissions", dirigirse a "Bucket Policy" hacer click en edit

Screen Shot 2022-07-29 at 08 02 51

PASO 3: Se escribe la siguiente politica en el espació correspondiente y se hace click en "Save Changes"

{
    "Version": "2012-10-17",
    "Id": "JetsonBucketPolicy",
    "Statement": [
        {
            "Sid": "JetsonBucketPolicyAllowPutObject",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::556216965853:user/JetsonNano-car-traffic-user-1"
            },
            "Action": [
                "s3:ListBucket",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::carimages-traffic-jetson-nano-4gb/*",
                "arn:aws:s3:::carimages-traffic-jetson-nano-4gb"
            ]
        },
        {
            "Sid": "LamndaAccessForS3",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::556216965853:role/service-role/MQTT-S3getCar-Recognition-Dynamodb-role-12j28le3"
            },
            "Action": "s3:GetObject",
            "Resource": [
                "arn:aws:s3:::carimages-traffic-jetson-nano-4gb/*",
                "arn:aws:s3:::carimages-traffic-jetson-nano-4gb"
            ]
        }
    ]
}

Rol de lambda

PASO 1: Dirigirse a la función lambda creada anteriormente y hacer click en el nombre de la función

Screen Shot 2022-07-28 at 18 15 22

PASO 2: Posteriormente colocarse en la pestaña "configuration", dirigirse a "Permissions" y hacer click en la politica predeterminada

Screen Shot 2022-07-28 at 18 17 15

PASO 3: Se abrirá la configuración del rol y se debe hacer click en "Add Permissions" y posteriormente en "Create inline policy"

Screen Shot 2022-07-28 at 23 11 40

PASO 4: Hacer click en "JSON"

Screen Shot 2022-07-28 at 18 59 53

PASO 5 : En la política del rol se deben colocar los permisos necesarios para que la función pueda apoyarse de los serviciós Rekognition, DynamoDB, y S3. Se autorizarón todas las acciones para el servicio Rekognition, permisos para leer y escribir en la tabla "Detected_Cars_DB", permisos de lectura en la tabla "CarOwners" y permisos para colocar y recuperar objetos del bucket de S3

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "arn:aws:logs:us-east-2:556216965853:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "rekognition:*"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:us-east-2:556216965853:log-group:/aws/lambda/MQTT-S3getCar-Recognition-Dynamodb:*"
            ]
        },
        {
            "Sid": "ListAndDescribe",
            "Effect": "Allow",
            "Action": [
                "dynamodb:List*",
                "dynamodb:DescribeReservedCapacity*",
                "dynamodb:DescribeLimits",
                "dynamodb:DescribeTimeToLive"
            ],
            "Resource": "arn:aws:dynamodb:us-east-2:556216965853:table/Detected-Cars-DB"
        },
        {
            "Sid": "SpecificTable",
            "Effect": "Allow",
            "Action": [
                "dynamodb:BatchGet*",
                "dynamodb:DescribeStream",
                "dynamodb:DescribeTable",
                "dynamodb:Get*",
                "dynamodb:Query",
                "dynamodb:Scan",
                "dynamodb:BatchWrite*",
                "dynamodb:CreateTable",
                "dynamodb:Update*",
                "dynamodb:PutItem"
            ],
            "Resource": "arn:aws:dynamodb:us-east-2:556216965853:table/Detected-Cars-DB"
        },
        {
            "Sid": "SpecificTableRead",
            "Effect": "Allow",
            "Action": [
                "dynamodb:BatchGet*",
                "dynamodb:DescribeStream",
                "dynamodb:DescribeTable",
                "dynamodb:Get*",
                "dynamodb:Query",
                "dynamodb:Scan",
                "dynamodb:BatchWrite*"
            ],
            "Resource": "arn:aws:dynamodb:us-east-2:556216965853:table/CarOwners"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:PutObject",
                "s3:Get*",
                "s3:List*",
                "s3-object-lambda:Get*",
                "s3-object-lambda:List*"
            ],
            "Resource": "arn:aws:s3:::carimages-traffic-jetson-nano-4gb"
        }
    ]
} 

PASO 6: Colocar un nombre de identificación para la política y hacer click en "Create Policy", posteriormente se obserbará la política creada en el rol.

Screen Shot 2022-07-28 at 23 05 05 Screen Shot 2022-07-28 at 23 07 25

Elaboración de archivos Car2.py y my-detection3.py

Car2.py

Durante el desarrollo del sistema fue necesario la elaboración del archivo Car2.py, que permite el seguimiento e identificación de los automóviles que fuesen detectados por la red neuronal convolucional profunda re-entrenada. Dicho archivo contiene las clases Auto y Tracker cuyos diagramas se muestran a continuación:

image image

En la clase Tracker la función "tracking" recibe una lista que contiene los valores x1, y1, x2, y2; estos corresponden a las coordenadas de la detección que devuelve el modelo ya re-entrenado. Con estos valores se calculan las coordenadas del centro del rectángulo de detección aplicando la ecuación del punto medio.

image

A continuación se identifica si el automóvil en el frame actual ya se ha detectado anteriormente. Para ello es necesario evaluar con un if si la distancia euclidianda entre los centros de la detección anterior y la detección actual es mayor a 100 px y si la diferencia de los centros en la coordenada "y" del automóvil detectado actualmente y el automóvil detectado con anteriorirdad es menor a 1/2 de la distancia euclidiana de las esquinas del recuadro que encierra la detección.

Si se cumple la condición se utiliza una variable llamada "validador" a la que se le asigna el valor True, lo cual indica que este ya había sido detectado anteriormente, y por lo tanto se agrega la nueva información de este automóvil utilizando las funciones de la clase Auto: "agreagar_info" para almacenar los nuevos valores de coordenadas de x1,y1,x2,y2 y sus centros; "set_centroides" para agregar los nuevos valores de las coordenadas de centros, adicional en esta función se guarda el tiempo de esta detección en el arreglo "tiempo"; y en la clase Tracker se agregan al diccionario "centorides" los nuevos valores de centros.

Cuando No se cumple la condición, y la variable "validador" se mantiene con su valor original False y la esquina inferior derecha del recuadro de detección (y2) es menor a 300 px, quiere decir que el automóvil detectado en el frame actual es una detección nueva. Por lo tanto es necesario crear un nuevo objeto Auto, al que con las funciones de la clase Auto: "asignar_id" se asigna el identificador correspondiente, "agregar_info" almacena los primeros valores de las coordenadas de los centros y x1, y1, x2, y2; y en la clase Tracker se agrega al diccionario "centorides" los valores de los centros y en el diccionario "autos_detectados" se agrega el Auto que se detectó. Finalmente a la variable "car_id" correspondiente a la identificación del automóvil, se le incrementa a su valor uno, para que la siguiente detección siga la secuencia apropiada.

Dicho proceso se describe gráficamente a continuación:

image

my-detection3.py

Para que la tarjeta Jetson Nano realice la lectura de un video, detecte los automóviles que se mueven en el mismo, obtenga la rapidez aproximada del automóvil y envíe una imagen, su identificador y la rapidez del mismo a los servicios de AWS, son necesarias las funciones dentro del archivo my-detection3.py. Es importante resaltar que al archivo se le importa Car2.py para acceder a sus clases además de importar también distintas librerías que apoyan en el desarrollo del sistema.

Inicialmente es necesario declarar las variables globales utilizadas a lo largo del código, estas incluyen los valores obtenidos del registro de la Jetson Nano en el servicio IoT Core: "ENPOINT", "CLIENT_ID", "PATH_TO_CERTIFICATE", "PATH_TO PRIVATE_KEY", "PATH_TO_AMAZON_ROOT_CA_1" y "TOPIC"; y los valores de las llaves obtenidas en la configuración del servicio S3: "ACCESS_KEY_ID" Y "SECRET_ACCESS_KEY".

Adicional se define la variable que contendrá el modelo "Car2.onnx", es decir el modelo Mobilenet SSD v1 ya re-entrenado en la máquina virtual de Azure, la misma se nombra como "net", y el video que será analizado "cap". Finalmente dos variables auxiliares del proceso del sistema: "sended_id" y "contador_out"

Dentro del archivo, se utiliza un while que realiza la lectura de una grabación en la que transitan seis automóviles. Inicialmente los frames del video son redimensionados, luego se selecciona un área que contendrá solamente la carretera donde transitan los automóviles de la grabación y a la misma se le aplica un filtro con la función bitwise_and de la librería OpenCv. A esta sección de carretera filtrada se le denomina como zona y es esta la cual es ingresada a la red neuronal "net", esta devuelve las esquinas del recuadro que encierran la detección de un automóvil, las cuales como se mencionó con anterioridad son x1, y1, x2, y2, estos valores son guardados en una lista denominada "detect".

Luego se crea un objeto Tracker al cual a su función tracking se le envía la lista "detect", la misma retorna el diccionario autos_detectados y este se asigna a la variable "info_id".

A continuación tras obtener el largo del diccionario "info_id" y la lista "detect", se realiza una validación con un if en el cual si el largo de la lista "detect" es menor a la de "info_id" se obtiene la diferencia de largo entre "info_id" y "detect", y si esta diferencia es mayor a cero se infiere que alguno de los automóviles detectados por "net" ya se encuentra fuera de la zona de análisis de la grabación y por lo tanto se utilizan como apoyo la lista "sended_id" que contiene los identificadores de los automóviles cuyos centros en la coordenada "y" se encuentran entre 310 y 330 px y "contador_out" que se utiliza como índice para ubicarse en la posición del ítem de la lista "sended_id" que se encuentra fuera de la zona de interés.

A continuación se obtiene el identificador, los centros y las coordenadas del recuadro de detección del automóvil dentro el diccionario "info_id" que será eliminado, este se eliminará si la esquina inferior derecha de su recuadro de detección y2 supera el valor de 420 px.

Al automóvil eliminado se le denomina como "auto_out" y sus atributos se almacenan en las variables "centosx", "centrosy", "tiempo_centros", "id_aux", "value_string_time", "value_savepath" y "value_fileimage" y son enviados a la función "grafico_mvra" que funciona como un multiproceso permitiendo que comience a ejecutarse mientras se sigue corriendo el while que realiza la lectura del video.

Si el largo de la lista "detect" es mayor a la de "info_id" se continua con la detección del automóvil colocando sobre el mismo un cuadro delimitador y el identificador del mismo. A continuación se realiza una evaluación con un if, en el cual si el centro en la coordenada y esta entre los valores 310 y 330 px, se agrega el identificador el automóvil en la lista ya mencionada anteriormente "sended_id", luego se recorta la imagen del automóvil haciendo uso de las coordenadas x1,y1,x2,y2 del cuadro delimitador, a continuación se registra la fecha y hora en que se realizó el recorte para complementar el valor del identificador, posteriormente se guarda la imagen en el directorio local imagen_auto y finalmente se ejecuta la función "set_aws_values" para almacenar la fecha, hora, ruta de la imagen y nombre de la imagen en las variables del objeto automóvil.

Cuando se ejecuta el multiproceso, en la función "grafico_mrva" se utiliza la variable arreglo "tiempos_aux" en la cual se almacenan los tiempos correspondientes a los centros en la coordenada "y" de los automóviles detectados. En el sistema los centros en la coordenada "y" represnetan el cambio de la posición del automóvil. Y es con estos valores y su relación con los valores del tiempo, en que se encuentran estas posiciones, que se obtienen dos modelos: Un modelo en forma de recta, y un modelo polinómico de grado dos. Para los modelos se utilizan las funciones poly1d y polyfit de la librería numpy, luego de obtener los modelos estos son derivados con la función deriv(), a continuación con una fucnión denomiada "rcuadrado" se selecciona el modelo con mejor ajuste a los datos de posición vs tiempo del automóvil que se esta analizando, a esta función se le envía los parámetros "tiempos_aux" y la lista de centros en la coordenada y.

Al obtener el modelo que mejor se ajusta a los datos, la derivada del modelo es evaluada en un valor del tiempo en que se encuentre una posición "y" cercana al límite final del área establecida que sea mayor a 280 px. Este resultado tendrá las dimensionales en px/s por lo cual es necesario convertir este valor a una estimación cercana en km/h. Para ello se procedió a centrar la perspectiva sin comprometer las medidas de la imagen original. Como se muestra en la imagen a continuación:

image

De la imagen anterior se marca la medida que se toma de referencia, esta corresponde a un Suzuki Swift, y la medida en pixeles tomada con la aplicación Paint fue de 52 px, dando un factor de conversión 0.266, dicho valor se utiliza para convertir px/s en km/h.

A continuación se procede con ejecutar la función "data_to_aws" en ella se utiliza el protocolo de mensajería MQTT para el envío de los valores de rapidez e identificador del automóvil al servicio de IoT Core de AWS. La función recibe: la variable que contiene el tiempo en que el valor de centro de la coordenada "y" del automóvil supera el valor de 310 px, el identificador, la rapidez obtenida, el directorio local donde esta guardada la imagen del automóvil, y el nombre de la imagen.

En la función se configura el "ENDPOINT", "CLIENT_ID", "PATH_TO_CERTIFICATE", "PATH_TO PRIVATE_KEY", "PATH_TO_AMAZON_ROOT_CA_1", se establece el Timeout de conexión y se configura la cola de publicación sin conexión. Se asigna en la variable "dataidaws" la concatenación del identificador con el tiempo recibido, en la variable "dataspeddaws" se asigna la rapidez del automóvil obtenida, y ambas variables son contenidas en un mensaje con formato json.

A continuación se conecta al cliente y se publica en el "TOPIC" el mensaje en el servicio de AWS IoT Core, tras publicarse se desconecta al cliente y se ejecuta la función "upload_files".

En esta función se recibe el directorio local donde se encuentra la imagen del automóvil, el nombre del bucket (carimages-traffic-jetson-nano-4gb) y el nombre de la imagen. Haciendo uso de la librería boto3, se configura el "ACCESS_KEY_ID" y "SECRET_ACCESS_KEY", luego se accede al directorio donde se encuentra la imagen y se sube al bucket establecido.

Finalmente se ejecuta la función "delete_local_image" que recibe el directorio donde se encuentra la imagen del automóvil y esta es eliminada.

Lo descrito anteriormente se representa gráficamente a continuación:

image image

image image image

Elaboración de función en servicio Lamnda para integración de servicios de AWS

Para la integración de los servicios configurados de AWS, se desarrolló una función en el servicio Lambda, la cual tiene como desencadenador el servicio de AWS IoT Core, lo que indica que cada vez que se publique un mensaje MQTT en el "TOPIC" definido anteriormente, se activarán las funciones dentro de la función lambda denominada "MQTT-S3getCar-Rekognition-DynamoDB".

Esta cuenta con una función "lambda_handler" en la cual se recibe el mensaje en formato json del servicio IoT Core, los valores "IDaws" y "dataspeedaws" que contienen la rapidez y el identificador concatenado del automóvil.

Se ejecuta la función "Sistema_multa" la cual recibe la rapidez del automóvil y en la cual se establece una "rapidez_aceptada" y una variable denominada "multa". A continuación con un evaluador if se evalúa si la rapidez recibida es mayor al valor de "rapidez_aceptada" de ser así la variable "multa" se asigna como un "Sí" de lo contrario se asigna un "no", finalmente se retorna el valor de la rapidez.

A continuación se establece una variable llamada "bucket" que contiene el nombre del bucket configurado en el servicio S3 "carimages-traffic-jetson-nano-4gb" donde se guardan las imágenes de los automóviles detectados y se establece una variable "plateimage" que contiene el valor de "IDaws" con la terminación .jpg. Tanto la variable "plateimage" como "bucket" es enviada a la función "call_rekognition".

En esta función inicialmente se define una variable "plate", luego con la librería boto3 se comunica con el servicio Rekognition para que el mismo obtenga el texto en la imagen del automóvil guardada en el bucket. Tras sustituir cualquier espacio detectado por un guion, se asignan a la variable "plate" los valores detectados y se retornar la variable "plate".

A continuación se ejecuta la función "normalize" que recibe "plate" en la misma se elimina cualquier acentuación que se haya identificado en los caracteres de la detección de texto de Rekognition y se ponen en mayúsculas.

Luego se ejecuta la función "Dynamo_write" que recibe los valores de "IDaws", "dataspeedaws", "plate", y "multa". Esta utiliza la librería boto3 para agregar a la tabla "Detected-Cars-DB" el identificador concatenado de la imagen, el timestamp de la detección del automóvil el cual se obtiene utilizando la función "get_timestamp", la matrícula, la rapidez, el nombre de la imagen y finalmente la indicación de la multa.

En la función "get_timestamp" se recibe como parámetro el identificador del automóvil detectado concatenado, en la función se busca el guión bajo que separa la concatenación y se retorna solamente la parte del timestamp.

Finalmente se ejecuta la función "sendmail" cuando el valor de "multa" sea "Si", esta función recibe la matrícula, el timestamp, y la rapidez. Inicialmente fue neceario acceder con la librería boto3 a la tabla "CarOwners" de la cual se obtuvieron los valores del email, primer nombre y primer apellido del dueño del vehículo al cual se le aplicaría la multa, posteriormente se define una variable denominada "message" con el contenido: 'CIUDADANO ' + str(firstname) + ' ' + str(surname) + ' USTED INCLUMPLIO CON EL LÍMITE DE RAPIDEZ ESTABLECIDO AL MANEJAR A ' + str(speed) + ' KM/H'.

Luego con la librería MIMEMultipart se crea un objeto msg, al cual se le indica el correo emisor, contraseña del correo emisor, asunto del correo y se adjunta el mensaje que llevaría el correo. A continuación con la librería smtplib se crea el objeto "server" y se define el host y puerto que se utiliza (smtp.office365.com y 587).

Finalmente se ingresa al "server" indicando el correo emisor y la contraseña y se envía el correo electrónico al infractor del límite de rapidez.

Lo descrito anteriormente se representa gráficamente a continuación:

image image

Autores:

Sara Elizabeth Castro Arriaga

Diego Fernando Bran Arriola

About

En el presente repositorio se encuentra el proceso de desarrollo, en fase de prueba de concepto, de un sistema de monitoreo de rapidez y obtención de matrículas de automóviles, dicho proceso se detalla en forma secuencial. Adicional se incluyen los documentos durante el desarrollo y los enlaces a las herramientas necesarias para la elaboración d…

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages