Friday, January 25, 2008

Unsharp Mask Algorithm in C#

Unsharp masking is a traditional darkroom technique that has proven very suitable for digital imaging.



Original


Unsharp Mask


The principle of unsharp masking is to create a blurred copy of the image and compare it to the underlying original. The difference in colour values between the two images is greatest for the pixels near sharp edges. When this difference is subtracted from the original image, the edges will be accentuated.



private unsafe Bitmap UnsharpMask(Bitmap img, double amount, double radius, double threshold)
{
if (amount > 500) amount = 500;
amount = amount * 2;
if (radius > 50) radius = 50;
radius = radius * 2;
if (threshold > 255) threshold = 255;

if (radius == 0)
{
img.Dispose();
return img;
}
int w = img.Width; int h = img.Height;
Bitmap imgBlur = new Bitmap(w, h);


ConvMatrix con = new ConvMatrix();
imgBlur = (Bitmap)img.Clone();
BitmapFilter.Conv3x3(imgBlur, con);

BitmapData imgdata1 = img.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
BitmapData imgdata2 = imgBlur.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

byte* p1 = (byte*)(void*)imgdata1.Scan0;
byte* p2 = (byte*)(void*)imgdata2.Scan0;

if (threshold > 0)
{
for (int x = 0; x < y =" 0;" imgrvalue =" p1[2];" imggvalue =" p1[1];" imgbvalue =" p1[0];" imgblurrvalue =" p2[2];" imgblurgvalue =" p2[1];" imgblurbvalue =" p2[0];" rnew =" (Math.Abs(imgRValue">= (int)threshold)
? Math.Max(0, Math.Min(255, ((int)amount * (imgRValue - imgBlurRValue)) + imgRValue)) : imgRValue;
int gNew = (Math.Abs(imgGValue - imgBlurGValue) >= (int)threshold)
? Math.Max(0, Math.Min(255, ((int)amount * (imgGValue - imgBlurGValue)) + imgGValue)) : imgGValue;
int bNew = (Math.Abs(imgBValue - imgBlurBValue) >= (int)threshold)
? Math.Max(0, Math.Min(255, ((int)amount * (imgBValue - imgBlurBValue)) + imgBValue)) : imgBValue;

if ((imgRValue != rNew) || (imgGValue != gNew) || (imgBValue != bNew))
{
p1[0] = (byte)bNew;
p1[1] = (byte)gNew;
p1[2] = (byte)rNew;

//img.SetPixel(x, y, System.Drawing.Color.FromArgb(rNew, gNew, bNew));
}
p1 = p1 + 3;
p2 = p2 + 3;


}
}

}
else
{
for (int x = 0; x < y =" 0;" imgrvalue =" p1[2];" imggvalue =" p1[1];" imgbvalue =" p1[0];" imgblurrvalue =" p2[2];" imgblurgvalue =" p2[1];" imgblurbvalue =" p2[0];" rnew =" ((int)amount"> 255)
rNew = 255;
else if (rNew < rnew =" 0;" gnew =" ((int)amount"> 255)
gNew = 255;
else if (gNew < gnew =" 0;" bnew =" ((int)amount"> 255)
bNew = 255;
else if (bNew < bnew =" 0;" p1 =" p1" p2 =" p2" topleft =" 1," topmid =" 2," topright =" 1;" midleft =" 2," pixel =" 4," midright =" 2;" bottomleft =" 1," bottommid =" 2," bottomright =" 1;" factor =" 16;" offset =" 0;" topleft =" TopMid" topright =" MidLeft" pixel =" MidRight" bottomleft =" BottomMid" bottomright =" nVal;" 0 ="=" bsrc =" (Bitmap)b.Clone();" bmdata =" b.LockBits(new" bmsrc =" bSrc.LockBits(new" stride =" bmData.Stride;" stride2 =" stride" scan0 =" bmData.Scan0;" srcscan0 =" bmSrc.Scan0;" p =" (byte*)(void*)Scan0;" psrc =" (byte*)(void*)SrcScan0;" noffset =" stride" nwidth =" b.Width" nheight =" b.Height" y =" 0;" x =" 0;" npixel =" ((((pSrc[2]" npixel =" 0;"> 255) nPixel = 255;

p[5 + stride] = (byte)nPixel;

nPixel = ((((pSrc[1] * m.TopLeft) + (pSrc[4] * m.TopMid) + (pSrc[7] * m.TopRight) +
(pSrc[1 + stride] * m.MidLeft) + (pSrc[4 + stride] * m.Pixel) + (pSrc[7 + stride] * m.MidRight) +
(pSrc[1 + stride2] * m.BottomLeft) + (pSrc[4 + stride2] * m.BottomMid) + (pSrc[7 + stride2] * m.BottomRight)) / m.Factor) + m.Offset);

if (nPixel < npixel =" 0;"> 255) nPixel = 255;

p[4 + stride] = (byte)nPixel;

nPixel = ((((pSrc[0] * m.TopLeft) + (pSrc[3] * m.TopMid) + (pSrc[6] * m.TopRight) +
(pSrc[0 + stride] * m.MidLeft) + (pSrc[3 + stride] * m.Pixel) + (pSrc[6 + stride] * m.MidRight) +
(pSrc[0 + stride2] * m.BottomLeft) + (pSrc[3 + stride2] * m.BottomMid) + (pSrc[6 + stride2] * m.BottomRight)) / m.Factor) + m.Offset);

if (nPixel < npixel =" 0;"> 255) nPixel = 255;

p[3 + stride] = (byte)nPixel;

p += 3;
pSrc += 3;
}
p += nOffset;
pSrc += nOffset;
}
}

b.UnlockBits(bmData);
bSrc.UnlockBits(bmSrc);

return true;
}


2 comments:

Unknown said...

does not work.

Fredrik said...

I've made a version that uses only safe code (a bit slower, but will work on web hosts with medium trust).

Here's a tutorial on
how to implement an unsharp filter in C#