I found some code (but I can't find the source URL again). It was some german guy's code that was answering a similar question on MSDN. I'm using the sigma functions. I reformatted the code a little and added the
NormalizeValue
method (at the top) as well as the
Blur
method (at the bottom). I call the
Blur
method from my own code.
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Collections;
using System.Drawing.Drawing2D;
using System.Collections.Generic;
namespace CamoPicker
{
public static class ImageBlur
{
private static int NormalizeValue(int value, int min, int max)
{
int result = Math.Min(Math.Max(value, min), max);
return result;
}
public static unsafe bool makeEdgesTransparentHorz(Bitmap bmp, int nWidth1, int nWidth2, int nZuwachs1, int nZuwachs2, bool bauto)
{
BitmapData bmData = null;
Bitmap bmpOrig = null;
BitmapData bmDataOrig = null;
try
{
ArrayList Al = new ArrayList();
bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
System.IntPtr Scan0 = bmData.Scan0;
byte* p = (byte*)(void*)Scan0;
bmpOrig = (Bitmap)bmp.Clone();
bmDataOrig = bmpOrig.LockBits(new Rectangle(0, 0, bmpOrig.Width, bmpOrig.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
System.IntPtr Scan0Orig = bmDataOrig.Scan0;
byte* pOrig = (byte*)(void*)Scan0Orig;
int lp = 0;
for (int row = 0; row < bmp.Height; row++)
{
for (int col = 0; col < bmp.Width; col++)
{
p = (byte*)(void*)Scan0;
p += (row * bmp.Width * 4) + (col * 4);
if ((p[3] > 0) && (lp == 0))
{
Al.Add(new Point(col, row));
}
lp = (int)p[3];
}
lp = 0;
}
Al.TrimToSize();
for (int i = 0; i < Al.Count; i++)
{
Point pt1 = (Point)Al[i];
p = (byte*)(void*)Scan0;
pOrig = (byte*)(void*)Scan0Orig;
if (pt1.X <= bmp.Width - nWidth1)
{
p += (pt1.Y * bmp.Width * 4) + (pt1.X * 4);
pOrig += (pt1.Y * bmpOrig.Width * 4) + (pt1.X * 4);
int start = 255 - (int)(nZuwachs1 * nWidth1);
int z = nZuwachs1;
if (bauto)
{
z = Math.Max(1, (int)Math.Ceiling(255.0 / nWidth1));
start = Math.Max(0, (int)(255 - (z * nWidth1)));
}
for (int ii = 0; ii < nWidth1; ii++)
{
int val = NormalizeValue(start, 0, 255);
p[3] = (byte)(((double)pOrig[3] / 255.0) * val);
start += z;
p += 4;
pOrig += 4;
}
}
}
Al.Clear();
lp = 0;
for (int row = 0; row < bmp.Height; row++)
{
for (int col = bmp.Width - 1; col >= 0; col--)
{
p = (byte*)(void*)Scan0;
p += (row * bmp.Width * 4) + (col * 4);
if ((p[3] > 0) && (lp == 0))
{
Al.Add(new Point(col, row));
}
lp = (int)p[3];
}
lp = 0;
}
Al.TrimToSize();
for (int i = 0; i < Al.Count; i++)
{
Point pt1 = (Point)Al[i];
p = (byte*)(void*)Scan0;
pOrig = (byte*)(void*)Scan0Orig;
if (pt1.X >= (nWidth2 - 1))
{
int start = 255 - (int)(nZuwachs2 * nWidth2);
int z = nZuwachs2;
if (bauto)
{
z = Math.Max(1, (int)Math.Ceiling(255.0 / nWidth2));
start = Math.Max(0, (int)(255 - (z * nWidth2)));
}
p = (byte*)(void*)Scan0;
p += ((nWidth2) * -4) + (pt1.Y * bmp.Width * 4) + ((pt1.X + nWidth2) * 4);
pOrig = (byte*)(void*)Scan0Orig;
pOrig += ((nWidth2) * -4) + (pt1.Y * bmpOrig.Width * 4) + ((pt1.X + nWidth2) * 4);
for (int ii = 0; ii < nWidth2; ii++)
{
int val = NormalizeValue(start, 0, 255);
p[3] = (byte)(((double)pOrig[3] / 255.0) * val);
start += z;
p -= 4;
pOrig -= 4;
}
}
}
bmp.UnlockBits(bmData);
bmpOrig.UnlockBits(bmDataOrig);
bmpOrig.Dispose();
bmpOrig = null;
return true;
}
catch
{
try
{
bmpOrig.UnlockBits(bmDataOrig);
bmp.UnlockBits(bmData);
}
catch
{
}
if (bmpOrig != null)
{
bmpOrig.Dispose();
bmpOrig = null;
}
}
return false;
}
public static unsafe bool makeEdgesTransparentVert(Bitmap bmp, int nWidth1, int nWidth2, int nZuwachs1, int nZuwachs2, bool bauto)
{
BitmapData bmData = null;
Bitmap bmpOrig = null;
BitmapData bmDataOrig = null;
try
{
ArrayList Al = new ArrayList();
bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
System.IntPtr Scan0 = bmData.Scan0;
byte* p = (byte*)(void*)Scan0;
bmpOrig = (Bitmap)bmp.Clone();
bmDataOrig = bmpOrig.LockBits(new Rectangle(0, 0, bmpOrig.Width, bmpOrig.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
System.IntPtr Scan0Orig = bmDataOrig.Scan0;
byte* pOrig = (byte*)(void*)Scan0Orig;
int lp = 0;
for (int col = 0; col < bmp.Width; col++)
{
for (int row = 0; row < bmp.Height; row++)
{
p = (byte*)(void*)Scan0;
p += (row * bmp.Width * 4) + (col * 4);
if ((p[3] > 0) && (lp == 0))
{
Al.Add(new Point(col, row));
}
lp = (int)p[3];
}
lp = 0;
}
Al.TrimToSize();
for (int i = 0; i < Al.Count; i++)
{
Point pt1 = (Point)Al[i];
p = (byte*)(void*)Scan0;
pOrig = (byte*)(void*)Scan0Orig;
if (pt1.Y <= bmp.Height - nWidth1)
{
p += (pt1.Y * bmp.Width * 4) + (pt1.X * 4);
pOrig += (pt1.Y * bmpOrig.Width * 4) + (pt1.X * 4);
int start = 255 - (int)(nZuwachs1 * nWidth1);
int z = nZuwachs1;
if (bauto)
{
z = Math.Max(1, (int)Math.Ceiling(255.0 / nWidth1));
start = Math.Max(0, (int)(255 - (z * nWidth1)));
}
for (int ii = 0; ii < nWidth1; ii++)
{
int val = NormalizeValue(start, 0, 255);
p[3] = (byte)(((double)pOrig[3] / 255.0) * val);
start += z;
p += (bmp.Width * 4);
pOrig += (bmpOrig.Width * 4);
}
}
}
Al.Clear();
lp = 0;
for (int col = 0; col < bmp.Width; col++)
{
for (int row = bmp.Height - 1; row >= 0; row--)
{
p = (byte*)(void*)Scan0;
p += (row * bmp.Width * 4) + (col * 4);
if ((p[3] > 0) && (lp == 0))
{
Al.Add(new Point(col, row));
}
lp = (int)p[3];
}
lp = 0;
}
Al.TrimToSize();
for (int i = 0; i < Al.Count; i++)
{
Point pt1 = (Point)Al[i];
p = (byte*)(void*)Scan0;
pOrig = (byte*)(void*)Scan0Orig;
if (pt1.Y >= (nWidth2 - 1))
{
int start = 255 - (int)(nZuwachs2 * nWidth2);
int z = nZuwachs2;
if (bauto)
{
z = Math.Max(1, (int)Math.Ceiling(255.0 / nWidth2));
start = Math.Max(0, (int)(255 - (z * nWidth2)));
}
p = (byte*)(void*)Scan0;
p += ((nWidth2) * bmp.Width * -4) + ((pt1.Y + nWidth2) * bmp.Width * 4) + (pt1.X * 4);
pOrig = (byte*)(void*)Scan0Orig;
pOrig += ((nWidth2) * bmpOrig.Width * -4) + ((pt1.Y + nWidth2) * bmpOrig.Width * 4) + (pt1.X * 4);
for (int ii = 0; ii < nWidth2; ii++)
{
int val = NormalizeValue(start, 0, 255);
p[3] = (byte)(((double)pOrig[3] / 255.0) * val);
start += z;
p -= (bmp.Width * 4);
pOrig -= (bmpOrig.Width * 4);
}
}
}
bmp.UnlockBits(bmData);
bmpOrig.UnlockBits(bmDataOrig);
bmpOrig.Dispose();
bmpOrig = null;
return true;
}
catch
{
try
{
bmpOrig.UnlockBits(bmDataOrig);
bmp.UnlockBits(bmData);
}
catch
{
}
if (bmpOrig != null)
{
bmpOrig.Dispose();
bmpOrig = null;
}
}
return false;
}
public static double[] getVector(int Length)
{
if ((Length & 0x01) != 1)
{
MessageBox.Show("Length must be odd", "Hinweis", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return new Double[] { };
}
double[] KernelVector = new double[Length];
int Radius = Length / 2;
double a = -2.0 * Radius * Radius / Math.Log(0.01 );
double Sum = 0.0;
for (int x = 0; x < KernelVector.Length; x++)
{
double dist = Math.Abs(x - Radius);
KernelVector[x] = Math.Exp(-dist * dist / a);
Sum += KernelVector[x];
}
return KernelVector;
}
public static unsafe bool makeEdgesTransparentHorzSigma(Bitmap bmp, int nWidth1, int nWidth2)
{
BitmapData bmData = null;
Bitmap bmpOrig = null;
BitmapData bmDataOrig = null;
try
{
ArrayList Al = new ArrayList();
bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
System.IntPtr Scan0 = bmData.Scan0;
byte* p = (byte*)(void*)Scan0;
bmpOrig = (Bitmap)bmp.Clone();
bmDataOrig = bmpOrig.LockBits(new Rectangle(0, 0, bmpOrig.Width, bmpOrig.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
System.IntPtr Scan0Orig = bmDataOrig.Scan0;
byte* pOrig = (byte*)(void*)Scan0Orig;
int lp = 0;
for (int row = 0; row < bmp.Height; row++)
{
for (int col = 0; col < bmp.Width; col++)
{
p = (byte*)(void*)Scan0;
p += (row * bmp.Width * 4) + (col * 4);
if ((p[3] > 0) && (lp == 0))
{
Al.Add(new Point(col, row));
}
lp = (int)p[3];
}
lp = 0;
}
Al.TrimToSize();
double[] Values = getVector((nWidth1 * 2) + 1);
if (Values.Length / 2 == nWidth1)
{
for (int i = 0; i < Al.Count; i++)
{
Point pt1 = (Point)Al[i];
p = (byte*)(void*)Scan0;
pOrig = (byte*)(void*)Scan0Orig;
if (pt1.X <= bmp.Width - nWidth1)
{
p += (pt1.Y * bmp.Width * 4) + (pt1.X * 4);
pOrig += (pt1.Y * bmpOrig.Width * 4) + (pt1.X * 4);
for (int ii = 0; ii < nWidth1; ii++)
{
int val = (int)Math.Max(0, (int)(255.0 * Values[ii]));
val = NormalizeValue(val, 0, 255);
p[3] = (byte)(((double)pOrig[3] / 255.0) * val);
p += 4;
pOrig += 4;
}
}
}
}
Al.Clear();
lp = 0;
for (int row = 0; row < bmp.Height; row++)
{
for (int col = bmp.Width - 1; col >= 0; col--)
{
p = (byte*)(void*)Scan0;
p += (row * bmp.Width * 4) + (col * 4);
if ((p[3] > 0) && (lp == 0))
{
Al.Add(new Point(col, row));
}
lp = (int)p[3];
}
lp = 0;
}
Al.TrimToSize();
Values = getVector((nWidth2 * 2) + 1);
if (Values.Length / 2 == nWidth2)
{
for (int i = 0; i < Al.Count; i++)
{
Point pt1 = (Point)Al[i];
p = (byte*)(void*)Scan0;
pOrig = (byte*)(void*)Scan0;
if (pt1.X >= (nWidth2 - 1))
{
p = (byte*)(void*)Scan0;
p += ((nWidth2) * -4) + (pt1.Y * bmp.Width * 4) + ((pt1.X + nWidth2) * 4);
pOrig = (byte*)(void*)Scan0Orig;
pOrig += ((nWidth2) * -4) + (pt1.Y * bmpOrig.Width * 4) + ((pt1.X + nWidth2) * 4);
for (int ii = 0; ii < nWidth2; ii++)
{
int val = (int)Math.Max(0, (int)(255.0 * Values[ii]));
val = NormalizeValue(val, 0, 255);
p[3] = (byte)(((double)pOrig[3] / 255.0) * val);
p -= 4;
pOrig -= 4;
}
}
}
}
bmp.UnlockBits(bmData);
bmpOrig.UnlockBits(bmDataOrig);
bmpOrig.Dispose();
bmpOrig = null;
return true;
}
catch
{
try
{
bmpOrig.UnlockBits(bmDataOrig);
bmp.UnlockBits(bmData);
}
catch
{
}
if (bmpOrig != null)
{
bmpOrig.Dispose();
bmpOrig = null;
}
}
return false;
}
public static unsafe bool makeEdgesTransparentVertSigma(Bitmap bmp, int nWidth1, int nWidth2)
{
BitmapData bmData = null;
Bitmap bmpOrig = null;
BitmapData bmDataOrig = null;
try
{
ArrayList Al = new ArrayList();
bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
System.IntPtr Scan0 = bmData.Scan0;
byte* p = (byte*)(void*)Scan0;
bmpOrig = (Bitmap)bmp.Clone();
bmDataOrig = bmpOrig.LockBits(new Rectangle(0, 0, bmpOrig.Width, bmpOrig.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
System.IntPtr Scan0Orig = bmDataOrig.Scan0;
byte* pOrig = (byte*)(void*)Scan0Orig;
int lp = 0;
for (int col = 0; col < bmp.Width; col++)
{
for (int row = 0; row < bmp.Height; row++)
{
p = (byte*)(void*)Scan0;
p += (row * bmp.Width * 4) + (col * 4);
if ((p[3] > 0) && (lp == 0))
{
Al.Add(new Point(col, row));
}
lp = (int)p[3];
}
lp = 0;
}
Al.TrimToSize();
double[] Values = getVector((nWidth1 * 2) + 1);
if (Values.Length / 2 == nWidth1)
{
for (int i = 0; i < Al.Count; i++)
{
Point pt1 = (Point)Al[i];
p = (byte*)(void*)Scan0;
pOrig = (byte*)(void*)Scan0Orig;
if (pt1.Y <= bmp.Height - nWidth1)
{
p += (pt1.Y * bmp.Width * 4) + (pt1.X * 4);
pOrig += (pt1.Y * bmpOrig.Width * 4) + (pt1.X * 4);
for (int ii = 0; ii < nWidth1; ii++)
{
int val = (int)Math.Max(0, (int)(255.0 * Values[ii]));
val = NormalizeValue(val, 0, 255);
p[3] = (byte)(((double)pOrig[3] / 255.0) * val);
p += (bmp.Width * 4);
pOrig += (bmpOrig.Width * 4);
}
}
}
}
Al.Clear();
lp = 0;
for (int col = 0; col < bmp.Width; col++)
{
for (int row = bmp.Height - 1; row >= 0; row--)
{
p = (byte*)(void*)Scan0;
p += (row * bmp.Width * 4) + (col * 4);
if ((p[3] > 0) && (lp == 0))
{
Al.Add(new Point(col, row));
}
lp = (int)p[3];
}
lp = 0;
}
Al.TrimToSize();
Values = getVector((nWidth2 * 2) + 1);
if (Values.Length / 2 == nWidth2)
{
for (int i = 0; i < Al.Count; i++)
{
Point pt1 = (Point)Al[i];
p = (byte*)(void*)Scan0;
pOrig = (byte*)(void*)Scan0Orig;
if (pt1.Y >= (nWidth2 - 1))
{
p = (byte*)(void*)Scan0;
p += ((nWidth2) * bmp.Width * -4) + ((pt1.Y + nWidth2) * bmp.Width * 4) + (pt1.X * 4);
pOrig = (byte*)(void*)Scan0Orig;
pOrig += ((nWidth2) * bmpOrig.Width * -4) + ((pt1.Y + nWidth2) * bmpOrig.Width * 4) + (pt1.X * 4);
for (int ii = 0; ii < nWidth2; ii++)
{
int val = (int)Math.Max(0, (int)(255.0 * Values[ii]));
val = NormalizeValue(val, 0, 255);
p[3] = (byte)(((double)pOrig[3] / 255.0) * val);
p -= (bmp.Width * 4);
pOrig -= (bmpOrig.Width * 4);
}
}
}
}
bmp.UnlockBits(bmData);
bmpOrig.UnlockBits(bmDataOrig);
bmpOrig.Dispose();
bmpOrig = null;
return true;
}
catch
{
try
{
bmpOrig.UnlockBits(bmDataOrig);
bmp.UnlockBits(bmData);
}
catch
{
}
if (bmpOrig != null)
{
bmpOrig.Dispose();
bmpOrig = null;
}
}
return false;
}
public static bool MergeBmp(Bitmap f, Bitmap z, Bitmap b)
{
BitmapData bmData = f.LockBits(new Rectangle(0, 0, f.Width, f.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
BitmapData bmData2 = z.LockBits(new Rectangle(0, 0, z.Width, z.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
BitmapData bmDataf = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
int stride = bmData.Stride;
System.IntPtr Scan0 = bmData.Scan0;
System.IntPtr Scan02 = bmData2.Scan0;
System.IntPtr Scanf = bmDataf.Scan0;
unsafe
{
byte* p = (byte*)(void*)Scan0;
byte* pf = (byte*)(void*)Scan02;
byte* pff = (byte*)(void*)Scanf;
int nOffset = stride - b.Width * 4;
int nWidth = b.Width;
int nHeight = b.Height;
for (int y = 0; y < nHeight; y++)
{
for (int x = 0; x < nWidth; x++)
{
if (pf[3] <= pff[3])
{
p[3] = pf[3];
}
else
{
p[3] = pff[3];
}
p += 4;
pf += 4;
pff += 4;
}
p += nOffset;
pf += nOffset;
pff += nOffset;
}
}
f.UnlockBits(bmData);
z.UnlockBits(bmData2);
b.UnlockBits(bmDataf);
return true;
}
public static void Blur(ref Bitmap bmp, bool useSigma, int width1, int width2, bool auto, int growth1, int growth2)
{
Bitmap bmp2 = null;
Bitmap bmp3 = null;
try
{
bmp2 = bmp.Clone() as Bitmap;
bmp3 = bmp.Clone() as Bitmap;
if (useSigma)
{
makeEdgesTransparentHorzSigma(bmp2, width1, width2);
makeEdgesTransparentVertSigma(bmp3, width1, width2);
}
else
{
makeEdgesTransparentHorz(bmp2, width1, width2, growth1, growth2, auto);
makeEdgesTransparentVert(bmp3, width1, width2, growth1, growth2, auto);
}
MergeBmp(bmp, bmp2, bmp3);
}
catch (Exception ex)
{
if (ex != null) {}
}
finally
{
if (bmp2 != null)
{
bmp2.Dispose();
}
if (bmp3 != null)
{
bmp3.Dispose();
}
}
}
}
}