330 likes | 503 Views
Обработка изображений на GPU. Обработка изображений (и видео) довольно часто встречается в раз-личных областях. При этом она зачастую требует проведения весьма сложных вычислений для большого количества пикселов.
E N D
Обработка изображений на GPU Обработка изображений (и видео) довольно часто встречается в раз-личных областях. При этом она зачастую требует проведения весьма сложных вычислений для большого количества пикселов. Кроме того, во многих случаях требуется высокая точность (т.е. 8 бит на компоненту явно недостаточно L Все это очень хорошо ложится на модель программирования GPU. Использование GPU позволяет параллельно обрабатывать огромное количество пикселов, задавая их как четырехмерные вещественные вектора J
Обработка изображений на GPU Операционная система Mac OS X содержит модуль CoreImage, обеспечивающий обработку изображений средствами GPU. В него входят десятки стандартных фильтров и возможность написания своих фильтров на специальном языке - подмножестве GLSL Сама система Mac OS X уже давно использует GPU для вывода данных на экран, используя мощные возможности современных GPU для полноценной поддержки полупрозрачности, преобразований и многих других эффектов.
Обработка изображений на GPU - общая схема Помещаем исходные изображения в текстуры (можно с float-форматом), вывод осуществляется в р-буфер или FBO. Средствами OpenGL осуществляется вывод прямоугольника, соответствующего выходному изображению. image1 Фрагментная программа outImage image2 imageN
Обработка изображений на GPU - вершинная программа struct InData { float4 pos : POSITION; float2 texCoord : TEXCOORD0; }; struct OutData { float4 pos : POSITION; float2 texCoord : TEXCOORD0; }; OutData main ( InData IN, uniform float4x4 ModelViewProj ) { OutData OUT; OUT.pos = mul ( ModelViewProj, IN.pos ); OUT.texCoord = IN.texCoord; return OUT; }
Обработка изображений на GPUПример: перевод в оттенки серого цвета Формула преобразования: С = 0.3 * Red +0.59 * Green + 0.11 * Blue
Обработка изображений на GPUПример: перевод в оттенки серого цвета struct InData { float4 pos : POSITION; float2 texCoord : TEXCOORD0; }; float4 main ( InData IN, uniform sampler2D tex0 ) : COLOR { const float3 luminance = float3 ( 0.3, 0.59, 0.11 ); float4 color = tex2D ( tex0, IN.texCoord ); return float4 ( float3 ( dot ( color.rgb, luminance ) ), 1.0 ); }
Обработка изображений на GPUПример: Sepia Формула преобразования: С = sepiaColor*(0.3 * Red +0.59 * Green + 0.11 * Blue)
Обработка изображений на GPUПример: Sepia struct InData { float4 pos : POSITION; float2 texCoord : TEXCOORD0; }; float4 main ( InData IN, uniform sampler2D tex0 ) : COLOR { const float3 luminance = float3 ( 0.3, 0.59, 0.11 ); const float3 sepiaColor = float3 ( 1, 0.89, 0.54 ); float4 color = tex2D ( tex0, IN.texCoord ); return float4 ( dot ( color.rgb, luminance ) * sepiaColor, 1.0 ); }
Обработка изображений на GPUПример: гамма-коррекция Формула преобразования: С = pow ( C, 1 / gamma )
Обработка изображений на GPUПример: гамма-коррекция struct InData { float4 pos : POSITION; float2 texCoord : TEXCOORD0; }; float4 main ( InData IN, uniform float gamma, uniform sampler2D tex0 ) : COLOR { float3 color = tex2D ( tex0, IN.texCoord ).rgb; return float4 ( pow ( color, 1.0 / gamma ), 1.0 ); }
Обработка изображений на GPUСвертка при помощи ядра Общий случай: - элементы исходного изображения - элементы выходного изображения - ядро свертки (3*3,5*5,….N*N)
Обработка изображений на GPU Пример - фильтр выделения границ (edge-detect) Преобразование интенсивности:
Обработка изображений на GPU Пример - фильтр выделения границ (edge-detect) float4 main ( InData IN, uniform sampler2D tex0 ) : COLOR { const float3 lum = float3 ( 0.3, 0.59, 0.11 ); const float2 d01 = float2 ( 0, 1.0 / 512.0 ); const float2 d10 = float2 ( 1.0 / 512.0, 0 ); const float scale = 1.0; float c1 = dot( lum, tex2D( tex0, IN.texCoord+d01 ).rgb ); float c2 = dot( lum, tex2D( tex0, IN.texCoord-d01 ).rgb ); float c3 = dot( lum, tex2D( tex0, IN.texCoord+d10 ).rgb ); float c4 = dot( lum, tex2D( tex0, IN.texCoord-d10 ).rgb ); return float4 ( float3 ( scale * ( abs( c1 - c2 ) + abs( c2 - c3 ) ) ), 1 ); }
Обработка изображений на GPUПример - Blur (размытие)
Обработка изображений на GPUПример - Blur (размытие) Размытие с ядром Гаусса: Заметим, что: Отсюда получаем:
Обработка изображений на GPUПример - Blur (размытие) Таким образом можно 2-мерное размытие свести к 2 двум одномерным - сперва по х, а потом - по у. Ядро, обладающее подобным свойством называется разделяемым (separable). При этом понадобится вспомогательный буфер y-blur x-blur buffer1 buffer2 buffer1
Обработка изображений на GPUПример - Blur (размытие) // // x-blur fragment shader // float4 main ( InData IN, uniform sampler2D tex0 ) : COLOR { float3 sum = float3 ( 0.0 ); float2 dx = float2 ( 1.0 / 512.0, 0.0 ); float2 tx = IN.texCoord - 3.0 * dx; for ( int i = 0; i < 7; i++ ) { sum += tex2D ( tex0, tx ).rgb; tx += dx; } return float4 ( sum / 7.0, 1.0 ); }
Обработка изображений на GPUПример - emboss Ядро (применяемое к интенсивности):
Обработка изображений на GPUПример - emboss float4 main ( InData IN, uniform sampler2D tex ) : COLOR { const float3 lum = float3 ( 0.3, 0.59, 0.11 ); const float2 d01 = float2 ( 0, 1.0 / 512.0 ); const float2 d10 = float2 ( 1.0 / 512.0, 0 ); float c00 = dot(lum, tex2D(tex, IN.texCoord-d01-d10).rgb); float c01 = dot(lum, tex2D(tex, IN.texCoord-d10).rgb); float c02 = dot(lum, tex2D(tex, IN.texCoord+d01-d10).rgb ); float c10 = dot(lum, tex2D(tex, IN.texCoord-d01).rgb ); float c11 = dot(lum, tex2D(tex, IN.texCoord).rgb ); float c12 = dot(lum, tex2D(tex, IN.texCoord+d01).rgb ); float c20 = dot(lum, tex2D(tex, IN.texCoord+d10-d01).rgb ); float c21 = dot(lum, tex2D(tex, IN.texCoord+d10).rgb ); float c22 = dot(lum, tex2D(tex, IN.texCoord+d10+d01).rgb ); float res = c00 + c01 - c02 + c10 + c11 - c12 + c20 - c21 - c22; return float4 ( res, res, res, 1.0 ); }
Обработка изображений на GPUПример - enhance
Обработка изображений на GPUПример - enhance Применяемое преобразование: Разностный аналог оператора Лапласа:
Обработка изображений на GPUПреобразования цветов в пространстве HSV • Модель HSV: • H (Hue) - тон ([0,360)), • S (Saturation) - насыщенность ([0,1]), • V (Value) - интенсивность (яркость) [0,1]) V Зеленый Желтый 1.0 Голубой Красный Синий Малиновый 0.0 S Черный
Обработка изображений на GPUПреобразования цветов в пространстве HSV
Обработка изображений на GPUПреобразования цветов в пространстве HSV
Обработка изображений на GPUПреобразования цветов в пространстве HSV float3 rgbToHsv ( const in float3 c ) { float mn = min ( min ( c.r, c.g ), c.b ); float mx = max ( max ( c.r, c.g ), c.b ); float delta = mx - mn; float v = mx, h = 0.0, s = 0.0; if ( mx > EPS ) { s = delta / mx; if ( c.r == mx ) h = ( c.g - c.b ) / delta; else if ( c.g == mx ) h = 2.0 + ( c.b - c.r ) / delta; else h = 4.0 + ( c.r - c.g ) / delta; } return float3 ( h / 6.0, s, v ); }
Обработка изображений на GPUПример - эффект старого фильма
Обработка изображений на GPUПример - эффект старого фильма • Основные элементы: • дергание (shudder) исходного изображения, • изменения яркости, • царапины, • волоски, пылинки и прочий мусор
Обработка изображений на GPUЭффект старого фильма, вершинная программа struct InData { float4 pos : POSITION; float2 texCoord : TEXCOORD0; }; struct OutData { float4 pos : POSITION; float2 texCoord : TEXCOORD0; float2 shudder; float2 blipCoord; float2 scratchCoord; float brightness; };
Обработка изображений на GPUЭффект старого фильма, вершинная программа OutData main ( InData IN,uniform float time, uniform float4x4 ModelViewProj ) { OutData OUT; OUT.shudder = IN.texCoord + C1* float2 ( sin(time*C2), cos(time*C3)); OUT.brightness = clamp(3.0*sin(time*C4), 0.7, 1.0 ); OUT.blipCoord = C5*IN.texCoord + float2(sin(C6*time)+cos(C7*time ), cos(C8*time)+sin(C9*time)); OUT.scratchCoord= IN.texCoord+float2(C10*cos(C11*time), C12*sin(C13*time)); OUT.pos = mul ( ModelViewProj, IN.pos ); OUT.texCoord = IN.texCoord; return OUT; }
Обработка изображений на GPUЭффект старого фильма, вершинная программа float4 main ( OutData IN, uniform sampler2D mainTex, uniform sampler2D scratchTex, uniform sampler2D blipTex ) : COLOR { const float3 luminance = float3 ( 0.3, 0.59, 0.11 ); float4 color = tex2D ( mainTex, IN.shudder ); float4 scratch = tex2D ( scratchTex, IN.scratchCoord ); float4 blip = tex2D ( blipTex, IN.blipCoord ); float4 outColor = dot ( color.rgb, luminance ) * IN.brightness * scratch * blip; return float4 ( outColor.r, outColor.g, outColor.b, 1.0 ); }
Обработка изображений на GPUПример - эффект перехода к другому видеоряду Программа смешения Видеоряд 1 Видеоряд 2 Задача: организовать плавный переход от одного видеоряда к другому Выходной видеоряд 1
Обработка изображений на GPUПример - эффект перехода к другому видеоряду Используем вспомогательную текстуру transMap: R-компонента - момент начала перехода к второму ряду G-компонента - конец перехода к второму ряду Закон смешения потоков: float3 trans = tex2D ( transMap, IN.texCoord ).rgb; float p = clamp ( time, trans.r, trans.g ); float4 c1 = tex2D ( image1Map, IN.texCoord ); float4 c2 = tex2D ( image2Map, IN.texCoord ); return mix ( c1, c2, (p - trans.r)/(trans.g - trans.r) );
Обработка изображений на GPUПример - эффект перехода к другому видеоряду В результате мы получили очень гибкий механизм перехода от одного видеоряда к другом - для каждого пиксела задается начало и конец перехода. Внутри интервала переходя происходит линейная интерполяция между цветами J