Estúpida razón por la cual su astuta aplicación de visión artificial no funciona: orientación en EXIF

Escribí mucho sobre proyectos de visión artificial y aprendizaje automático, como sistemas de reconocimiento de objetos y proyectos de reconocimiento facial . También tengo una biblioteca de reconocimiento facial Python de código abierto que de alguna manera se convirtió en una de las 10 bibliotecas de aprendizaje automático más populares en Github . Todo esto ha llevado a los recién llegados a Python y visión artificial a hacerme muchas preguntas.



Por experiencia, existe un problema técnico específico que con mayor frecuencia confunde a las personas. No, esta no es una pregunta teórica difícil o un problema con las GPU caras. El hecho es que casi todos cargan imágenes rotadas en la memoria, sin siquiera saberlo. Y las computadoras no detectan objetos muy bien ni reconocen caras en imágenes rotadas.

Cómo las cámaras digitales rotan automáticamente las imágenes


Cuando toma una foto, la cámara registra la posición del teléfono, de modo que en otro programa la imagen se mostrará en la orientación correcta:



Pero la cámara en realidad no gira los datos de píxeles dentro del archivo. Dado que los sensores de imagen en las cámaras digitales se leen línea por línea como un flujo continuo de información de píxeles, es más fácil para la cámara almacenar siempre los datos de píxeles en el mismo orden, independientemente de la posición real del teléfono.



Esta es la preocupación del programa para ver: gire correctamente la imagen antes de mostrarla en la pantalla. Junto con los datos de la imagen en sí, la cámara también guarda metadatos: configuraciones de lentes, datos de ubicación y, por supuesto, el ángulo de rotación de la cámara. El espectador debe usar esta información para mostrar correctamente.

El formato de metadatos de imagen más común se llama EXIF (abreviatura de Formato de archivo de imagen intercambiable). Los metadatos EXIF ​​están incrustados en cada archivo jpeg. No puede verlos en la pantalla, pero los lee cualquier programa que sepa dónde buscar.

Aquí están los metadatos EXIF ​​dentro de la imagen JPEG de nuestro ganso desde la herramienta exiftool :



¿Ves el elemento 'Orientación'? Le dice al espectador que antes de mostrar en la pantalla, la imagen debe girarse 90 grados en el sentido de las agujas del reloj. Si el programa se olvida de hacer esto, ¡la imagen estará de su lado!



¿Por qué esto rompe tantas aplicaciones de visión artificial en Python?


Los metadatos EXIF ​​no formaban parte originalmente del formato JPEG. Se introdujeron mucho más tarde, tomando prestada la idea del formato TIFF. Por compatibilidad con versiones anteriores, estos metadatos son opcionales y algunos programas no se molestan en analizarlos.

La mayoría de las bibliotecas de imágenes de Python, como numpy, scipy, TensorFlow, Keras, etc., se consideran herramientas científicas para personas serias que trabajan con conjuntos de datos compartidos. No les importan los problemas a nivel del consumidor , como la rotación automática de imágenes, aunque esto es necesario para casi todas las fotografías del mundo tomadas con cámaras modernas.

Esto significa que cuando procesa una imagen con casi cualquier biblioteca de Python, obtiene los datos de la imagen original sin rotación. ¿Y adivina qué sucede cuando intentas subir una foto de tu lado o boca abajo en el modelo de detección de cara u objeto? El detector no se dispara porque le proporcionó datos incorrectos.

Puede pensar que los problemas surgen solo en los programas para principiantes y estudiantes, ¡pero esto no es así! Incluso la versión demo de la API Vision de Google no maneja correctamente la orientación EXIF:


La API de demostración de Google Vision no sabe cómo rotar imágenes orientadas a retratos tomadas desde un teléfono móvil estándar

Aunque Google Vision reconoce algunos animales de su lado, los marca con la etiqueta común "animal", porque los modelos de visión artificial son mucho más difíciles de reconocer a un ganso de su lado que a un ganso vertical. Aquí está el resultado, si gira la imagen correctamente antes de introducirla en el modelo:



Con la orientación correcta, Google detecta aves con una marca de ganso más específica y un indicador de mayor confianza. Mucho mejor!

Este es un problema súper obvio cuando ve claramente que la imagen está de lado , como en esta demostración. Pero aquí es donde todo se vuelve insidioso, ¡por lo general no lo ves! Todos los programas normales en su computadora mostrarán la imagen en la orientación correcta, y no cómo está realmente almacenada en el disco. Por lo tanto, cuando intente ver una imagen para ver por qué su modelo no funciona, se mostrará correctamente y no comprenderá por qué el modelo no funciona.


Finder en Mac siempre muestra fotos giradas correctamente desde EXIF. No hay forma de ver que la imagen está realmente almacenada de lado

Esto inevitablemente lleva a muchas entradas abiertas en Github: la gente se queja de que los proyectos de código abierto están rotos y los modelos no son muy precisos. Pero el problema es mucho más simple: ¡simplemente envían fotos giradas o invertidas a la entrada!

Corrección


La solución es que cada vez que cargue imágenes en programas de Python, debe verificar los metadatos de orientación EXIF ​​y rotar las imágenes si es necesario. Es bastante fácil de hacer, pero en Internet es sorprendentemente difícil encontrar ejemplos de código que lo hagan bien para todas las orientaciones.

Aquí está el código para cargar cualquier imagen en una matriz numpy con la orientación correcta:

import PIL.Image import PIL.ImageOps import numpy as np def exif_transpose(img): if not img: return img exif_orientation_tag = 274 # Check for EXIF data (only present on some files) if hasattr(img, "_getexif") and isinstance(img._getexif(), dict) and exif_orientation_tag in img._getexif(): exif_data = img._getexif() orientation = exif_data[exif_orientation_tag] # Handle EXIF Orientation if orientation == 1: # Normal image - nothing to do! pass elif orientation == 2: # Mirrored left to right img = img.transpose(PIL.Image.FLIP_LEFT_RIGHT) elif orientation == 3: # Rotated 180 degrees img = img.rotate(180) elif orientation == 4: # Mirrored top to bottom img = img.rotate(180).transpose(PIL.Image.FLIP_LEFT_RIGHT) elif orientation == 5: # Mirrored along top-left diagonal img = img.rotate(-90, expand=True).transpose(PIL.Image.FLIP_LEFT_RIGHT) elif orientation == 6: # Rotated 90 degrees img = img.rotate(-90, expand=True) elif orientation == 7: # Mirrored along top-right diagonal img = img.rotate(90, expand=True).transpose(PIL.Image.FLIP_LEFT_RIGHT) elif orientation == 8: # Rotated 270 degrees img = img.rotate(90, expand=True) return img def load_image_file(file, mode='RGB'): # Load the image with PIL img = PIL.Image.open(file) if hasattr(PIL.ImageOps, 'exif_transpose'): # Very recent versions of PIL can do exit transpose internally img = PIL.ImageOps.exif_transpose(img) else: # Otherwise, do the exif transpose ourselves img = exif_transpose(img) img = img.convert(mode) return np.array(img) 

Desde aquí, puede transferir una matriz de datos de imagen a cualquier biblioteca estándar de visión artificial de Python que espere una matriz de entrada: por ejemplo, Keras o TensorFlow.

Como el problema es omnipresente, publiqué esta función como una biblioteca de pip llamada image_to_numpy . Puede instalarlo de la siguiente manera:

  pip3 install image_to_numpy 

Funciona con cualquier programa de Python, arreglando la carga de imágenes, por ejemplo:

 import matplotlib.pyplot as plt import image_to_numpy # Load your image file img = image_to_numpy.load_image_file("my_file.jpg") # Show it on the screen (or whatever you want to do) plt.imshow(img) plt.show() 

Vea el archivo Léame para más detalles.

¡Disfrútalo!

Source: https://habr.com/ru/post/471112/


All Articles