Sharpen on a Bitmap using C# - 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;
}

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;
}

hi i edit the code a litle bit and add two other matrices
for me this works now perfect
/// <summary>
/// Sharpens the specified image.
/// </summary>
/// <param name="image">The image.</param>
/// <param name="strength">strength erwartet werte zwische 0 - 99</param>
/// <returns></returns>
public Bitmap Sharpen(Image image, whichMatrix welcheMatrix , double strength)
{
double FaktorKorrekturWert = 0;
//strenght muß für den jeweiligen filter angepasst werden
switch (welcheMatrix)
{
case whichMatrix.Gaussian3x3:
//diese Matrix benötigt einen strenght Wert von 0 bis -9.9 default ist -2.5
//und einen korekturwert von 16
strength = (strength * -1) / 10;
FaktorKorrekturWert = 16;
break;
case whichMatrix.Mean3x3:
//diese Matrix benötigt einen strenght Wert von 0 bis -9 default ist -2.25
//und einen Korrekturwert von 10
strength = strength * -9 / 100;
FaktorKorrekturWert = 10;
break;
case whichMatrix.Gaussian5x5Type1:
//diese Matrix benötigt einen strenght Wert von 0 bis 2.5 default ist 1.25
//und einen Korrekturwert von 12
strength = strength * 2.5 / 100;
FaktorKorrekturWert = 12;
break;
default:
break;
}
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.
var filter = Matrix(welcheMatrix);
//const int filterSize = 3; // wenn die Matrix 3 Zeilen und 3 Spalten besitzt dann 3 bei 4 = 4 usw.
int filterSize = filter.GetLength(0);
double bias = 1.0 - strength;
double factor = strength / FaktorKorrekturWert;
//const int s = filterSize / 2;
int s = filterSize / 2; // Filtersize ist keine Constante mehr darum wurde der befehl const entfernt
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] = System.Drawing.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;
}
public enum whichMatrix
{
Gaussian3x3,
Mean3x3,
Gaussian5x5Type1
}
private double[,] Matrix(whichMatrix welcheMatrix)
{
double[,] selectedMatrix = null;
switch (welcheMatrix)
{
case whichMatrix.Gaussian3x3:
selectedMatrix = new double[,]
{
{ 1, 2, 1, },
{ 2, 4, 2, },
{ 1, 2, 1, },
};
break;
case whichMatrix.Gaussian5x5Type1:
selectedMatrix = new double[,]
{
{-1, -1, -1, -1, -1},
{-1, 2, 2, 2, -1},
{-1, 2, 16, 2, -1},
{-1, 2, -1, 2, -1},
{-1, -1, -1, -1, -1}
};
break;
case whichMatrix.Mean3x3:
selectedMatrix =new double[,]
{
{ 1, 1, 1, },
{ 1, 1, 1, },
{ 1, 1, 1, },
};
break;
}
return selectedMatrix;
}

Related

Please show how to save bitmap file to directory

This code is about changing contrast parameter for jpg files via bitmap. I'm stuck in the point where I'm saving the result. I'm taking a photo (string s = ld[0];), then changing it and then trying to save as new (resultBitmap.Save(project.Directory + "_new.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);)
Please tell me what am I doing wrong! It doesn't save a new file to directory.
Random rnd = new Random();
int threshold = rnd.Next(16,28);
string d = project.Directory + #"\avito\photos\";
string[] ld = System.IO.Directory.GetFiles(d, "*.*", System.IO.SearchOption.AllDirectories);
string s = ld[0];
Bitmap sourceBitmap = new Bitmap(System.Drawing.Image.FromFile(s)); //
System.Drawing.Imaging.BitmapData sourceData = sourceBitmap.LockBits(new Rectangle(0, 0,
sourceBitmap.Width, sourceBitmap.Height),
System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
byte[] pixelBuffer = new byte [sourceData.Stride * sourceData.Height];
System.Runtime.InteropServices.Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length);
sourceBitmap.UnlockBits(sourceData);
double contrastLevel = Math.Pow((100.0 + threshold) / 100.0, 2);
double blue = 0;
double green = 0;
double red = 0;
for (int k = 0; k + 4 < pixelBuffer.Length; k += 4) {
blue = ((((pixelBuffer[k] / 255.0) - 0.5) * contrastLevel) + 0.5) * 255.0;
green = ((((pixelBuffer[k + 1] / 255.0) - 0.5) * contrastLevel) + 0.5) * 255.0;
red = ((((pixelBuffer[k + 2] / 255.0) - 0.5) *
contrastLevel) + 0.5) * 255.0;
if (blue > 255)
{ blue = 255; }
else if (blue < 0)
{ blue = 0; }
if (green > 255)
{ green = 255; }
else if (green < 0)
{ green = 0; }
if (red > 255)
{ red = 255; }
else if (red < 0)
{ red = 0; }
pixelBuffer[k] = (byte)blue;
pixelBuffer[k + 1] = (byte)green;
pixelBuffer[k + 2] = (byte)red;
}
Bitmap resultBitmap = new Bitmap(sourceBitmap.Width, sourceBitmap.Height);
System.Drawing.Imaging.BitmapData resultData = resultBitmap.LockBits(new Rectangle(0, 0,
resultBitmap.Width, resultBitmap.Height),
System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
System.Runtime.InteropServices.Marshal.Copy(pixelBuffer, 0, resultData.Scan0, pixelBuffer.Length);
resultBitmap.UnlockBits(resultData);
resultBitmap.Save(project.Directory + "_new.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
resultBitmap.Dispose();
sourceBitmap.Dispose();

Why does this edge detector not work correctly when bitmap width not divisible by 4?

Using the Sobel edge detector code below I find that the output bitmap has a diagonal line of zero values superimposed over detected edges if the input bitmap has a width not divisible by 4. The red square marked in the output bitmap at co-ords (80,80) is broken up and incorrectly placed in this case. Why is this and how can I make the code work with any bitmap width?
private Bitmap SobelEdgeDetect2(Bitmap original, byte Threshold = 128)
{
// https://stackoverflow.com/questions/16747257/edge-detection-with-lockbits-c-sharp
int width = original.Width;
int height = original.Height;
int BitsPerPixel = Image.GetPixelFormatSize(original.PixelFormat);
int OneColorBits = BitsPerPixel / 8;
BitmapData bmpData = original.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, original.PixelFormat);
int position;
int[,] gx = new int[,] { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } };
int[,] gy = new int[,] { { 1, 2, 1 }, { 0, 0, 0 }, { -1, -2, -1 } };
Bitmap dstBmp = new Bitmap(width, height, original.PixelFormat);
BitmapData dstData = dstBmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, dstBmp.PixelFormat);
int byteCount = dstData.Stride * dstBmp.Height;
byte[] input = new byte[byteCount];
byte[] processed = new byte[byteCount];
IntPtr ptr = bmpData.Scan0;
IntPtr dst = dstData.Scan0;
Marshal.Copy(ptr, input, 0, input.Length);
Marshal.Copy(dst,processed, 0, input.Length);
int BlackPoints = 0;
int WhitePoints = 0;
for (int i = 1; i < height - 1; i++) // y
{
for (int j = 1; j < width - 1; j++) // x
{
int NewX = 0, NewY = 0;
for (int ii = 0; ii < 3; ii++)
{
for (int jj = 0; jj < 3; jj++)
{
int I = i + ii - 1;
int J = j + jj - 1;
byte Current = input[(I * (width) + J) * OneColorBits];
NewX += gx[ii, jj] * Current;
NewY += gy[ii, jj] * Current;
}
}
position = (i * (width) + j) * OneColorBits;
if (NewX * NewX + NewY * NewY > Threshold * Threshold)
{
processed[position] = 255;
processed[position + 1] = 255;
processed[position + 2] = 255;
WhitePoints++;
}
else
{
processed[position] = 0;
processed[position + 1] = 0;
processed[position + 2] = 0;
BlackPoints++;
}
if (j >= 78 && j <= 82 && i >= 78 && i <= 82)
{
processed[position] = 0;
processed[position + 1] = 0;
processed[position + 2] = 255;
}
}
}
Marshal.Copy(processed, 0, dst, input.Length);
dstBmp.UnlockBits(dstData);
return dstBmp;
}
For a 201 pixel wide bitmap, dstData.Stride was 604. For a 200 pixel wide bitmap dstData.Stride was 612, which explains why width had to be divisible by 4 for my code.
Replacing
position = (i * (width) + j) * OneColorBits;
by
position = i * dstData.Stride + j * OneColorBits;
and
byte Current = input[(I * (width) + J) * OneColorBits];
by
byte Current = input[I * dstData.Stride + J * OneColorBits];
fixed the problem.

C# Bitmap blur with transparent background

I'd like to add blur effect on my text. In order to do this, I'm using this method:
public static Bitmap ConvolutionFilter(Bitmap sourceBitmap, double[,] filterMatrix, double factor = 1, int bias = 0)
{
BitmapData sourceData = sourceBitmap.LockBits(new Rectangle(0, 0,
sourceBitmap.Width, sourceBitmap.Height),
ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
byte[] pixelBuffer = new byte[sourceData.Stride * sourceData.Height];
byte[] resultBuffer = new byte[sourceData.Stride * sourceData.Height];
Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length);
sourceBitmap.UnlockBits(sourceData);
double blue = 0.0;
double green = 0.0;
double red = 0.0;
int filterWidth = filterMatrix.GetLength(1);
int filterHeight = filterMatrix.GetLength(0);
int filterOffset = (filterWidth - 1) / 2;
int calcOffset = 0;
int byteOffset = 0;
for (int offsetY = filterOffset; offsetY < sourceBitmap.Height - filterOffset; offsetY++)
{
for (int offsetX = filterOffset; offsetX < sourceBitmap.Width - filterOffset; offsetX++)
{
blue = 0;
green = 0;
red = 0;
byteOffset = offsetY * sourceData.Stride + offsetX * 4;
for (int filterY = -filterOffset; filterY <= filterOffset; filterY++)
{
for (int filterX = -filterOffset; filterX <= filterOffset; filterX++)
{
calcOffset = byteOffset +
(filterX * 4) +
(filterY * sourceData.Stride);
blue += (double)(pixelBuffer[calcOffset]) *
filterMatrix[filterY + filterOffset,
filterX + filterOffset];
green += (double)(pixelBuffer[calcOffset + 1]) *
filterMatrix[filterY + filterOffset,
filterX + filterOffset];
red += (double)(pixelBuffer[calcOffset + 2]) *
filterMatrix[filterY + filterOffset,
filterX + filterOffset];
}
}
blue = factor * blue + bias;
green = factor * green + bias;
red = factor * red + bias;
blue = (blue > 255 ? 255 : (blue < 0 ? 0 : blue));
green = (green > 255 ? 255 : (green < 0 ? 0 : green));
red = (red > 255 ? 255 : (red < 0 ? 0 : red));
resultBuffer[byteOffset] = (byte)(blue);
resultBuffer[byteOffset + 1] = (byte)(green);
resultBuffer[byteOffset + 2] = (byte)(red);
resultBuffer[byteOffset + 3] = 255;
}
}
Bitmap resultBitmap = new Bitmap(sourceBitmap.Width, sourceBitmap.Height);
BitmapData resultData = resultBitmap.LockBits(new Rectangle(0, 0, resultBitmap.Width, resultBitmap.Height), ImageLockMode.WriteOnly,
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Marshal.Copy(resultBuffer, 0, resultData.Scan0, resultBuffer.Length);
resultBitmap.UnlockBits(resultData);
return resultBitmap;
}
Code from: https://softwarebydefault.com/2013/06/09/image-blur-filters/
This metod blurs my text, but it changes transparent background to black background.
Before:
After:
Text is a Bitmap rendered by Graphics.DrawText(...) method.
I'd like to get blurred text but on transparent background. How can I achive it?
You are setting the alpha value to 255 (not transparent) in the filter.
resultBuffer[byteOffset + 3] = 255; // Fully opaque - not transparent at all
If you treat the alpha component just like the color components (red/gree/blue), I think you'll get what you're after.

Image filter too slow

I need a specific rewrite of this code snippet to run it faster..
I can barely get 5fps out off this code and I need 30fps to run it smoothly..
Need help on how to rewrite it to run faster..
I'm using it as a filter on my media player to enhance poor frames in the media, so it look a little better on higher resolutions..
public static Bitmap MedianFilter(this Bitmap sourceBitmap, int matrixSize, int bias = 0, bool grayscale = false)
{
BitmapData sourceData = sourceBitmap.LockBits(new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
byte[] pixelBuffer = new byte[sourceData.Stride * sourceData.Height];
byte[] resultBuffer = new byte[sourceData.Stride * sourceData.Height];
Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length);
sourceBitmap.UnlockBits(sourceData);
if (grayscale == true)
{
float rgb = 0;
for (int k = 0; k < pixelBuffer.Length; k += 4)
{
rgb = pixelBuffer[k] * 0.11f;
rgb += pixelBuffer[k + 1] * 0.59f;
rgb += pixelBuffer[k + 2] * 0.3f;
pixelBuffer[k] = (byte)rgb;
pixelBuffer[k + 1] = pixelBuffer[k];
pixelBuffer[k + 2] = pixelBuffer[k];
pixelBuffer[k + 3] = 255;
}
}
int filterOffset = (matrixSize - 1) / 2;
int calcOffset = 0;
int byteOffset = 0;
List<int> neighbourPixels = new List<int>();
byte[] middlePixel;
for (int offsetY = filterOffset; offsetY < sourceBitmap.Height - filterOffset; offsetY++)
{
for (int offsetX = filterOffset; offsetX < sourceBitmap.Width - filterOffset; offsetX++)
{
byteOffset = offsetY * sourceData.Stride + offsetX * 4;
neighbourPixels.Clear();
for (int filterY = -filterOffset; filterY <= filterOffset; filterY++)
{
for (int filterX = -filterOffset; filterX <= filterOffset; filterX++)
{
calcOffset = byteOffset + (filterX * 4) + (filterY * sourceData.Stride);
neighbourPixels.Add(BitConverter.ToInt32(pixelBuffer, calcOffset));
}
}
neighbourPixels.Sort();
middlePixel = BitConverter.GetBytes(neighbourPixels[filterOffset]);
resultBuffer[byteOffset] = middlePixel[0];
resultBuffer[byteOffset + 1] = middlePixel[1];
resultBuffer[byteOffset + 2] = middlePixel[2];
resultBuffer[byteOffset + 3] = middlePixel[3];
}
}
Bitmap resultBitmap = new Bitmap(sourceBitmap.Width, sourceBitmap.Height);
BitmapData resultData = resultBitmap.LockBits(new Rectangle(0, 0, resultBitmap.Width, resultBitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
Marshal.Copy(resultBuffer, 0, resultData.Scan0, resultBuffer.Length);
resultBitmap.UnlockBits(resultData);
return resultBitmap;
}

RGB to Ycbcr conversion

I am doing image processing and I have a 3D array with the rgb values of an image and I am trying to convery those values into ycbcr ( I made a copy of the rgb array and called it ycbcr, and
public static void rgb2ycbcr(System.Drawing.Bitmap bmp, ref byte[, ,] arrayrgb, ref byte[, ,] arrayycbcr)
{
byte Y;
byte Cb;
byte Cr;
for (int i = 1; i < (bmp.Height + 1); i++) //don't worry about bmp.height/width+2 its for my project
{
for (int j = 1; j < (bmp.Width + 1); j++)
{
byte R = arrayrgb[i, j, 0];
byte G = arrayrgb[i, j, 1];
byte B = arrayrgb[i, j, 2];
Y = (byte)((0.257 * R) + (0.504 * G) + (0.098 * B) + 16);
Cb = (byte)(-(0.148 * R) - (0.291 * G) + (0.439 * B) + 128);
Cr = (byte)((0.439 * R) - (0.368 * G) - (0.071 * B) + 128);
arrayycbcr[i, j, 0] = Y;
arrayycbcr[i, j, 1] = Cb;
arrayycbcr[i, j, 2] = Cr;
}
}
}
the problem is I am not getting the same values for ycbcr as I would get in matlab when I use rgb2ycbcr, is there something missing in my code?
Faster and acurate code.
Output values ​​between 0 and 255 (JPG formula)
width = bmp.Width;
height = bmp.Height;
yData = new byte[width, height]; //luma
bData = new byte[width, height]; //Cb
rData = new byte[width, height]; //Cr
unsafe
{
BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, bmp.PixelFormat);
int heightInPixels = bitmapData.Height;
int widthInBytes = width * 3;
byte* ptrFirstPixel = (byte*)bitmapData.Scan0;
//Convert to YCbCr
for (int y = 0; y < heightInPixels; y++)
{
byte* currentLine = ptrFirstPixel + (y * bitmapData.Stride);
for (int x = 0; x < width; x++)
{
int xPor3 = x * 3;
float blue = currentLine[xPor3++];
float green = currentLine[xPor3++];
float red = currentLine[xPor3];
yData[x, y] = (byte)((0.299 * red) + (0.587 * green) + (0.114 * blue));
bData[x, y] = (byte)(128 - (0.168736 * red) + (0.331264 * green) + (0.5 * blue));
rData[x, y] = (byte)(128 + (0.5 * red) + (0.418688 * green) + (0.081312 * blue));
}
}
bmp.UnlockBits(bitmapData);
}
Convert R/G/B to uint before assign.
uint R =ConvertToUint(arrayrgb[i, j, 0]);
uint G =ConvertToUint(arrayrgb[i, j, 1]);
uint B =ConvertToUint(arrayrgb[i, j, 2]);

Categories

Resources