Обработка изображений на GPU

advertisement
Обработка изображений на GPU
L
J
Обработка изображений (и видео) довольно часто
встречается в раз-личных областях. При этом она
зачастую требует проведения весьма сложных
вычислений для большого количества пикселов.
Кроме того, во многих случаях требуется высокая
точность (т.е. 8 бит на компоненту явно недостаточно
Все это очень хорошо ложится на модель
программирования GPU.
Использование GPU позволяет параллельно
обрабатывать огромное количество пикселов, задавая
их как четырехмерные вещественные вектора
Обработка изображений на GPU
Операционная система Mac OS X содержит
модуль CoreImage, обеспечивающий
обработку изображений средствами GPU.
В него входят десятки стандартных
фильтров и возможность написания своих
фильтров на специальном языке подмножестве GLSL
Сама система Mac OS X уже давно использует
GPU для вывода данных на экран, используя
мощные возможности современных GPU для
полноценной поддержки полупрозрачности,
преобразований и многих других эффектов.
Обработка изображений на GPU - общая схема
Помещаем исходные изображения в текстуры (можно с floatформатом), вывод осуществляется в р-буфер или FBO.
Средствами OpenGL осуществляется вывод прямоугольника,
соответствующего выходному изображению.
image1
image2
imageN
Фрагментная
программа
outImage
Обработка изображений на 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
Свертка при помощи ядра
Общий случай:
cˆi , j 
r
r
 k
l  r m r
l ,m
 ci l , j  m
ci , j
- элементы исходного изображения
cˆi , j
- элементы выходного изображения
kl , m
- ядро свертки (3*3,5*5,….N*N)
Обработка изображений на GPU
Пример - фильтр выделения границ
(edge-detect)
Преобразование
интенсивности:

Iˆi , j  k  I i 1, j  I i 1, j  I i , j 1  I i , j 1

Обработка изображений на GPU
Пример - фильтр выделения границ
(edge-detect)
float4 main ( InData IN,
uniform sampler2D tex0
{
const float3 lum
= float3 (
const float2 d01
= float2 (
const float2 d10
= float2 (
const float scale = 1.0;
float
float
float
float
c1
c2
c3
c4
=
=
=
=
dot(
dot(
dot(
dot(
lum,
lum,
lum,
lum,
tex2D(
tex2D(
tex2D(
tex2D(
) : COLOR
0.3, 0.59, 0.11 );
0, 1.0 / 512.0 );
1.0 / 512.0, 0 );
tex0,
tex0,
tex0,
tex0,
IN.texCoord+d01
IN.texCoord-d01
IN.texCoord+d10
IN.texCoord-d10
).rgb
).rgb
).rgb
).rgb
);
);
);
);
return float4 ( float3 ( scale * ( abs( c1 - c2 ) +
abs( c2 - c3 ) ) ), 1 );
}
Обработка изображений на GPU
Пример - Blur (размытие)
Обработка изображений на GPU
Пример - Blur (размытие)
Размытие с ядром Гаусса:
Заметим, что:

ki , j  C  exp  k  i 2  k  j 2




ki , j  C  exp  k  i 2  C  exp  k  j 2
Отсюда получаем:
ˆ r ˆ

cˆi , j    kl   k m  ci l , j  m 
l  r 
m r

r

kl  C  exp  k  l 2


Обработка изображений на 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
Ядро (применяемое к интенсивности):
1 1  1


1 1  1
1  1  1


Обработка изображений на GPU
Пример - emboss
float4 main ( InData
{
const float3 lum
const float2 d01
const float2 d10
float
float
float
float
float
float
float
float
float
float
=
=
=
=
=
=
=
=
=
=
= float3 ( 0.3, 0.59, 0.11 );
= float2 ( 0, 1.0 / 512.0 );
= float2 ( 1.0 / 512.0, 0 );
dot(lum, tex2D(tex, IN.texCoord-d01-d10).rgb);
dot(lum, tex2D(tex, IN.texCoord-d10).rgb);
dot(lum, tex2D(tex, IN.texCoord+d01-d10).rgb );
dot(lum, tex2D(tex, IN.texCoord-d01).rgb );
dot(lum, tex2D(tex, IN.texCoord).rgb );
dot(lum, tex2D(tex, IN.texCoord+d01).rgb );
dot(lum, tex2D(tex, IN.texCoord+d10-d01).rgb );
dot(lum, tex2D(tex, IN.texCoord+d10).rgb );
dot(lum, tex2D(tex, IN.texCoord+d10+d01).rgb );
c00 + c01 - c02 + c10 + c11 - c12 +
c20 - c21 - c22;
return float4 ( res, res, res, 1.0 );
}
c00
c01
c02
c10
c11
c12
c20
c21
c22
res
IN, uniform sampler2D tex ) : COLOR
Обработка изображений на GPU
Пример - enhance
Обработка изображений на GPU
Пример - enhance
Применяемое преобразование:
Cˆ i , j  Ci , j  1  k  Ci , j 
Разностный аналог оператора Лапласа:
Ci , j  Ci 1, j  Ci 1, j  Ci , j 1  Ci1, j 1  4  Ci , j
Обработка изображений на GPU
Преобразования цветов в пространстве HSV
V
Зеленый
1.0
Голубой
Синий
Желтый
Красный
Модель HSV:
• H (Hue) - тон ([0,360)),
• S (Saturation) - насыщенность ([0,1]),
• V (Value) - интенсивность (яркость) [0,1])
Малиновый
R, G, B  H , S ,V   k  H , k  S , k V   R, G, B
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
uniform sampler2D
uniform sampler2D
{
const float3 luminance =
float4
float4
float4
float4
color
scratch
blip
outColor
=
=
=
=
mainTex,
scratchTex,
blipTex ) : COLOR
float3 ( 0.3, 0.59, 0.11 );
tex2D ( mainTex,
IN.shudder );
tex2D ( scratchTex, IN.scratchCoord );
tex2D ( blipTex,
IN.blipCoord
);
dot ( color.rgb, luminance ) *
IN.brightness * scratch * blip;
return float4 ( outColor.r, outColor.g, outColor.b, 1.0 );
}
Обработка изображений на GPU
Пример - эффект перехода к другому
видеоряду
Программа смешения
Видеоряд 1
Выходной видеоряд 1
Видеоряд 2
Задача:
организовать плавный
переход от одного видеоряда
к другому
Обработка изображений на GPU
Пример - эффект перехода к другому
видеоряду
Используем вспомогательную текстуру transMap:
R-компонента - момент начала перехода к второму ряду
G-компонента - конец перехода к второму ряду
Закон смешения потоков:
float3
float
float4
float4
trans
p
c1
c2
=
=
=
=
tex2D
clamp
tex2D
tex2D
(
(
(
(
transMap, IN.texCoord
time, trans.r, trans.g
image1Map, IN.texCoord
image2Map, IN.texCoord
).rgb;
);
);
);
return mix ( c1, c2, (p - trans.r)/(trans.g - trans.r) );
Обработка изображений на GPU
Пример - эффект перехода к другому
видеоряду
J
В результате мы получили
очень гибкий механизм
перехода от одного
видеоряда к другом - для
каждого пиксела задается
начало и конец перехода.
Внутри интервала
переходя происходит
линейная интерполяция
между цветами
Download