Output of multiscale retinex algorithm.

## Introduction

The variation of illumination conditions of an object can produce large changes in the image plane, significantly impairing the performance of face verification and recognition algorithms. I present three photometric normalisation algorithms for use in pre-processing face images in order to be used in verification and recognition algorithms. Mainly I follow the ideas of paper "A Comparison of Photometric Normalisation Algorithms for Face Verification", James Short, Josef Kittler and Kieron Messer(2004) and "Lighting Normalization Algorithms for Face Verification", Guillaume Heusch, Fabien Cardinaux, Sebastien Marcel(2005). Multiscale retinex method is coded exactly like the theory says. The anisotropic and isotropic smoothing methods have a little modifications but essentially they are the same. If you want to see more details about them, you can see the papers previously mentioned.

## Using the Code

You can apply the multiscale retinex method like:

MultiscaleRetinex retinex = new MultiscaleRetinex
(param.Sigmas, param.Widths, param.FilterSize);
picFiltered.Image = retinex.Apply((Bitmap)bitmap.Clone());

This is the code of multiscale retinex algorithm:

public override unsafe Bitmap Apply(Bitmap bitmap)
{
int count = sigmas.Length;
Bitmap bmp;
double[,] sum = new double[bitmap.Width, bitmap.Height];
for (int i = 0; i < count;i++ )
{
bmp = new GaussianBlur(sigmas[i], size).Apply(bitmap);
sum = SumBitmap(bmp,sum,widths[i]);
}
return Normalise(DivBitmap(bitmap, sum));
}

You can apply the isotropic smoothing method like:

IsotropicSmoothing iso = new IsotropicSmoothing(param.Value);
picFiltered.Image = iso.Apply((Bitmap)bitmap.Clone());

This is the code of isotropic smoothing algorithm:

public override unsafe Bitmap Apply(Bitmap bitmap)
{
Bitmap = bitmap;
Point size = PixelSize;
double[,] src = new double[size.X, size.Y];
bool first = true;
byte N, S, E, W, A;
double Lw, Le, Ls, Ln, tmp, min = 0, max = 0;
LockBitmap();
for (int y = 0; y < size.Y ; y++)
{
PixelData* pPixel = PixelAt(0, y);
for (int x = 0; x < size.X ; x++)
{
tmp = pPixel->gray;
if ((x > 0) && (x < size.X-1) && (y > 0) && (y < size.Y-1))
{
A = pPixel->gray;
E = PixelAt(x, y+1)->gray;
S = PixelAt(x+1, y)->gray;
N = PixelAt(x-1, y)->gray;
W = PixelAt(x, y-1)->gray;
Lw = A - W;
Le = A - E;
Ln = A - N;
Ls = A - S;
tmp = A + smooth * (Ln + Ls + Le + Lw);
}
src[x, y] = tmp;
if (first) { min = max = tmp; first = false; }
else
{
if (tmp < min) min = tmp;
else
if (tmp > max) max = tmp;
}
pPixel++;
}
}
UnlockBitmap();
return Normalise(src, min, max);
}

Output of isotropic smoothing algorithm.

You can apply the anisotropic smoothing method like:

AnisotropicSmoothing anis = new AnisotropicSmoothing(param.Value);
picFiltered.Image = anis.Apply((Bitmap)bitmap.Clone());

This is the code of anisotropic smoothing algorithm:

public override unsafe Bitmap Apply(Bitmap bitmap)
{
Bitmap = bitmap;
Point size = PixelSize;
double[,] src = new double[size.X,size.Y];
bool first = true;
byte N, S, E, W, A;
double Lw, Le, Ls, Ln, pw, pe, ps, pn, eps = .1, tmp, min = 0, max = 0;
LockBitmap();
for (int y = 0; y < size.Y; y++)
{
PixelData* pPixel = PixelAt(0, y);
for (int x = 0; x < size.X; x++)
{
tmp = pPixel->gray;
if ((x > 0) && (x < size.X-1) && (y > 0) && (y < size.Y-1))
{
A = pPixel->gray;
E = PixelAt(x, y+1)->gray;
S = PixelAt(x+1, y)->gray;
N = PixelAt(x-1, y)->gray;
W = PixelAt(x, y-1)->gray;
Lw = A - W;
Le = A - E;
Ln = A - N;
Ls = A - S;
pw = Math.Min(A, W) / (Math.Abs(A - W) + eps);
pe = Math.Min(A, E) / (Math.Abs(A - E) + eps);
pn = Math.Min(A, N) / (Math.Abs(A - N) + eps);
ps = Math.Min(A, S) / (Math.Abs(A - S) + eps);
tmp = A + smooth * (Ln * pn + Ls * ps + Le * pe + Lw * pw);
}
src[x, y] = tmp;
if (first) { min = max = tmp; first = false; }
else
{
if (tmp < min) min = tmp;
else
if (tmp > max) max = tmp;
}
pPixel++;
}
}
UnlockBitmap();
return Normalise(src,min, max);
}

Output of anisotropic smoothing algorithm.

## Credits

## Versions