2010-09-15 16 views
8

Tengo una aplicación donde necesito tomar la intensidad promedio de una imagen para alrededor de 1 millón de imágenes. Se "siente" como un trabajo para un sombreador de fragmentos de GPU, pero los sombreadores de fragmentos son para cálculos locales por píxel, mientras que el promedio de imágenes es una operación global.Sumas de intensidades de imagen en GPU

Un enfoque que consideré es cargar la imagen en una textura, aplicar una imagen borrosa de 2x2, cargar el resultado en una textura N/2 x N/2 y repetir hasta que la salida sea 1x1. Sin embargo, esto tomaría aplicaciones log del shader.

¿Hay alguna forma de hacerlo en una sola pasada? ¿O debería simplemente descomponer y usar CUDA/OpenCL?

+0

Mi aplicación realiza la coincidencia de chaflán de un modelo 3D proyectado a una imagen de entrada. Represento una imagen que contiene los bordes de la silueta de mi modelo, y para cada píxel de borde, utilizo una tabla de búsqueda para encontrar el píxel de borde más cercano en la imagen de entrada. Entonces necesito el resultado promedio, lo que me dice que el modelo se ajusta a los datos. Intenté leer los píxeles del borde renderizado de opengl y hacer coincidir el chaflán en la CPU, pero la operación de lectura fue un gran cuello de botella.Esperaba que al hacer todo el trabajo en la GPU y leer solo en un solo valor, obtuviera una gran aceleración. –

+0

(ctd) Dado que puedo pasar la tabla de búsqueda como una textura, puedo hacer las búsquedas en un sombreador de vértices, pero todavía tengo el cuello de botella de leer los datos nuevamente en la memoria principal. –

+0

Nada te obliga a desenfocar 2x2, podrías hacer, por ejemplo, desenfocar con una caja de 16x16 y luego cargar el resultado en una textura de N/16 x N/16. De esa forma puede lograr grandes operaciones de aceleración y menos copia ... –

Respuesta

4

La operación de suma es un caso específico de la "reducción", una operación estándar en las bibliotecas CUDA y OpenCL. Un bonito escrito sobre él está disponible en el cuda demos page. En CUDA, Thrust y CUDPP son solo dos ejemplos de bibliotecas que ofrecen reducción. Estoy menos familiarizado con OpenCL, pero CLPP parece ser una buena biblioteca que proporciona reducción. Simplemente copie su búfer de color en un objeto de búfer de píxeles de OpenGL y use la llamada de interoperabilidad de OpenGL apropiada para hacer que la memoria del búfer de píxeles sea accesible en CUDA/OpenCL.

Si se debe hacer utilizando la API opengl (como se requería la pregunta original), la solución es representar una textura, crear un mapa de mip de la textura y leer en la textura de 1x1. Tienes que configurar el filtrado correcto (el bilineal es apropiado, creo), pero debería acercarse a la respuesta correcta, error de precisión del módulo.

1

Mi instinto me dice que intente su implementación en OpenCL. Puede optimizar su tamaño de imagen y hardware de gráficos dividiendo las imágenes en trozos de datos personalizados que luego se suman en paralelo. Podría ser muy rápido de hecho.

Los sombreadores de fragmentos son excelentes para las circunvoluciones, pero ese resultado generalmente se escribe en el gl_FragColor por lo que tiene sentido. En última instancia, tendrá que recorrer cada píxel de la textura y sumar el resultado que luego se leerá en el programa principal. Generar estadísticas de imágenes quizás no sea para lo que se diseñó el sombreador de fragmentos y no está claro que se obtenga una ganancia de rendimiento importante ya que no se garantiza que un búfer en particular esté ubicado en la memoria de la GPU.

Parece que puede estar aplicando este algoritmo a un escenario de detección de movimiento en tiempo real, o alguna otra aplicación de detección automática de funciones. Puede ser más rápido calcular algunas estadísticas de una muestra de píxeles en lugar de la imagen completa y luego crear un clasificador de aprendizaje automático.

¡La mejor de las suertes para usted en cualquier caso!

+0

Gracias por su respuesta. Analizaré OpenCL. –

1

No necesita CUDA si desea ceñirse a GLSL. Al igual que en la solución CUDA que se menciona aquí, se puede hacer en un fragmento shader staight hacia adelante. Sin embargo, necesita llamadas de sorteo de registro (resolución). Simplemente configure un sombreador que tome muestras de 2x2 píxeles de la imagen original y obtenga la suma promedio de esas. El resultado es una imagen con media resolución en ambos ejes. Repite eso hasta que la imagen sea de 1x1 px. Algunas consideraciones: Use GL_FLOAT texturas de luminancia si están disponibles, para obtener una suma más precisa. Use glViewport para dividir el área de representación en cada etapa. El resultado termina en el píxel superior izquierdo de tu framebuffer.

Cuestiones relacionadas