Simple image filters written as HLSL pixel shaders

I had to write some image filtering pixel shaders for some coarse-work. So I thought I will make them available for anyone who might want to write there own image filtering pixel shaders, or just want some quickly without having to worry about the details for now.

The snippets below are in HLSL, and are single pass techniques. Written to compile with pixel shader 2.0. The snippets have “uniform extern texture tex;” declared. The shaders only work with 1024 x 768 resolution textures: a rigid implementation, easily overcame in later shader versions with the use of ddx and ddy intrinsic functions. OK Enough fluffing around, heres the code:

Blurs using a 3×3 filter kernel

// Blurs using a 3x3 filter kernel
float4 BlurFunction3x3(VertexShaderOutput input) : COLOR0
{
  // TOP ROW
  float4 s11 = tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f, -1.0f / 768.0f));	// LEFT
  float4 s12 = tex2D(texsampler, input.texcoords + float2(0, -1.0f / 768.0f));				// MIDDLE
  float4 s13 = tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f, -1.0f / 768.0f));	// RIGHT

  // MIDDLE ROW
  float4 s21 = tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f, 0));				// LEFT
  float4 col = tex2D(texsampler, input.texcoords);											// DEAD CENTER
  float4 s23 = tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f, 0)); 				// RIGHT

  // LAST ROW
  float4 s31 = tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f, 1.0f / 768.0f));	// LEFT
  float4 s32 = tex2D(texsampler, input.texcoords + float2(0, 1.0f / 768.0f));					// MIDDLE
  float4 s33 = tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f, 1.0f / 768.0f));	// RIGHT

  // Average the color with surrounding samples
  col = (col + s11 + s12 + s13 + s21 + s23 + s31 + s32 + s33) / 9;
  return col;
}

Blurs using a 5×5 filter kernel – ARG!

// Blurs using a 5x5 filter kernel
float4 BlurFunction5x5(VertexShaderOutput input) : COLOR0
{
  return (
    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		-2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		-2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(0,					-2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		-2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		-2.0f / 768.0f)) +

    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		-1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		-1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(0,					-1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		-1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		-1.0f / 768.0f)) +

    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		0)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		0)) +
    tex2D(texsampler, input.texcoords + float2(0,					0)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		0)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		0)) +

    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(0,					1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		1.0f / 768.0f)) +

    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(0,					2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		2.0f / 768.0f))
  ) / 25;
}

Blurs using a 7×7 filter kernel – ARGGGG!!!!

// Blurs using a 7x7 filter kernel
float4 BlurFunction7x7(VertexShaderOutput input) : COLOR0
{
  return (
    tex2D(texsampler, input.texcoords + float2(-3.0f / 1024.0f,		-3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		-3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		-3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(0,					-3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		-3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		-3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(3.0f / 1024.0f,		-3.0f / 768.0f)) +

    tex2D(texsampler, input.texcoords + float2(-3.0f / 1024.0f,		-2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		-2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		-2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(0,					-2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		-2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		-2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(3.0f / 1024.0f,		-2.0f / 768.0f)) +

    tex2D(texsampler, input.texcoords + float2(-3.0f / 1024.0f,		-1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		-1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		-1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(0,					-1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		-1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		-1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(3.0f / 1024.0f,		-1.0f / 768.0f)) +

    tex2D(texsampler, input.texcoords + float2(-3.0f / 1024.0f,		0)) +
    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		0)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		0)) +
    tex2D(texsampler, input.texcoords + float2(0,					0)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		0)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		0)) +
    tex2D(texsampler, input.texcoords + float2(3.0f / 1024.0f,		0)) +

    tex2D(texsampler, input.texcoords + float2(-3.0f / 1024.0f,		1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(0,					1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(3.0f / 1024.0f,		1.0f / 768.0f)) +

    tex2D(texsampler, input.texcoords + float2(-3.0f / 1024.0f,		2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(0,					2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(3.0f / 1024.0f,		2.0f / 768.0f)) +

    tex2D(texsampler, input.texcoords + float2(-3.0f / 1024.0f,		3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(0,					3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(3.0f / 1024.0f,		3.0f / 768.0f))
  ) / 49;
}

Outputs edges only using a A 3×3 edge filter kernel

// Outputs edges only using a A 3x3 edge filter kernel
float4 OutlinesFunction3x3(VertexShaderOutput input) : COLOR0
{
  float4 lum = float4(0.30, 0.59, 0.11, 1);

  // TOP ROW
  float s11 = dot(tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f, -1.0f / 768.0f)), lum);	// LEFT
  float s12 = dot(tex2D(texsampler, input.texcoords + float2(0, -1.0f / 768.0f)), lum);				// MIDDLE
  float s13 = dot(tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f, -1.0f / 768.0f)), lum);	// RIGHT

  // MIDDLE ROW
  float s21 = dot(tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f, 0)), lum);				// LEFT
  // Omit center
  float s23 = dot(tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f, 0)), lum); 				// RIGHT

  // LAST ROW
  float s31 = dot(tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f, 1.0f / 768.0f)), lum);	// LEFT
  float s32 = dot(tex2D(texsampler, input.texcoords + float2(0, 1.0f / 768.0f)), lum);				// MIDDLE
  float s33 = dot(tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f, 1.0f / 768.0f)), lum);	// RIGHT

  // Filter ... thanks internet 🙂
  float t1 = s13 + s33 + (2 * s23) - s11 - (2 * s21) - s31;
  float t2 = s31 + (2 * s32) + s33 - s11 - (2 * s12) - s13;

  float4 col;

  if (((t1 * t1) + (t2 * t2)) > 0.05) {
  col = float4(0,0,0,1);
  } else {
    col = float4(1,1,1,1);
  }

  return col;
}

A 3×3 emboss filter kernel

// A 3x3 emboss filter kernel
float4 EmbossShaderFunction3x3(VertexShaderOutput input) : COLOR0
{
  float4 s22 = tex2D(texsampler, input.texcoords); // center
  float4 s11 = tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f, -1.0f / 768.0f));
  float4 s33 = tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f, 1.0f / 768.0f));

  s11.rgb = (s11.r + s11.g + s11.b);
  s22.rgb = (s22.r + s22.g + s22.b) * -0.5;
  s33.rgb = (s22.r + s22.g + s22.b) * 0.2;

  return (s11 + s22 + s33);
  // return col * (s11 + s22 + s33); // with color 🙂 - but B & W looks a lot nicer
}

Advertisements