Census Transform in HLSL

The census transform is a filter that represents the pixel’s neighborhood relationship in a binary string. The binary string will be 0000000 if the center pixel is lesser than all of its neighbors. The binary string will be 11111111 if the center pixel is greater than or equal to all of its neighbors.

The filter does not depend on the image’s actual intensity. As a result, the filter is robust to illumination.

Source Code

float GetGreyScale(float3 Color)
{
   return max(max(Color.r, Color.g), Color.b);
}

float GetCensusTransform(sampler SampleImage, float2 Tex, float2 PixelSize)
{
   float OutputColor = 0.0;
   float4 ColumnTex[3];
   ColumnTex[0] = Tex.xyyy + (float4(-1.0, +1.0, 0.0, -1.0) * PixelSize.xyyy);
   ColumnTex[1] = Tex.xyyy + (float4( 0.0, +1.0, 0.0, -1.0) * PixelSize.xyyy);
   ColumnTex[2] = Tex.xyyy + (float4(+1.0, +1.0, 0.0, -1.0) * PixelSize.xyyy);

   const int Neighbors = 8;
   float SampleNeighbor[Neighbors];
   SampleNeighbor[0] = GetGreyScale(tex2D(SampleImage, ColumnTex[0].xy).rgb);
   SampleNeighbor[1] = GetGreyScale(tex2D(SampleImage, ColumnTex[1].xy).rgb);
   SampleNeighbor[2] = GetGreyScale(tex2D(SampleImage, ColumnTex[2].xy).rgb);
   SampleNeighbor[3] = GetGreyScale(tex2D(SampleImage, ColumnTex[0].xz).rgb);
   SampleNeighbor[4] = GetGreyScale(tex2D(SampleImage, ColumnTex[2].xz).rgb);
   SampleNeighbor[5] = GetGreyScale(tex2D(SampleImage, ColumnTex[0].xw).rgb);
   SampleNeighbor[6] = GetGreyScale(tex2D(SampleImage, ColumnTex[1].xw).rgb);
   SampleNeighbor[7] = GetGreyScale(tex2D(SampleImage, ColumnTex[2].xw).rgb);
   float CenterSample = GetGreyScale(tex2D(SampleImage, ColumnTex[1].xz).rgb);

   // Generate 8-bit integer from the 8-pixel neighborhood
   for(int i = 0; i < Neighbors; i++)
   {
      float Comparison = step(SampleNeighbor[i], CenterSample);
      OutputColor += ldexp(Comparison, i);
   }

   // Convert the 8-bit integer to float, and average the results from each channel
   return OutputColor * (1.0 / (exp2(8) - 1));
}