Hello friends am trying to apply 3x3 median filter to fingerprint image of appxo 500x500.
I am using pointers to acess the image data. But i realy cant figure out how to do it. I know the concept very well, but if u guyz help me out in code it will be great help. I searched on net, but i dint get any help. thank you
public void medianfilter(Bitmap image)
{
Byte[,] rtemp = new Byte[3, 3];
Byte[,] gtemp = new Byte[3, 3];
Byte[,] btemp = new Byte[3, 3];
BitmapData data = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int stride = data.Stride;
unsafe {
byte* imgPtr = (byte*)(void*)(data.Scan0);
int nOffset = stride - image.Width * 3;
for (int i = 0; i < image.Width; i++)
{
for (int j = 0; j < image.Height; j++)
{
for (int x = i; x < 3 + i; x++)
{
for (int y = j; y < 3 + j; y++) {
rtemp[x, y] = imgPtr[0];
gtemp[x, y] = imgPtr[1];
btemp[x, y] = imgPtr[2];
imgPtr += 3; } } imgPtr += nOffset;
}
}
}
}
First of all you are not modifying the Bitmap at all!
You need to dereference the pointer before to apply the change and then you have to UNLOCK the bitmap...
Here's what I had in my old computer graphics course. Modify it as needed.
unsafe
{
//Go to first pixel, the cast is important
byte* p = (byte*)imageData.Scan0.ToPointer();
//For each line
for (int y = 0; y < bmp.Height; y++)
{
//For each pixel (bmp.Width * 3) because jpg has R, G, and B value if the bitmap has an alpha do a *4 multiplier
for (int x = 0; x < bmp.Width * 3; x++)
{
//Invert from the original image
*p = (byte)(255 - *p);
//Go to next pointer
p++;
}
//Move pointer to the right end of the line and then go down to a new line
//Skip the unused space
p += offset;
}
}
bmp.UnlockBits(imageData);
bmp.Save(path);
Hope it helps!
Related
I'm currently in the development phase of a photoconverter program and in the process of developing a blur filter. At the initial stages of prototyping this feature, i devised a algorithm in which I had an accumulator for each color channel and add all the pixels in a radius of the target pixel. Afterwards the program would divide the accum by the amount of pixels read(not counting those offscreen). At first I thought this would be fine but when it started to work, I had the problem of this filter taking an hour to render with this being the result at the lowest setting. So I opted to utilize parallel processing in C# to make this process much easier and faster to run. With the boost of speed came the cost of the image becoming very glitched out. Here's the image before, and Here's the image afterwards
This is the code I wrote for the filter
public static DirectBitmap NewBlur (DirectBitmap image, int radius)
{
int sectorDiam = 128;
DirectBitmap newimage = image;
List<Rectangle> renderSectors = new List<Rectangle>();
Rectangle rect;
for (int x = 0; x < (image.Width / sectorDiam); x++)
{
int xwidth = sectorDiam;
for (int y = 0; y < (image.Height / sectorDiam); y++)
{
int yheight = sectorDiam;
rect = new Rectangle(x * sectorDiam, y * sectorDiam, xwidth, yheight);
renderSectors.Add(rect);
}
}
var Picrect = new Rectangle(0, 0, image.Width, image.Height);
var data = image.Bitmap.LockBits(Picrect, ImageLockMode.ReadWrite, image.Bitmap.PixelFormat);
var depth = Bitmap.GetPixelFormatSize(data.PixelFormat) / 8; //bytes per pixel
var buffer = new byte[data.Width * data.Height * depth];
Marshal.Copy(data.Scan0, buffer, 0, buffer.Length);
Parallel.ForEach(renderSectors, sector =>
{
BlurSection(buffer, sector, Picrect, radius, image.Width, image.Height, depth);
}
);
Marshal.Copy(buffer, 0, data.Scan0, buffer.Length);
image.Bitmap.UnlockBits(data);
return image;
}
And here's the method for each section of the image to be blurred.
public static void BlurSection(byte[] buffer, Rectangle blurSector, Rectangle bitmaprect, int radius, int width, int height, int depth)
{
int[] Accum = new int[4];
for (int x = blurSector.X; x < blurSector.Width+ blurSector.X; x++)
{
for (int y = blurSector.Y; y < blurSector.Height + blurSector.Y; y++)
{
Accum[0] = 0;
Accum[1] = 0;
Accum[2] = 0;
Accum[3] = 0;
for (int i = -radius; i <= radius; i++)
{
for (int j = -radius; j <= radius; j++)
{
var offset = 0;
offset = (((y+j) * width) + (x+i)) * depth;
if (bitmaprect.Contains(new Point(x + i, y + j))){
Accum[0] += buffer[offset + 0];
Accum[1] += buffer[offset + 1];
Accum[2] += buffer[offset + 2];
Accum[3]++;
}
}
}
Accum[0] = Accum[0] / Accum[3];
if (Accum[0] > 255)
{
Accum[0] = 255;
}
Accum[1] = Accum[1] / Accum[3];
if (Accum[1] > 255)
{
Accum[1] = 255;
}
Accum[2] = Accum[2] / Accum[3];
if (Accum[2] > 255)
{
Accum[2] = 255;
}
var newoffset = ((y * width) + (x * depth*2));
buffer[newoffset + 0] = (byte)Accum[0];
buffer[newoffset + 1] = (byte)Accum[1];
buffer[newoffset + 2] = (byte)Accum[2];
}
}
}
It's also worth noting that I'm using a Bitmap class to make access to pixel data much easier, the "DirectBitmap" you can find here: https://stackoverflow.com/a/34801225/15473435. Is there anything that I'm missing or not aware of that's causing this algorithm not to function?
I'm trying to set few pixels in a bitmap using unsafe pointer access(for performance boost)-this is my code:
private unsafe void DrawImage(Bitmap bmp1)
{
BitmapData bmData = bmp1.LockBits(new Rectangle(0, 0, bmp1.Width, bmp1.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp1.PixelFormat);
IntPtr scan0 = bmData.Scan0;
int stride = bmData.Stride;
int x = 200;
int y = 400;
for (; y < 600; y++) {
byte * p = (byte * ) scan0.ToPointer();
p += y * stride + x * 4;
for (; x < 900; x++) {
p[0] = 0; //blue
p[1] = 0; //green
p[2] = 255; //red
p += 4;
}
}
bmp1.UnlockBits(bmData);
}
As you can see,i'm trying to set a block (to red color) from y=400 to y=600 , and x=200 to x=900.
On every interation of the outer loop i advance the pointer to the desired address ,but i'm getting only a "thin" horizontal line of red pixels...which indicated that somthing is wrong with the y address..i can't get why.
p += y * stride + x * 4;-this is how i advance the pointer everytime... did i miss something?
i hope my question was clear.
Thanks in advance.
The shortcuts in your loops don't go well together. At least the inner loop needs a proper start value. Best to set both start and end values; most likely you will want to go for a rectangle later anyway..
Also, as Hans noted you should make sure to look into the pixel widths of your actual PixelFormat.
Finally the loop advances are not correct.
This should work:
private unsafe void DrawImage(Bitmap bmp1)
{
BitmapData bmData = bmp1.LockBits(new Rectangle(0, 0, bmp1.Width, bmp1.Height),
System.Drawing.Imaging.ImageLockMode.ReadWrite,
bmp1.PixelFormat);
// this is only a rather incomplete test, of course:
int pixWidth = bmp1.PixelFormat == PixelFormat.Format24bppRgb ? 3 :
bmp1.PixelFormat == PixelFormat.Format32bppArgb ? 4 : 4;
IntPtr scan0 = bmData.Scan0;
int stride = bmData.Stride;
int x0 = 100;
int y0 = 100;
int x1 = 200;
int y1 = 300;
byte* p = (byte*)scan0.ToPointer() + y0 * stride;
for (int y = y0; y < y1; y++)
{
p += stride;
int px = x0 * pixWidth;
for (int x = x0; x < x1; x++)
{
px += pixWidth;
p[px + 0] = 0; //blue
p[px + 1] = 0; //green
p[px + 2] = 255; //red
}
}
bmp1.UnlockBits(bmData);
}
As noted this is not really a performance boost over GDI+ FillRectangle. However if you want to set not a block of pixels and/or not set all to one fixed color only, your code will make sense..
I am capturing data from some camera (array of RAW data).
Then I'm mapping this data to RGB values according to color palette.
I need to map it as fast as possible, so I use BitmapDdata and edit pixels in unsafe piece of code using pointers.
public void dataAcquired(int[] data)
{
Bitmap bmp = new Bitmap(width, height);
BitmapData data = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
for (int i = 0; i < data.Length; i++)
{
int x = i % bmp.Width;
int y = i / bmp.Width;
Rgb rgb = mapColors[data[i]];
unsafe
{
byte* ptr = (byte*)data.Scan0;
ptr[(x * 3) + y * data.Stride] = rgb.b;
ptr[(x * 3) + y * data.Stride + 1] = rgb.g;
ptr[(x * 3) + y * data.Stride + 2] = rgb.r;
}
}
bmp.UnlockBits(data);
}
And I'm doing this for every incoming frame. It works fine, but it still takes something like 30ms for each frame for 320x240 pixels.
Is it possible to make it even more faster? Maybe I couldlock/unlock data in memory only once, but I'm not sure about this.
Instead of calculating x and y for each pixel, you could make them loop counters, like this:
for( y = 0; y < bmp.Height; y++ )
for( x = 0; x < bmp.Width; x++ )
Better yet, ditch x and y altogether and just keep incrementing the ptr pointer instead of recalculating an offset from the ptr pointer three times per pixel.
Try this (warning: I have not checked it.)
public void dataAcquired()
{
Bitmap bmp = new Bitmap(width, height);
BitmapData data = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
unsafe
{
int i = 0;
byte* ptr = (byte*)data.Scan0;
for( int y = 0; y < bmp.Height; y++ )
{
byte* ptr2 = ptr;
for( int x = 0; x < bmp.Width; x++ )
{
Rgb rgb = mapColors[data[i++]];
*(ptr2++) = rgb.b;
*(ptr2++) = rgb.g;
*(ptr2++) = rgb.r;
}
ptr += data.Stride;
}
}
bmp.UnlockBits(data);
}
Try run code in parallel: change
for (int i = 0; i < data.Length; i++) {
...
}
into
Parallel.For(0, data.Length, (i) => {
int x = i % bmp.Width;
int y = i / bmp.Width;
Rgb rgb = mapColors[data[i]];
unsafe {
byte* ptr = (byte*) data.Scan0;
ptr[(x * 3) + y * data.Stride] = rgb.b;
ptr[(x * 3) + y * data.Stride + 1] = rgb.g;
ptr[(x * 3) + y * data.Stride + 2] = rgb.r;
}
});
public unsafe Bitmap MedianFilter(Bitmap Img)
{
int Size =2;
List<byte> R = new List<byte>();
List<byte> G = new List<byte>();
List<byte> B = new List<byte>();
int ApetureMin = -(Size / 2);
int ApetureMax = (Size / 2);
BitmapData imageData = Img.LockBits(new Rectangle(0, 0, Img.Width, Img.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);
byte* start = (byte*)imageData.Scan0.ToPointer ();
for (int x = 0; x < imageData.Width; x++)
{
for (int y = 0; y < imageData.Height; y++)
{
for (int x1 = ApetureMin; x1 < ApetureMax; x1++)
{
int valx = x + x1;
if (valx >= 0 && valx < imageData.Width)
{
for (int y1 = ApetureMin; y1 < ApetureMax; y1++)
{
int valy = y + y1;
if (valy >= 0 && valy < imageData.Height)
{
Color tempColor = Img.GetPixel(valx, valy);// error come from here
R.Add(tempColor.R);
G.Add(tempColor.G);
B.Add(tempColor.B);
}
}
}
}
}
}
R.Sort();
G.Sort();
B.Sort();
Img.UnlockBits(imageData);
return Img;
}
I tried to do this. but i got an error call "Bitmap region is already locked" can anyone help how to solve this. (error position is highlighted)
GetPixel is the slooow way to access the image and doesn't work (as you noticed) anymore if someone else starts messing with the image buffer directly. Why would you want to do that?
Check Using the LockBits method to access image data for some good insight into fast image manipulation.
In this case, use something like this instead:
int pixelSize = 4 /* Check below or the site I linked to and make sure this is correct */
byte* color =(byte *)imageData .Scan0+(y*imageData .Stride) + x * pixelSize;
Note that this gives you the first byte for that pixel. Depending on the color format you are looking at (ARGB? RGB? ..) you need to access the following bytes as well. Seems to suite your usecase anyway, since you just care about byte values, not the Color value.
So, after having some spare minutes, this is what I'd came up with (please take your time to understand and check it, I just made sure it compiles):
public void SomeStuff(Bitmap image)
{
var imageWidth = image.Width;
var imageHeight = image.Height;
var imageData = image.LockBits(new Rectangle(0, 0, imageWidth, imageHeight), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);
var imageByteCount = imageData.Stride*imageData.Height;
var imageBuffer = new byte[imageByteCount];
Marshal.Copy(imageData.Scan0, imageBuffer, 0, imageByteCount);
for (int x = 0; x < imageWidth; x++)
{
for (int y = 0; y < imageHeight; y++)
{
var pixelColor = GetPixel(imageBuffer, imageData.Stride, x, y);
// Do your stuff
}
}
}
private static Color GetPixel(byte[] imageBuffer, int imageStride, int x, int y)
{
int pixelBase = y*imageStride + x*3;
byte blue = imageBuffer[pixelBase];
byte green = imageBuffer[pixelBase + 1];
byte red = imageBuffer[pixelBase + 2];
return Color.FromArgb(red, green, blue);
}
This
Relies on the PixelFormat you used in your sample (regarding both the pixelsize/bytes per pixel and the order of the values). If you change the PixelFormat this will break.
Doesn't need the unsafe keyword. I doubt that it makes a lot of difference, but you are free to use the pointer based access instead, the method would be the same.
I have a drawing application developed in winforms C# which uses many System.Drawing.Bitmap object throughout the code.
Now I am writing it into WPF with c#. I have done almost 90% of the conversion.
Coming to the problem... I have the following code which is used to traverse the image pixel by pixel
Bitmap result = new Bitmap(img); // img is of System.Drawing.Image
result.SetResolution(img.HorizontalResolution, img.VerticalResolution);
BitmapData bmpData = result.LockBits(new Rectangle(0, 0, result.Width, result.Height), ImageLockMode.ReadWrite, img.PixelFormat);
int pixelBytes = System.Drawing.Image.GetPixelFormatSize(img.PixelFormat) / 8;
System.IntPtr ptr = bmpData.Scan0;
int size = bmpData.Stride * result.Height;
byte[] pixels = new byte[size];
int index = 0;
double R = 0;
double G = 0;
double B = 0;
System.Runtime.InteropServices.Marshal.Copy(ptr, pixels, 0, size);
for (int row = 0; row <= result.Height - 1; row++)
{
for (int col = 0; col <= result.Width - 1; col++)
{
index = (row * bmpData.Stride) + (col * pixelBytes);
R = pixels[index + 2];
G = pixels[index + 1];
B = pixels[index + 0];
.
.// logic code
.
}
}
result.UnlockBits(bmpData);
It uses System.Drawing's for the purpose.
Is it possible to achieve this thing in wpf as well keeping it simple as it is?
In addtion to Chris's anwser you might want to look at WriteableBitmap. It's another way to manipulate images pixels.
Example
You can use BitmapImage.CopyPixels to copy the image your pixel buffer.
BitmapImage img= new BitmapImage(...); // This is your image
int bytePerPixel = (img.Format.BitsPerPixel + 7) / 8;
int stride = img.PixelWidth * bytesPerPixel;
int size = img.PixelHeight * stride;
byte[] pixels = new byte[size];
img.CopyPixels(pixels, stride, 0);
// Now you can access 'pixels' to perform your logic
for (int row = 0; row < img.PixelHeight; row++)
{
for (int col = 0; col < img.PixelWidth; col++)
{
index = (row * stride) + (col * bytePerPixel );
...
}
}