This question already has answers here:
When to use pointers in C#/.NET?
(5 answers)
Closed 9 years ago.
I just want to know where we can use pointers in C#.
we can use pointers in C++ but i have no idea where we can use them in C#.
I also want to know if there is any pointer used in unmanaged code.
Yes, you can use pointers. See unsafe keyword.
An example of a pratical use: convert image to grayscale
public static Bitmap MakeGrayscale2(Bitmap original)
{
unsafe
{
//create an empty bitmap the same size as original
Bitmap newBitmap = new Bitmap(original.Width, original.Height);
//lock the original bitmap in memory
BitmapData originalData = original.LockBits(
new Rectangle(0, 0, original.Width, original.Height),
ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
//lock the new bitmap in memory
BitmapData newData = newBitmap.LockBits(
new Rectangle(0, 0, original.Width, original.Height),
ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
//set the number of bytes per pixel
int pixelSize = 3;
for (int y = 0; y < original.Height; y++)
{
//get the data from the original image
byte* oRow = (byte*)originalData.Scan0 + (y * originalData.Stride);
//get the data from the new image
byte* nRow = (byte*)newData.Scan0 + (y * newData.Stride);
for (int x = 0; x < original.Width; x++)
{
//create the grayscale version
byte grayScale =
(byte)((oRow[x * pixelSize] * .11) + //B
(oRow[x * pixelSize + 1] * .59) + //G
(oRow[x * pixelSize + 2] * .3)); //R
//set the new image's pixel to the grayscale version
nRow[x * pixelSize] = grayScale; //B
nRow[x * pixelSize + 1] = grayScale; //G
nRow[x * pixelSize + 2] = grayScale; //R
}
}
//unlock the bitmaps
newBitmap.UnlockBits(newData);
original.UnlockBits(originalData);
return newBitmap;
}
}
As seen here.
Related
I am using mvfox-igc camera sdk for getting images from that camera my problem is that i have byte array of mono8 image and i want to convert that pixel data into 24bit image my programming language
can anybody help me please my code looks like this but is is not doing its work properly
processedBitmap = new Bitmap(data.request.imageWidth.read(),data.request.imageHeight.read(),PixelFormat.Format24bppRgb);
unsafe
{
BitmapData bitmapData = processedBitmap.LockBits(new Rectangle(0, 0, processedBitmap.Width, processedBitmap.Height), ImageLockMode.ReadWrite, processedBitmap.PixelFormat);
int bytesPerPixel = System.Drawing.Bitmap.GetPixelFormatSize(processedBitmap.PixelFormat) / 8;
int heightInPixels = bitmapData.Height;
int widthInBytes = bitmapData.Width * bytesPerPixel;
byte* PtrFirstPixel = (byte*)bitmapData.Scan0;
byte* firstby = (byte*)data.request.imageData.read();
int indexx=0;
Parallel.For(0, heightInPixels, y =>
{
byte* currentLine = PtrFirstPixel + (y * bitmapData.Stride);
for (int x = 0; x < widthInBytes; x = x + bytesPerPixel)
{
currentLine[x] = firstby[indexx];//((byte*)data.request.imageData.read())[0];//(byte)oldBlue;
currentLine[x + 1] = firstby[indexx];//((byte*)data.request.imageData.read())[0];//(byte)oldGreen;
currentLine[x + 2] = firstby[indexx];//((byte*)data.request.imageData.read())[0];//(byte)oldRed;
indexx = indexx + 1;
}
});
processedBitmap.UnlockBits(bitmapData);
processedBitmap.Save("bmp.jpg");
My code calculates average color of each pixel in an image and returns a new image.
Image calculateAverage(Bitmap image1, Bitmap image2)
{
// Locking the image into memory.
BitmapData sourceData = image1.LockBits(new Rectangle(0, 0, image1.Width, image1.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
// All of the pixels will be stored in this array(each 4 numbers represent a pixel).
byte[] sourceBuffer = new byte[sourceData.Stride * sourceData.Height];
// Copying the image pixels into sourceBuffer.
Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, sourceBuffer.Length);
// Don't need the image, unlock memory.
image1.UnlockBits(sourceData);
// --- Same thing for the second image ---
BitmapData blendData = image2.LockBits(new Rectangle(0, 0, image2.Width, image2.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
byte[] blendBuffer = new byte[blendData.Stride * blendData.Height];
Marshal.Copy(blendData.Scan0, blendBuffer, 0, blendBuffer.Length);
image2.UnlockBits(blendData);
//---
// Calculating average of each color in each pixel.
for (int k = 0; (k + 4 < sourceBuffer.Length) && (k + 4 < blendBuffer.Length); k += 4)
{
sourceBuffer[k] = (byte)calcualteAverage(sourceBuffer[k], blendBuffer[k]);
sourceBuffer[k + 1] = (byte)calcualteAverage(sourceBuffer[k + 1], blendBuffer[k + 1]);
sourceBuffer[k + 2] = (byte)calcualteAverage(sourceBuffer[k + 2], blendBuffer[k + 2]);
// Average of Alpha
sourceBuffer[k + 3] = (byte)calcualteAverage(sourceBuffer[k + 3], sourceBuffer[k + 3]);
}
// Saving the result.
Bitmap resultBitmap = new Bitmap(image1.Width, image1.Height);
BitmapData resultData = resultBitmap.LockBits(new Rectangle(0, 0,
resultBitmap.Width, resultBitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
Marshal.Copy(sourceBuffer, 0, resultData.Scan0, sourceBuffer.Length);
resultBitmap.UnlockBits(resultData);
return resultBitmap;
}
For performance reasons I need to rewrite this method using unsafe code though I'm a noob with pointers; don't know how it can improve performance or what will change in the algorithm?
The function can be replaced by this:
public static Bitmap CalculateAverage(
Bitmap sourceBitmap, Bitmap blendBitmap)
{
// Locking the images into the memory.
BitmapData sourceData = sourceBitmap.LockBits(
new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
BitmapData blendData = blendBitmap.LockBits(
new Rectangle(0, 0, blendBitmap.Width, blendBitmap.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
// Get required variables. This wont work for images with different sizes.
int resultWidth = sourceBitmap.Width;
int resultHeight = sourceBitmap.Height;
int stride = sourceData.Stride;
// result will be stored here.
var resultBitmap = new Bitmap(resultWidth, resultHeight);
BitmapData resultData = resultBitmap.LockBits(
new Rectangle(0, 0, resultWidth, resultHeight),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
{
// Getting address of locked images.
byte* sourceAddress = (byte*)sourceData.Scan0.ToPointer();
byte* blendAddress = (byte*)blendData.Scan0.ToPointer();
byte* resultAddress = (byte*)resultData.Scan0.ToPointer();
// Iterating throgh pixels and storing averages inside the result variable.
for (int y = 0; y < resultHeight; y++)
{
for (int x = 0; x < resultWidth; x++)
{
for (int color = 0; color < 4; color++)
{
int currentByte = (y * stride) + x * 4 + color;
resultAddress[currentByte] = (byte)average(
sourceAddress[currentByte],
blendAddress[currentByte]);
}
}
}
}
// Unlocking the Bits; returning the result bitmap.
sourceBitmap.UnlockBits(sourceData);
blendBitmap.UnlockBits(blendData);
resultBitmap.UnlockBits(resultData);
return resultBitmap;
}
I cannot test it at the moment but this might give a hint in the right direction. If there are any questions please don't hesitate to ask. It's based on this code: How to calculate the average rgb color values of a bitmap.
Context: I have a program that gets the ArGB of any image. Throws it into a Color ARGBFormat = Color.FromArgb(alpha, red, green, blue); Now I would like to put that into a PictureBox. I do not have a complete Pixel Array (It is more or less scattered).
Code:
Bitmap bmp = new Bitmap(ImagePath);
Rectangle bmpRec = new Rectangle(0, 0, bmp.Width, bmp.Height); //Creates Rectangle for holding picture
BitmapData bmpData = bmp.LockBits(bmpRec, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); //Gets the Bitmap data
IntPtr Pointer = bmpData.Scan0;
int DataBytes = Math.Abs(bmpData.Stride) * bmp.Height; //Gets array size
byte[] rgbValues = new byte[DataBytes]; //Creates array
Marshal.Copy(Pointer, rgbValues, 0, DataBytes); //Copies of out memory
StringBuilder EveryPixel = new StringBuilder(" ");
int PixelSize = 4;
Color ARGBFormat;
Bitmap ImageOut = new Bitmap(bmp.Width, bmp.Height);
unsafe
{
for (int y = 0; y < bmpData.Height; y++)
{
byte* row = (byte*)bmpData.Scan0 + (y * bmpData.Stride);
for (int x = 0; x < bmpData.Width; x++)
{
int offSet = x * PixelSize;
// read pixels
byte blue = row[offSet];
byte green = row[offSet + 1];
byte red = row[offSet + 2];
byte alpha = row[offSet + 3];
ARGBFormat = Color.FromArgb(alpha, red, green, blue);
ImageOut.SetPixel(x, y, ARGBFormat); //Slow
EveryPixel.Append(ARGBFormat);
}
}
}
I want to use that code that I have been working on ^ to be displayed into a PictureBox without using SetPixels. I want to use LockBits as it is the most optimize method.
Here you go
initialization code before the loop
BitmapData bitmapData = ImageOut.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
byte[] pixels = new byte[bmp.Width * bmp.Height * 4]; //4 means 1 byte for each a r g b
IntPtr ptr = bitmapData.Scan0;
Marshal.Copy(ptr , pixels, 0, pixels.Length);
update the pixels within the loop
pixels[offSet] = blue;
pixels[offSet + 1] = green;
pixels[offSet + 2] = red;
pixels[offSet + 3] = alpha;
finally to cleanup the code
bitmapData.UnlockBits();
so for me code look like
unsafe
{
BitmapData bitmapData = ImageOut.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
byte[] pixels = new byte[bmp.Width * bmp.Height * 4]; //4 means 1 byte for each a r g b
IntPtr ptr = bitmapData.Scan0;
Marshal.Copy(ptr , pixels, 0, pixels.Length);
for (int y = 0; y < bmpData.Height; y++)
{
byte* row = (byte*)bmpData.Scan0 + (y * bmpData.Stride);
for (int x = 0; x < bmpData.Width; x++)
{
int offSet = x * PixelSize;
// read pixels
byte blue = row[offSet];
byte green = row[offSet + 1];
byte red = row[offSet + 2];
byte alpha = row[offSet + 3];
//copy to target
pixels[offSet] = blue;
pixels[offSet + 1] = green;
pixels[offSet + 2] = red;
pixels[offSet + 3] = alpha;
}
}
bitmapData.UnlockBits();
}
//set to picturebox
pictureBox.Image = ImageOut;
I hope this work for you.
I wrote the code below in order to manipulate the color of an image. I want to somehow rip apart each pixel of the image. So for each pixel, i want access to the 5 bits of red, 6 bits of green and 5 bits of blue (as per 16 bit images). How would i change my code to do this? I guess i would have to somehow convert those byte values which i'm setting to bits?
Any help would be great.
private Bitmap InvertBitmap(Bitmap bmp)
{
unsafe
{
//create an empty bitmap the same size as original
Bitmap newBitmap = new Bitmap(bmp.Width, bmp.Height);
//lock the original bitmap in memory
System.Drawing.Imaging.BitmapData originalData = bmp.LockBits(
new Rectangle(0, 0, bmp.Width, bmp.Height),
System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
//lock the new bitmap in memory
System.Drawing.Imaging.BitmapData newData = newBitmap.LockBits(
new Rectangle(0, 0, bmp.Width, bmp.Height),
System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
//set the number of bytes per pixel
int pixelSize = 3;
for (int y = 0; y < bmp.Height; y++)
{
//get the data from the original image
byte* originalImageRow = (byte*)originalData.Scan0 + (y * originalData.Stride);
//get the data from the new image
byte* newImageRow = (byte*)newData.Scan0 + (y * newData.Stride);
for (int x = 0; x < bmp.Width; x++)
{
//set the new image's pixel to the inverted version
newImageRow[x * pixelSize] = (byte)(255 - originalImageRow[x * pixelSize + 0]); //B
newImageRow[x * pixelSize + 1] = (byte)(255 - originalImageRow[x * pixelSize + 1]); //G
newImageRow[x * pixelSize + 2] = (byte)(255 - originalImageRow[x * pixelSize + 2]); //R
}
}
//unlock the bitmaps
newBitmap.UnlockBits(newData);
bmp.UnlockBits(originalData);
return newBitmap;
}
}
If you have a 16-bit integer x, you can extract ranges of bits within it by first masking those bits with a binary AND, then shifting the result. Like so:
int x = 33808; // 1000010000010000, for testing
int r = (x & 63488) >> 11; // 63488 = 1111100000000000
int g = (x & 2016) >> 5; // 2016 = 0000011111100000
int b = (x & 31); // 31 = 0000000000011111
// r = 10000
// g = 100000
// b = 10000
I hope that helps.
RGB24 is 1 byte per color channel so you don't need to do any bit twiddling to extract them from the data you already have. "getting the bits" doesn't really make sense as you can set their values already e.g.
newImageRow[x * pixelSize] = (byte)(originalImageRow[x * pixelSize + 0] | 0x80); //B
will set the new image blue channel to the original image blue channel but will set the high order bit to 1.
newImageRow[x * pixelSize] = (byte)(originalImageRow[x * pixelSize + 0] ^ 0xFF); //B
will invert the channel.
So you really just need to use bitwise operators (| & >> << ^)on the data you already have.
I'm trying to write out a grayscale image using Lockbits, my current code looks is
/// <summary>
/// Save the content of the FrameProc out to a bitmap
/// </summary>
public void Save(string path)
{
Bitmap bmp = new Bitmap(this.size.Width, this.size.Height
,PixelFormat.Format32bppRgb);
var data = bmp.LockBits(this.size, ImageLockMode.WriteOnly, bmp.PixelFormat);
unsafe
{
for (int y = 0; y < this.size.Height; y++)
{
byte* row = (byte*)data.Scan0 + (y * data.Stride);
for (int x = 0; x < this.size.Width; x++)
{
byte value = (byte)this.buffer[y, x];
row[x*Bits+r] = value;
row[x*Bits+g] = value;
row[x*Bits+b] = value;
}
}
}
bmp.UnlockBits(data);
bmp.Save(path, ImageFormat.Bmp);
}
where
/// <summary>
/// The amount of Bytes per pixel in the image
/// </summary>
private const int Bits = 4;
/// <summary>
/// Image components
/// </summary>
private const int a=3, r = 2, g = 1, b = 0;
However the image i receive is not correct:
Maybe this is related to how i'm reading them in? So here's that code
public FrameProc(Bitmap bmp)
{
this.size=new Rectangle(new Point(0,0), bmp.Size);
var data = bmp.LockBits(this.size
,ImageLockMode.ReadOnly
,bmp.PixelFormat);
this.buffer = new Matrix(this.size.Height, this.size.Width);
unsafe
{
for (int y = 0; y < this.size.Height; y++)
{
byte* row = (byte*)data.Scan0 + (y * data.Stride);
for (int x = 0; x < this.size.Width; x++)
{
this.buffer[y,x] = 0.299*row[x*Bytes+r]
+ 0.587*row[x*Bytes+g]
+ 0.114*row[x*Bytes+b];
}
}
}
bmp.UnlockBits(data);
}
From the results you're getting - it looks exactly as if each pixel is three bytes big and not four as you have declared it - and as one would expect. (Note: you called it Bits - but that's wrong - it should be namned Bytes, not Bits).
I'd experiment with any one of this:
change from 4 to 3 bytes
change from Format32bppRgb to Format32bppArgb and fill out the alpha with 255
change from 4 to 3 bytes and from Format32bppRgb to from Format24bppRgb
I would also rewrite the loop slightly for performance (sorry, I can't help myself):
for (int x = 0; x < this.size.Width; x++, row += Bits)
{
byte value = (byte)this.buffer[y, x];
row[r] = value;
row[g] = value;
row[b] = value;
}
But were you really would get more speed if you get a pointer to this.buffer using the fixed keyword. Yes, you're not having any performance problems, but I couldn't help myself from mentioning it!
Use this function indeed:
public Bitmap MakeGrayscale(Bitmap original)
{
unsafe
{
//create an empty bitmap the same size as original
Bitmap newBitmap = new Bitmap(original.Width, original.Height);
//lock the original bitmap in memory
BitmapData originalData = original.LockBits(
new Rectangle(0, 0, original.Width, original.Height),
ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
//lock the new bitmap in memory
BitmapData newData = newBitmap.LockBits(
new Rectangle(0, 0, original.Width, original.Height),
ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
//set the number of bytes per pixel
// here is set to 3 because I use an Image with 24bpp
int pixelSize = 3;
for (int y = 0; y < original.Height; y++)
{
//get the data from the original image
byte* oRow = (byte*)originalData.Scan0 + (y * originalData.Stride);
//get the data from the new image
byte* nRow = (byte*)newData.Scan0 + (y * newData.Stride);
for (int x = 0; x < original.Width; x++)
{
//create the grayscale version
byte grayScale =
(byte)((oRow[x * pixelSize] * .11) + //B
(oRow[x * pixelSize + 1] * .59) + //G
(oRow[x * pixelSize + 2] * .3)); //R
//set the new image's pixel to the grayscale version
nRow[x * pixelSize] = grayScale; //B
nRow[x * pixelSize + 1] = grayScale; //G
nRow[x * pixelSize + 2] = grayScale; //R
}
}
//unlock the bitmaps
newBitmap.UnlockBits(newData);
original.UnlockBits(originalData);
return newBitmap;
}
}
Source and other interesting examples (with theory behind) could be taken from here