OpenCV Python: ¿solución rápida para la lectura de imágenes float32 de 3 canales?

Necesito imágenes en color ordenadas por RBG de 3 canales de tipo float32 con sus valores en el intervalo [0.0, 1.0] para cada canal de color.

Esta es mi solución actual:

 def read_images(imagelist): buffer = list() for f in imagelist: # load single image, convert to float32 img = cv2.imread(f).astype(np.float32) # change interval from [0, 255] to [0.0, 1.0] img /= 255.0 # leave out alpha channel, if any if img.shape[2] == 4: img = img[:, :, 0:3] buffer.append(img) return np.array(buffer) 

Luego, en un controlador de imágenes, cambio BGR a RGB (porque el cv2 de imread lee las imágenes en orden BGR de forma predeterminada).

Este procedimiento consume bastante tiempo para conjuntos de imágenes grandes: estoy cargando miles de imágenes para el preprocesamiento y luego alimento las imágenes a algunas redes neuronales implementadas en TensorFlow.

¿Hay alguna manera de mejorar el rendimiento de este enfoque?

Con este enfoque, es probable que no haya mucho que pueda hacer para acelerar la lectura de su imagen. Pensé que tal vez Matplotlib sería más rápido, ya que se lee directamente como flotante y en orden RGB, pero es tres veces más lento que OpenCV, incluso después de convertir el tipo y el orden de los canales. PIL es un poco más rápido que Matplotlib, pero sigue siendo el doble de lento que OpenCV, por lo que no ayuda, y scikit-image es aproximadamente la misma velocidad que PIL:

 import matplotlib.image as mpimg import cv2 import numpy as np from skimage import io from PIL import Image import timeit times = range(1000) # matplotlib start_time = timeit.default_timer() for t in times: img = mpimg.imread('img1.png') print("mpimg.imread(): ", timeit.default_timer() - start_time, "s") # OpenCV start_time = timeit.default_timer() for t in times: img = cv2.cvtColor( cv2.imread('img1.png'), cv2.COLOR_BGR2RGB).astype(np.float32)/255.0 print("cv2.imread(): ", timeit.default_timer() - start_time, "s") # scikit-image start_time = timeit.default_timer() for t in times: img = io.imread('img1.png').astype(np.float32)/255.0 print("io.imread(): ", timeit.default_timer() - start_time, "s") # PIL start_time = timeit.default_timer() for t in times: img = np.asarray(Image.open('img1.png')).astype(np.float32)/255.0 print("Image.open(): ", timeit.default_timer() - start_time, "s") 

mpimg.imread (): 37.68960806101677 s
cv2.imread (): 13.830177563999314 s
io.imread (): 29.395271296001738 s
Image.open (): 26.633562815986807 s

En su lugar, podría ser mejor preprocesar leyendo todas las imágenes y guardándolas en un mejor formato para leerlas (es decir, leyendo directamente de bytes) en lugar de usar lectores de imágenes. Puede serializar (pickle) sus imágenes en archivos .p o .pickle , y luego cargar los datos directamente en una lista. De esa manera solo tienes que hacer la carga lenta una vez y solo una vez. Como señala Dan Mašek a continuación en los comentarios, decapar tus archivos significa descomprimirlos en datos sin procesar, por lo que los tamaños de los archivos serán mucho más grandes. Puede crear su misma lista que tiene ahora (su búfer) con el tipo correcto y el orden de los canales, y luego seleccionar la lista; cuando llega el momento de entrenar puede cargar el archivo de pickle; Es mucho más rápido, y super simple:

 with open(training_file, mode='rb') as f: training_data = pickle.load(f)