Lecciones aprendidas de Manejo Al Hombro

24 de mayo de 2017

#.Update (24/05/2017)

Voy a presentar en Datos y Pintas este 1 de junio a las 7:00 p.m. acerca de la apertura de Datos de @ManejoAlHombro, sería genial si les interesa llegar a escuchar sobre los datos y conocimiento que estamos abriendo para el uso de las autoridades (o interesados).

Ver evento en Eventbrite

Igualmente les sugiero que vean el sitio web de ManejoAlHombro.


Hace ya dos meses les comenté sobre un caso particular sobre un invento hecho durante un fin de semana llamado “Manejo Al Hombro”. En este post les comenté una prueba de concepto que pretendía desarrollar una aplicación que permitiese al ciudadano denunciar públicamente hechos del tránsito, especialmente a los conductores que utilizan ilegalmente el hombro.

Después de estos dos meses, en los que incluso aparecimos en Televisión, la aplicación ya se encuentra pública en Android y iOS y tenemos más de 500 denuncias reportadas en tan solo dos meses, todas públicas, sin embargo hay algunas cosas que quisiera compartir con ustedes acerca de la experiencia y el proceso que fue llegar desde esa prueba de concepto hasta una aplicación real.

#.Lección 1 - Cambio de Tecnologías

Primero, la prueba de concepto fue desarrollada utilizando Sinatra y Titanium. Sobre el transcurso, decidí cambiarlo a un stack de Padrino y React Native, por múltiples razones.

Cambié de Sinatra a Padrino mayormente porque me percaté que estaba rehaciendo todo lo que Padrino ya ofrecía internamente y con soporte externo. No valía la pena seguir desarrollando algo que ya existiese. Podría haber utilizado Rails, igualmente, pero mi intención es mantener el codebase lo más simple y sencillo posible.

Cambié de Titanium a React Native porque me topé con un problema en Titanium a nivel del último SDK. Noté que la comunidad de Titanium está casi muerta (mayormente debido a sus cambios de licenciamiento, los cuales volvieron a cambiar a gratuito hace poco), luego de esperar por varios días una respuesta. Una pena. El cambio a React Native fue sencillo, en unos días tenía lo mismo que la prueba conceptual, pero en React Native.

Fig 0. Manejo Al Hombro desde iPhone

Titanium y React Native (RN) tienen enfoques un poco distintos. Titanium está enfocado en desarrollar sobre un único código fuente (tanto la parte visual como la parte funcional, salvo algunos casos), RN está enfocado en permitir el desarrollo de aplicaciones paralelas utilizando una única tecnología. Es decir, aún si podemos reutilizar algunos componentes visuales, los procesos o acciones suelen diferir de la tecnología.

Hice otros cambios a nivel de las tecnologías bases:

  • Cambiamos de DataMapper a ActiveRecord, el primero parece un proyecto muerto sinceramente.
  • Cambiamos de mis propios componentes visuales a utilizar NativeBase, la verdad no tenía tiempo ni intención de ponerme a jugar con los componentes.
  • Implementamos Redis para el caché y cola antes de inserción de la data.
  • Implementamos RabbitMQ como sistema de Mensajería / Queues.
  • Toda la data se procesa en servidores paralelos (Viva Docker) en forma bastante rápida.
  • Todos los assets, fotografías, reportes, etc. se almacenan automáticamente en Amazon S3.
  • Las fotografías son comprimidas y procesadas ligeramente para que pesen menos y tengan un tamaño estándar. Para esto usamos ImageMagick.
  • Hay un proceso completo de Continuous Delivery, tanto para los servicios como para los apps. Para los apps implementamos Fastlane, una joya.
  • A nivel de seguridad, se hicieron varios ajustes necesarios. Los servicios están protegidos con SSL y requieren una sesión (datos intercambiados mediante JWT).

#.Lección 2 - Enseñarle al lector (OCR) y detector (haciendo Machine Learning)

Como les comenté en el otro post, OpenALRP ya posee una buena base con la que podemos desarrollar un detector y lector de placas, aprovechando que la composición físca de la placa es similar a la placa de Estados Unidos o de México.

Recuerden que la intención es que la persona no tenga que teclear la placa del infractor, para ello implementamos el sistema que fuese totalmente autónomo.

Inicialmente todo anduvo bien, pero noté algunos problemas con algunos caracteres o letras. Hablando con el buen compañero Juan Merlos, mejor conocido como @merlos de Panatrans, me comentó que el había iniciado el proceso de tomar las fotografías para entrenar el detector y el lector, pero que nunca se había decidido hacerlo. Juan fue muy diligente y nos proveyó cientos de fotografías de placas ya cortadas para poder entrenar al detector y al lector (mil gracias Juan, me ahorraste decenas de horas).

Con estas fotografías pude hacer el entrenamiento del lector, utilizando Tesseract y casi un día completo entrenando el lector caracter por caracter de las más de 1,000 placas.

El proceso, descrito en la documentación de OpenALPR es similar al siguiente:

  1. Cargas una placa y la pasas por el lector.
  2. El lector te arroja el resultado que el leyó.
  3. Vas caracter por caracter indicándole si el resultado que leyó es el correcto. Si no lo es, le indicas el caracter correcto.

El entrenamiento del lector arroja un “mapa” de caracteres que van a ser utilizados por el lector la próxima vez que le toque leer la placa. Este mapa se utiliza para volver a leer las placas y a compararlas con todas las placas que ya fueron leídas y las compara con el resultado que se les indicó.

Fig 1. Mapa de Caracteres luego de entrenar al OCR (lector)

Luego de varias pasadas del entrenamiento pude pasar de un 83% de confianza a un 95% de confianza. En algunos casos, el lector detecta erradamente algunos caracteres que no existen (por ejemplo cuando la placa tiene algún cuadro protector) o algunas letras las detecta erradamente. Esto era común con algunas letras recurrentemente (como la A y el número 4), lo que se solventó luego del entrenamiento del lector.

El detector no necesité entrenarlo, gracias a que la placa es similar en forma a la placa de Estados Unidos (12”x6” y mismos tamaños en las letras, separación y bordes).

Tal como lo prometí desde un principio, todo el código de entrenamiento del OCR (lector) y el resultado fue liberado en GitHub y está disponible para cualquier persona que quiera implementar un lector similar en sus propios proyectos.

#.Lección 3 - No todas las fotos son iguales

Esta lección hizo que tuvieramos que invertir un par de semanas en pruebas. Voy a plantearles el problema con fotografías para que sea más fácil de explicar.

¿Qué notan de diferente entre estas dos fotografías de autos?

Fig 2. Fotografía desde costado del vehículo
Fig 3. Fotografía desde atrás del vehículo

Si notan, la Fig. 2 está tomada con el auto casi de forma paralela al vehículo que conduce, mientras la Fig. 3 está tomada desde atrás de un vehículo.

Esto es un problema, ya que la placa entre más cerca / paralela esté al auto que conduce, más se deforma y menos parece un rectángulo y más similar a un romboide. El problema no solo está para detectar la placa, sino que entre más romboide sea la fotografía más complicado es detectar correctamente las letras (ya que las mismas también se deforman).

OpenALPR está diseñado para una cámara estática o en una única posición, algo que no nos funcionaría para nuestro trabajo. Esto lo detectamos luego de un par de pruebas en la calle.

Para solventar esto hicimos un trabajo simple, utilizando nuevamente una recomendación en la documentación de OpenALPR. Realizamos distintas configuraciones de ángulos que nos permitiese hacer un skew a la fotografía y transformar el romboide a un rectángulo.

Eso permite que una fotografía como esta:

Original

Pase por distintas configuraciones que la conviertan a algo similar a esto:

Distorsionada

Notamos que ahora parece más un rectángulo y por ende es más probable la detección. El sistema ahora pasa la fotografía por múltiples configuraciones y detecta la configuración que de el mejor resultado. En el caso anterior, el sistema pasó de no detectar ninguna placa a detectar una placa con 85% de confianza.

#.Lección 4 - Sigue siendo una máquina

Este es quizás el punto más importante. Aún luego de tantas características y trabajos extras que desarrollamos hemos aprendido algunas cosas muy interesantes en cuanto al desarrollo de este proyecto tan interesante.

Una de estas cosas es que el sistema sigue siendo una máquina y aunque hagamos tantas mejoras en el sistemas para mejorar los resultados, hay ocasiones en el que el sistema puede equivocarse. Gracias a los trabajos, los resultados errados se redujeron notablemente.

Hay ocasiones en los que incluso a simple vista es difícil leer la fotografía (por ejemplo hay casos donde las placas tienen una lámina protectora oscura) y el sistema lo detectó sin problema, mientras hay casos donde ocurre todo lo contrario: pareciese que fuese fácil de leer y aún así el sistema no lo lee o no lo detecta.

Entre más fotografías se introducen al sistema, el sistema sigue aprendiendo más, ya que estamos utilizando las fotografías y los errores para seguir mejorando el lector y el detector.

#.Funcionalidades extras creadas

Esta es mi parte favorita. Manejo Al Hombro viene con varias mejoras desde aquella versión piloto, algunas mencionadas en la Lección 1 (Tecnologías):

  1. Agregamos distintos tipos de reportes, no solo el manejo al hombro.
  2. Liberamos estadísticas y Datos de los infractores, con intención de mejorar la generación de conocimiento a través de estos datos.
  3. La aplicación ya está disponible en Android y iOS y hemos recibido más de 500 reportes en estos meses de prueba y producción. ¡Descárguenla y úsenla!
  4. Se hizo integración con Twitter (únicamente por ahora) y se menciona al Tránsito.
  5. Hay un módulo de administración completo por detrás. Las fotografías son moderadas con una integración que hicimos en Pixmat con Slack. Siempre que llega un reporte el mismo nos envía una solicitud para publicarlo a Slack y ahí decidimos si lo queremos o no publicar.
  6. Guardamos la ubicación (GPS) de los reportes, siempre y cuando se envíe el mismo.
  7. Mejoramos nuestro stack de tecnología haciéndolo mucho más rápido y eficiente.

#.Pendientes

Nos quedan varias funcionalidades pendientes en la aplicación móvil que prefiero no mencionarlas en este post y dejarlas como sorpresa a futuro para las próximas versiones.

A nivel del portal, vamos a seguir mejorando también los datos que estamos abriendo para su consumo y la parte de las estadísticas. Por ejemplo, me gustaría poder tener estas mismas estadísticas filtradas (quizás por tipo y hora).

Me gustaría obviamente saber un poco lo que opinan sobre esta aplicación y que ideas tienen. Al final, es un proyecto comunitario y cívico y la aplicación es lo que es gracias a sus usuarios.