Sharpen on a Bitmap using C#

I want to put a sharpen filter on an image. I have found a web with short tutorial. I tried to do it in C# so here is my code. Anyway, I tried to find out why it is not working. I do not know if I am doing something wrong, if yes, please advise me what to do to make it work as it should be. Thanks

public static Bitmap sharpen(Bitmap image) { Bitmap sharpenImage = new Bitmap(image.Width, image.Height); int filterWidth = 3; int filterHeight = 3; int w = image.Width; int h = image.Height; double[,] filter = new double[filterWidth, filterHeight]; filter[0, 0] = filter[0, 1] = filter[0, 2] = filter[1, 0] = filter[1, 2] = filter[2, 0] = filter[2, 1] = filter[2, 2] = -1; filter[1, 1] = 9; double factor = 1.0; double bias = 0.0; Color[,] result = new Color[image.Width, image.Height]; for (int x = 0; x < w; ++x) { for (int y = 0; y < h; ++y) { double red = 0.0, green = 0.0, blue = 0.0; Color imageColor = image.GetPixel(x, y); for (int filterX = 0; filterX < filterWidth; filterX++) { for (int filterY = 0; filterY < filterHeight; filterY++) { int imageX = (x - filterWidth / 2 + filterX + w) % w; int imageY = (y - filterHeight / 2 + filterY + h) % h; red += imageColor.R * filter[filterX, filterY]; green += imageColor.G * filter[filterX, filterY]; blue += imageColor.B * filter[filterX, filterY]; } int r = Math.Min(Math.Max((int)(factor * red + bias), 0), 255); int g = Math.Min(Math.Max((int)(factor * green + bias), 0), 255); int b = Math.Min(Math.Max((int)(factor * blue + bias), 0), 255); result[x, y] = Color.FromArgb(r, g, b); } } } for (int i = 0; i < w; ++i) { for (int j = 0; j < h; ++j) { sharpenImage.SetPixel(i, j, result[i, j]); } } return sharpenImage; }

-------------Problems Reply------------

public static Bitmap sharpen(Bitmap image)
{
Bitmap sharpenImage = new Bitmap(image.Width, image.Height);

int filterWidth = 3;
int filterHeight = 3;
int w = image.Width;
int h = image.Height;

double[,] filter = new double[filterWidth, filterHeight];

filter[0, 0] = filter[0, 1] = filter[0, 2] = filter[1, 0] = filter[1, 2] = filter[2, 0] = filter[2, 1] = filter[2, 2] = -1;
filter[1, 1] = 9;

double factor = 1.0;
double bias = 0.0;

Color[,] result = new Color[image.Width, image.Height];

for (int x = 0; x < w; ++x)
{
for (int y = 0; y < h; ++y)
{
double red = 0.0, green = 0.0, blue = 0.0;

//=====[REMOVE LINES]========================================================
// Color must be read per filter entry, not per image pixel.
Color imageColor = image.GetPixel(x, y);
//===========================================================================

for (int filterX = 0; filterX < filterWidth; filterX++)
{
for (int filterY = 0; filterY < filterHeight; filterY++)
{
int imageX = (x - filterWidth / 2 + filterX + w) % w;
int imageY = (y - filterHeight / 2 + filterY + h) % h;

//=====[INSERT LINES]========================================================
// Get the color here - once per fiter entry and image pixel.
Color imageColor = image.GetPixel(imageX, imageY);
//===========================================================================

red += imageColor.R * filter[filterX, filterY];
green += imageColor.G * filter[filterX, filterY];
blue += imageColor.B * filter[filterX, filterY];
}
int r = Math.Min(Math.Max((int)(factor * red + bias), 0), 255);
int g = Math.Min(Math.Max((int)(factor * green + bias), 0), 255);
int b = Math.Min(Math.Max((int)(factor * blue + bias), 0), 255);

result[x, y] = Color.FromArgb(r, g, b);
}
}
}
for (int i = 0; i < w; ++i)
{
for (int j = 0; j < h; ++j)
{
sharpenImage.SetPixel(i, j, result[i, j]);
}
}
return sharpenImage;
}

I took Daniel's answer and modified it for performance, by using BitmapData class, since using GetPixel/SetPixel is very expensive and inappropriate for performance-hungry systems. It works exactly the same as the previous solution and can be used instead.

public static Bitmap Sharpen(Bitmap image)
{
Bitmap sharpenImage = (Bitmap)image.Clone();

int filterWidth = 3;
int filterHeight = 3;
int width = image.Width;
int height = image.Height;

// Create sharpening filter.
double[,] filter = new double[filterWidth, filterHeight];
filter[0, 0] = filter[0, 1] = filter[0, 2] = filter[1, 0] = filter[1, 2] = filter[2, 0] = filter[2, 1] = filter[2, 2] = -1;
filter[1, 1] = 9;

double factor = 1.0;
double bias = 0.0;

Color[,] result = new Color[image.Width, image.Height];

// Lock image bits for read/write.
BitmapData pbits = sharpenImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

// Declare an array to hold the bytes of the bitmap.
int bytes = pbits.Stride * height;
byte[] rgbValues = new byte[bytes];

// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(pbits.Scan0, rgbValues, 0, bytes);

int rgb;
// Fill the color array with the new sharpened color values.
for (int x = 0; x < width; ++x)
{
for (int y = 0; y < height; ++y)
{
double red = 0.0, green = 0.0, blue = 0.0;

for (int filterX = 0; filterX < filterWidth; filterX++)
{
for (int filterY = 0; filterY < filterHeight; filterY++)
{
int imageX = (x - filterWidth / 2 + filterX + width) % width;
int imageY = (y - filterHeight / 2 + filterY + height) % height;

rgb = imageY * pbits.Stride + 3 * imageX;

red += rgbValues[rgb + 2] * filter[filterX, filterY];
green += rgbValues[rgb + 1] * filter[filterX, filterY];
blue += rgbValues[rgb + 0] * filter[filterX, filterY];
}
int r = Math.Min(Math.Max((int)(factor * red + bias), 0), 255);
int g = Math.Min(Math.Max((int)(factor * green + bias), 0), 255);
int b = Math.Min(Math.Max((int)(factor * blue + bias), 0), 255);

result[x, y] = Color.FromArgb(r, g, b);
}
}
}

// Update the image with the sharpened pixels.
for (int x = 0; x < width; ++x)
{
for (int y = 0; y < height; ++y)
{
rgb = y * pbits.Stride + 3 * x;

rgbValues[rgb + 2] = result[x, y].R;
rgbValues[rgb + 1] = result[x, y].G;
rgbValues[rgb + 0] = result[x, y].B;
}
}

// Copy the RGB values back to the bitmap.
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, pbits.Scan0, bytes);
// Release image bits.
sharpenImage.UnlockBits(pbits);

return sharpenImage;
}

This will create a softer sharpening effect. You can expand the filter array if you need to, or change the 16 to something larger, but I found this isn't as harsh as the one you have.

const int filterWidth = 5;
const int filterHeight = 5;

double[,] filter = new double[filterWidth,filterHeight] {
{ -1, -1, -1, -1, -1 },
{ -1, 2, 2, 2, -1 },
{ -1, 2, 16, 2, -1 },
{ -1, 2, 2, 2, -1 },
{ -1, -1, -1, -1, -1 }
};

double factor = 1.0 / 16.0;

I combined niaher's and David's answer and fixed the "bias" property. Now you can pass a "strength" between 0.0 and 1.0 to the Sharpen() function.

/// <summary>
/// Sharpens the specified image.
/// </summary>
/// <param name="image">The image.</param>
/// <param name="strength">The strength between 0.0 and 1.0.</param>
/// <returns></returns>
public static Bitmap Sharpen(Image image, double strength)
{
using (var bitmap = image as Bitmap)
{
if (bitmap != null)
{
var sharpenImage = bitmap.Clone() as Bitmap;

int width = image.Width;
int height = image.Height;

// Create sharpening filter.
const int filterWidth = 5;
const int filterHeight = 5;

var filter = new double[,]
{
{-1, -1, -1, -1, -1},
{-1, 2, 2, 2, -1},
{-1, 2, 16, 2, -1},
{-1, 2, 2, 2, -1},
{-1, -1, -1, -1, -1}
};

double bias = 1.0 - strength;
double factor = strength/16.0;

var result = new Color[image.Width,image.Height];

// Lock image bits for read/write.
if (sharpenImage != null)
{
BitmapData pbits = sharpenImage.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite,
PixelFormat.Format24bppRgb);

// Declare an array to hold the bytes of the bitmap.
int bytes = pbits.Stride*height;
var rgbValues = new byte[bytes];

// Copy the RGB values into the array.
Marshal.Copy(pbits.Scan0, rgbValues, 0, bytes);

int rgb;
// Fill the color array with the new sharpened color values.
for (int x = 0; x < width; ++x)
{
for (int y = 0; y < height; ++y)
{
double red = 0.0, green = 0.0, blue = 0.0;

for (int filterX = 0; filterX < filterWidth; filterX++)
{
for (int filterY = 0; filterY < filterHeight; filterY++)
{
int imageX = (x - filterWidth/2 + filterX + width)%width;
int imageY = (y - filterHeight/2 + filterY + height)%height;

rgb = imageY*pbits.Stride + 3*imageX;

red += rgbValues[rgb + 2]*filter[filterX, filterY];
green += rgbValues[rgb + 1]*filter[filterX, filterY];
blue += rgbValues[rgb + 0]*filter[filterX, filterY];
}

rgb = y*pbits.Stride + 3*x;

int r = Math.Min(Math.Max((int) (factor*red + (bias*rgbValues[rgb + 2])), 0), 255);
int g = Math.Min(Math.Max((int) (factor*green + (bias*rgbValues[rgb + 1])), 0), 255);
int b = Math.Min(Math.Max((int) (factor*blue + (bias*rgbValues[rgb + 0])), 0), 255);

result[x, y] = Color.FromArgb(r, g, b);
}
}
}

// Update the image with the sharpened pixels.
for (int x = 0; x < width; ++x)
{
for (int y = 0; y < height; ++y)
{
rgb = y*pbits.Stride + 3*x;

rgbValues[rgb + 2] = result[x, y].R;
rgbValues[rgb + 1] = result[x, y].G;
rgbValues[rgb + 0] = result[x, y].B;
}
}

// Copy the RGB values back to the bitmap.
Marshal.Copy(rgbValues, 0, pbits.Scan0, bytes);
// Release image bits.
sharpenImage.UnlockBits(pbits);
}

return sharpenImage;
}
}
return null;
}

Ok, fixed the problem with distored edges. Here´s the updated one:

/// <summary>
/// Sharpens the specified image.
/// </summary>
/// <param name="image">The image.</param>
/// <param name="strength">The strength.</param>
/// <returns></returns>
public static Bitmap Sharpen(Image image, double strength)
{
using (var bitmap = image as Bitmap)
{
if (bitmap != null)
{
var sharpenImage = bitmap.Clone() as Bitmap;

int width = image.Width;
int height = image.Height;

// Create sharpening filter.
const int filterSize = 5;

var filter = new double[,]
{
{-1, -1, -1, -1, -1},
{-1, 2, 2, 2, -1},
{-1, 2, 16, 2, -1},
{-1, 2, 2, 2, -1},
{-1, -1, -1, -1, -1}
};

double bias = 1.0 - strength;
double factor = strength/16.0;

const int s = filterSize/2;

var result = new Color[image.Width,image.Height];

// Lock image bits for read/write.
if (sharpenImage != null)
{
BitmapData pbits = sharpenImage.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite,
PixelFormat.Format24bppRgb);

// Declare an array to hold the bytes of the bitmap.
int bytes = pbits.Stride*height;
var rgbValues = new byte[bytes];

// Copy the RGB values into the array.
Marshal.Copy(pbits.Scan0, rgbValues, 0, bytes);

int rgb;
// Fill the color array with the new sharpened color values.
for (int x = s; x < width - s; x++)
{
for (int y = s; y < height - s; y++)
{
double red = 0.0, green = 0.0, blue = 0.0;

for (int filterX = 0; filterX < filterSize; filterX++)
{
for (int filterY = 0; filterY < filterSize; filterY++)
{
int imageX = (x - s + filterX + width)%width;
int imageY = (y - s + filterY + height)%height;

rgb = imageY*pbits.Stride + 3*imageX;

red += rgbValues[rgb + 2]*filter[filterX, filterY];
green += rgbValues[rgb + 1]*filter[filterX, filterY];
blue += rgbValues[rgb + 0]*filter[filterX, filterY];
}

rgb = y * pbits.Stride + 3 * x;

int r = Math.Min(Math.Max((int)(factor * red + (bias * rgbValues[rgb + 2])), 0), 255);
int g = Math.Min(Math.Max((int)(factor * green + (bias * rgbValues[rgb + 1])), 0), 255);
int b = Math.Min(Math.Max((int)(factor * blue + (bias * rgbValues[rgb + 0])), 0), 255);

result[x, y] = Color.FromArgb(r, g, b);
}
}
}

// Update the image with the sharpened pixels.
for (int x = s; x < width - s; x++)
{
for (int y = s; y < height - s; y++)
{
rgb = y*pbits.Stride + 3*x;

rgbValues[rgb + 2] = result[x, y].R;
rgbValues[rgb + 1] = result[x, y].G;
rgbValues[rgb + 0] = result[x, y].B;
}
}

// Copy the RGB values back to the bitmap.
Marshal.Copy(rgbValues, 0, pbits.Scan0, bytes);
// Release image bits.
sharpenImage.UnlockBits(pbits);
}

return sharpenImage;
}
}
return null;
}

Category:c# Views:0 Time:2009-05-24

Related post

  • Android image sharpening, saturation, hue, brightness, and contrast 2011-06-24

    I'm trying to create an app that will allow me to adjust the hue, saturation, brightness, contrast, and sharpness of an image by adjusting the seekbars for each of the above fields. like at I have no idea how to do this and I can't find any tutorials

  • Sharpen Image Filter 2011-12-23

    I have code that takes an image saved on my computer and processes into a grayscale, smoothed gray, and canny edge image. What I would like it to do is sharpen the image by adding some type of filter to the image and then convert to gray and canny ed

  • Simple Frameworks for Displaying Bitmaps and Handling Button Presses 2008-08-23

    We have a set of applications that basically display a bunch of bitmaps and text, then allow user to press "buttons" (certain bitmaps) that cause actions to occur. We currently have these implemented using DirectX and a bunch of code to place the bit

  • How do you reference a bitmap on the stage in actionscript? 2008-09-04

    How do you reference a bitmap on the stage in flash using actionscript 3? I have a bitmap on the stage in flash and at the end of the movie I would like to swap it out for the next in the sequence before the movie loops. in my library i have 3 images

  • GDI+ DrawImage() with transparent bitmap to a printer 2008-09-15

    Does anybody have any pointers on how to successfully draw a bitmap that has an alpha channel using Graphics::DrawImage() when the Graphics context is created based on a printer HDC? The printer drivers don't generally support alpha blending - so is

  • Load a WPF BitmapImage from a System.Drawing.Bitmap 2008-09-18

    I have an instance of a System.Drawing.Bitmap and would like to make it available to my WPF app in the form of a System.Windows.Media.Imaging.BitmapImage. What would be the best approach for this? --------------Solutions------------- How about loadin

  • GDI+ System.Drawing.Bitmap gives error Parameter is not valid intermittently 2008-09-25

    I have some C# code in an ASP.Net application that does this: Bitmap bmp = new Bitmap(1184, 1900); And occasionally it throws an exception "Parameter is not valid". Now i've been googling around and apparently GDI+ is infamous for throwing random exc

  • How to create a very big bitmap in C++/MFC / GDI 2008-09-26

    I'd like to be able to create a large (say 20,000 x 20,000) pixel bitmap in a C++ MFC application, using a CDC derived class to write to the bitmap. I've tried using memory DCs as described in the MSDN docs, but these appear to be restricted to sizes

  • How to draw ARGB bitmap using GDI+? 2008-10-08

    I have valid HBITMAP handle of ARGB type. How to draw it using GDI+? I've tried method: graphics.DrawImage(Bitmap::FromHBITMAP(m_hBitmap, NULL), 0, 0); But it doesn't use alpha channel. --------------Solutions------------- I've got working sample: //

  • Reading RAW image files as GDI+ bitmaps 2008-10-22

    Is there a good way to read RAW image files (especially Canon CR2 and Adobe DNG files) as GDI+ bitmaps that is reasonably fast? I found an example running under WPF that would read an image using any installed image codec and then display it in an im

  • How could I insert a bitmap or other image objects in a CListCtrl in MFC? 2008-10-23

    I want to list the thumbnails of a set of photos in a listctrl. But the only way to achieve this is to use the setImageList method to bind a image list to the CListCtrl object and insert items like this: InsertItem (int nItem, LPCTSTR lpszitem, int n

  • Convert Bitmap to Polygon - (Reverse-Rasterizing) 2008-11-10

    Given a bitmap image with some blots of solid color on it, what algorithm would you employ to construct polygons in the same shape as the blots? This can be done in multiple steps: a high-resolution polygon could be later cut down by a best fit algor

  • Applying PixelShaders on offscreen Bitmaps 2008-11-17

    i'm currently experimenting using PixelShaders introduced with .net 3.5 sp1 to improve image processing performance. everything is much faster , but til yet i just had effects applied to some elements in my wpf forms, that i actually want to avoid. w

  • OutOfMemoryException When Creating a Large Bitmap in CF.NET 2008-11-18

    My compact framework application creates a smooth-scrolling list by rendering all the items to a large bitmap surface, then copying that bitmap to an offset position on the screen so that only the appropriate items show. Older versions only rendered

  • How to draw 32-bit alpha channel bitmaps? 2008-11-20

    I need to create a custom control to display bmp images with alpha channel. The background can be painted in different colors and the images have shadows so I need to truly "paint" the alpha channel. Does anybody know how to do it? I also want if pos

  • How to access each byte in a bitmap image 2008-12-03

    Say I have a bitmap image, is it possible to iterate through all the individual bytes in the image? If yes, how? --------------Solutions------------- I found this: http://channel9.msdn.com/forums/TechOff/108813-Bitmap-to-byte-array/ Saying that you c

  • convert bitmap to byte array 2008-12-09

    How can I convert a bitmap to a byte array in c++ WITHOUT the .net framework? --------------Solutions------------- If you’re using Windows, you can use GetDIBits to retrieve the bitmap data. If your bitmap is a device independent bitmap, you can acce

  • Strange problem about conversion between GDI+ to GDI: Bitmap and HBitmap 2008-12-10

    I want to convert gdi+ Bitmap into gdi object HBitmap. I am using the following method: Bitmap* img = new Bitmap(XXX); // lots of codes... HBITMAP temp; Color color; img->GetHBITMAP(color, &temp); the img object is drawing on a dialog. when th

  • Capture the Screen into a Bitmap 2008-12-12

    I want to capture the screen in my code to get an image - like using the 'print screen' button on the keyboard . Does anyone have an idea how to do this? I have no starting point. --------------Solutions------------- If using the .NET 2.0 (or later)

Copyright (C) dskims.com, All Rights Reserved.

processed in 0.110 (s). 11 q(s)