Суммируйте интенсивности изображения в GPU - PullRequest
8 голосов
/ 16 сентября 2010

У меня есть приложение, в котором мне нужно взять среднюю интенсивность изображения для примерно 1 миллиона изображений. Это «похоже» на работу с фрагментным шейдером GPU, но фрагментные шейдеры предназначены для локальных вычислений на пиксель, в то время как усреднение изображения является глобальной операцией.

Один из подходов, которые я рассмотрел, - это загрузить изображение в текстуру, применив размытость изображения 2x2, загрузить результат обратно в текстуру N / 2 x N / 2 и повторять до тех пор, пока результат не станет 1x1. Однако для этого потребуется зарегистрировать n приложений шейдера.

Есть ли способ сделать это за один проход? Или я должен просто сломаться и использовать CUDA / OpenCL?

Ответы [ 3 ]

4 голосов
/ 20 сентября 2010

Операция суммирования является частным случаем «редукции», стандартной операции в библиотеках CUDA и OpenCL. Хорошая рецензия на него доступна на странице cuda demos . В CUDA Thrust и CUDPP являются лишь двумя примерами библиотек, которые обеспечивают сокращение. Я менее знаком с OpenCL, но CLPP , кажется, хорошая библиотека, которая обеспечивает сокращение. Просто скопируйте ваш цветной буфер в объект буфера пикселей OpenGL и используйте соответствующий вызов взаимодействия OpenGL, чтобы сделать доступной память этого пиксельного буфера в CUDA / OpenCL.

Если это должно быть сделано с использованием API opengl (как требуется для исходного вопроса), решение состоит в том, чтобы выполнить рендеринг в текстуру, создать мип-карту текстуры и прочитать текстуру 1x1. Вы должны установить правильную фильтрацию (я думаю, что это билинейный режим), но он должен быть близок к правильному ответу, по модулю погрешности точности.

1 голос
/ 03 марта 2012

CUDA не нужна, если вы предпочитаете придерживаться GLSL.Как и в упомянутом здесь решении CUDA, это можно сделать в фрагментном шейдере прямо вперед.Однако вам нужно про лог (разрешение) отрисовки звонков.Просто установите шейдер, который берет 2x2 пикселя из исходного изображения и выводит их среднюю сумму.В результате получается изображение с половинным разрешением по обеим осям.Повторяйте это, пока изображение не станет 1x1 px.Некоторые соображения: Используйте GL_FLOAT текстуры яркости, если они доступны, чтобы получить более точную сумму.Используйте glViewport, чтобы четверть области рендеринга на каждом этапе.Затем результат попадает в верхний левый пиксель вашего кадрового буфера.

1 голос
/ 16 сентября 2010

Мой инстинкт подсказывает мне попробовать вашу реализацию в OpenCL. Вы можете оптимизировать размер изображения и графическое оборудование, разбив изображения на отдельные куски данных, которые затем суммируются параллельно. Может быть очень быстро на самом деле.

Фрагментные шейдеры отлично подходят для сверток, но этот результат обычно записывается в gl_FragColor, так что это имеет смысл. В конечном итоге вам придется перебрать каждый пиксель текстуры и суммировать результат, который затем считывается в основной программе. Генерация статистики изображения, возможно, не соответствует тому, для чего был разработан фрагментный шейдер, и неясно, что следует добиться значительного прироста производительности, поскольку не гарантируется, что конкретный буфер находится в памяти GPU.

Похоже, вы применяете этот алгоритм к сценарию обнаружения движения в реальном времени или к какому-либо другому приложению автоматического обнаружения функций. Может быть быстрее вычислить некоторую статистику из выборки пикселей, а не всего изображения, а затем создать классификатор машинного обучения.

Удачи тебе в любом случае!

...