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.
Related
```
if (alpha != null && input != null)
{
Bitmap output = new Bitmap(input.Width, input.Height, PixelFormat.Format32bppArgb);
var rect = new Rectangle(0, 0, input.Width, input.Height);
var bitsAlpha = alpha.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
var bitsInput = input.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
var bitsOutput = output.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
{
for (int y = 0; y < input.Height; y++)
{
byte* ptrAlpha = (byte*)bitsAlpha.Scan0 + y * bitsAlpha.Stride;
byte* ptrInput = (byte*)bitsInput.Scan0 + y * bitsInput.Stride;
byte* ptrOutput = (byte*)bitsOutput.Scan0 + y * bitsOutput.Stride;
for (int x = 0; x < input.Width; x++)
{
ptrOutput[4 * x] = ptrInput[4 * x]; // blue
ptrOutput[4 * x + 1] = ptrInput[4 * x + 1]; // green
ptrOutput[4 * x + 2] = ptrInput[4 * x + 2]; // red
ptrOutput[4 * x + 3] = ptrAlpha[4 * x]; // alpha
}
}
}
alpha.UnlockBits(bitsAlpha);
input.UnlockBits(bitsInput);
output.UnlockBits(bitsOutput);
return output;
}
```
I changed the PixelFormat to Format8bppIndexed.I set the pixel format to Format8bppIndexed and came to this conclusion image . Please help me
From what I can see, you're trying to use an 8-bit grayscale image as alpha for another picture.
This does not mean the final output will be 8-bit. It doesn't even mean the input image is 8-bit. In fact, the output of this should still be 32-bit, since 8-bit only supports palette-based transparency, meaning you set alpha to specific colours (affecting all pixels on the image that use that colour), rather than to specific pixels on the image.
The only things you need to change are these:
Since the alpha image is apparently 8-bit, lock that one as 8-bit. But to be sure, you should add a specific check in advance to test if its pixel format is indeed Format8bppIndexed.
Since that image is now locked as 8-bit, its single pixels are not grouped per 4 bytes but per 1 byte. So in the code that retrieves the alpha from it, remove the * 4 part.
The changed lines:
var bitsAlpha = alpha.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);
and
ptrOutput[4 * x + 3] = ptrAlpha[x]; // alpha
Besides this, the code should be kept as it is.
Red, Green, Blue and Alpha is for 32bit images (each of these is stored as a byte which 8 bits, 4 x 8 = 32), indexed images doesn't work this way.
1 . if your image is a 32bit image, then your loop steps should be 4:
for (int x = 0; x < input.Width; x+=4) // x+=3 for 24bit images (without alpha like jpg images)
instead of
for (int x = 0; x < input.Width; x++)
for 8bit indexed images it does not work that way and the colors are stored in a pallet (have a look at this)
I need to extract R,G,B values from the image and store in 3 different arrays with it's equivalent co-ordinates values. For example: In 500*500 Image, R must store only red color information of each pixel and it's equivalent co-ordinate values i.e., [0,0] to its maximum co-ordinate [499,499]. After extracting all the R values into array, I need to retrieve the R value of particular pixel using the co-ordinate as a reference by mouse click in the Image, And need to follow same for G,B values. Can anyone help me doing this using C#? In WPF application.
if your image is a System.Drawing.Bitmap:
BitmapData data = image.LockBits(new Rectangle(startX, startY, w, h), System.Drawing.Imaging.ImageLockMode.ReadOnly, PixelFormat);
try
{
byte[] pixelData = new Byte[data.Stride];
for (int scanline = 0; scanline < data.Height; scanline++)
{
Marshal.Copy(data.Scan0 + (scanline * data.Stride), pixelData, 0, data.Stride);
for (int pixeloffset = 0; pixeloffset < data.Width; pixeloffset++)
{
// PixelFormat.Format32bppRgb means the data is stored
// in memory as BGR. We want RGB, so we must do some
// bit-shuffling.
rgbArray[offset + (scanline * scansize) + pixeloffset] =
(pixelData[pixeloffset * PixelWidth + 2] << 16) + // R
(pixelData[pixeloffset * PixelWidth + 1] << 8) + // G
pixelData[pixeloffset * PixelWidth]; // B
}
}
}
finally
{
image.UnlockBits(data);
}
I am using Cudafy as c# wrapper
I need to get colour info InputBitmap0.GetPixel(x, y) of a bitmap and make an new bitmap for output .
I need the following work to be done in GPU.
IN CPU
OutputBitmap.SetPixel(object_point_x, object_point_y, InputBitmap0.GetPixel(x, y));
In short:
How to GetPixel() for each pixel point of the input Bitmap, SetPixel() for each pixel point of the outputbitmap Bitmap in GPU.
OutputBitmap.SetPixel(object_point_x, object_point_y, InputBitmap0.GetPixel(x, y))
It took time but finally, I , cracked my case.
We have two Bitmap : one for output OutputBitmap and another for input InputBitmap0
Lets divide this task into parts:
do InputBitmap0.GetPixel() for x ,y coordinate
then , OutputBitmap.SetPixel() for a different coordinate object_point_x, object_point_y
Cudafy does not support Bitmap or Color type data. So I converted the Bitmaps to byte type.
BitmapData InputBitmapData0 = InputBitmap0.LockBits(new Rectangle(0, 0, InputBitmap0.Width, InputBitmap0.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
IntPtr ptr0 = InputBitmapData0.Scan0;//pointer for color
int stride0 = InputBitmapData0.Stride;
byte[] input_ragba_color = new byte[InputBitmapData0.Stride * InputBitmap0.Height];
Marshal.Copy(ptr0, input_ragba_color, 0, bytes0);// Copy the RGB values of color value into the array.
We have copied the content of the InputBitmap0 to the rgbValues array. Now we need to do the work of GetPixel() (get the values of R,G,B,A).
We need to do the above work ( make array) for OutputBitmap too because we will be doing SetPixel() in GPU but we will copy the array back to the bitmap later.
BitmapData OutputBitmapData = OutputBitmap.LockBits(new Rectangle(0, 0, OutputBitmap.Width, OutputBitmap.Height), ImageLockMode.WriteOnly, OutputBitmap.PixelFormat);
IntPtr ptr_output = OutputBitmapData.Scan0;
byte[] output_ragba = new byte[OutputBitmapData.Stride * OutputBitmap.Height];
Its GPU time for calculation. Lets initialize gpu.
CudafyModule km = new CudafyTranslator.Cudafy();
GPGPU gpu = new CudafyHost.getDevice(CudafyModes.Target, CudafyModes.DeviceId);
gpu.LoadModule(km);
Now send input_ragba_color and output_ragba to the gpu because we can iterate the array and do any calculation.
byte[] dev_output_rgba_color = gpu.Allocate<byte>(output_ragba.Length);
byte[] dev_input_ragba_color = gpu.CopyToDevice(input_ragba_color);
gpu.Launch(N, 1).update_bitmap(x, y, object_point_x, object_point_y,int stride0, int OutputBitmapData.Stride,dev_input_ragba_color,dev_output_rgba_color);
Now inside GPU(kernel)
[Cudafy]
public static void update_bitmap(GThread thread, int x,int y,int object_point_x,int object_point_y,int stride0, int OutputBitmapData_Stride,byte [] dev_input_ragba_color,byte [] dev_output_rgba_color)
{
dev_output_rgba_color[(object_point_y * OutputBitmapData_Stride) + (object_point_x * 4)] = input_ragba_color[(y * stride0) + (x * 4)];
dev_output_rgba_color[(object_point_y * OutputBitmapData_Stride) + (object_point_x * 4) + 1] = input_ragba_color[(y * stride0) + (x * 4) + 1];
dev_output_rgba_color[(object_point_y * OutputBitmapData_Stride) + (object_point_x * 4) + 2] = input_ragba_color[(y * stride0) + (x * 4) + 2];
dev_output_rgba_color[(object_point_y * OutputBitmapData_Stride) + (object_point_x * 4) + 3] = input_ragba_color[(y * stride0) + (x * 4) + 3];
}
I am taking values of each R,G,B,A ,ex: input_ragba_color[(y *
stride0) + (x * 4) + 1] which is solving 1st task
(InputBitmap0.GetPixel())
dev_output_rgba_color is taking the values of input_ragba_color
example:
dev_output_rgba_color[(object_point_y * OutputBitmapData_Stride) + (object_point_x * 4)] = input_ragba_color[(y * stride0) + (x * 4)];
which is solves our 2nd task (OutputBitmap.SetPixel())
We now know that gpu has populated an array(dev_output_rgba_color) for our OutputBitmap.
gpu.CopyFromDevice(dev_output_rgba_color, output_ragba); //dev_output_rgba_color values will be assigned to output_ragba
gpu.FreeAll();
Copy the result back to the OutputBitmap using the memory pointer and unlock it from the memory.
Marshal.Copy(output_ragba, 0, ptr_output, output_bytes);// Copy the RGB values of color value into the array.
OutputBitmap.UnlockBits(OutputBitmapData);
Now the OutputBitmap contains the updated values.
I think you will need to use a byte[] and allocate that on the GPU. I've seen you asking around and this answer is a work in progress, I'll keep updating it over the next few days as I get time.
CudafyModule km = new CudafyTranslator.Cudafy();
GPGPU gpu = new CudafyHost.getDevice(CudafyModes.Target, CudafyModes.DeviceId);
gpu.LoadModule(km);
var image = new Bitmap(width, height);
image = (Bitmap)Image.FromFile(#"C:\temp\a.bmp", true);
byte[] imageBytes = new byte[width * height * 4];
using(MemoryStream ms = new MemoryStream())
{
image.Save(ms, format);
imageBytes = ms.ToArray();
}
byte[] device_imageBytes = _gpu.CopyToDevice(imageBytes);
byte r = 0;
byte g = 0;
byte b = 0;
byte device_r = _gpu.Allocate<byte>(r);
byte device_g = _gpu.Allocate<byte>(g);
byte device_b = _gpu.Allocate<byte>(b);
//Call this in a loop
gpu.Launch(N, 1).GetPixel(x, y, device_imageBytes, device_r, device_g, device_b);
...
[Cudafy]
public static void GetPixel(GThread thread, int x, int y, byte[] imageBytes, byte blue, byte green, byte red)
{
int offset = x * BPP + y * stride;
blue = imageBytes[offset++];
green = imageBytes[offset++];
red = imageBytes[offset];
double R = red;
double G = green * 255;
double B = blue * 255 * 255;
}
I am not very familiar with bitmaps and I need to save a FrameworkElement (specificaly Grid) as bitmap and copy it to buffer. The problem is I need to save it in Rgba format, not Pgrba, which isn't supported in RenderTargetBitmap. Relevant code is here:
_targetBitmap = new RenderTargetBitmap(xres, yres, 96, 96, PixelFormats.Pbgra32);
_targetBitmap.Clear();
// Child is grid
_targetBitmap.Render(Child);
// copy the pixels into the buffer
_targetBitmap.CopyPixels(new Int32Rect(0, 0, xres, yres), bufferPtr, _bufferSize, _stride);
I tried using WriteableBitmap, but I didn't how to render the Child. Any suggestions?
The CopyPixels function is already giving you direct access to the pixel data, so all you need to do is convert between formats. In this case, you need to swap the channel orders around and undo the premultiplication of alpha values.
NOTE: This code assumes your bufferPtr is a byte array or a byte pointer.
for (int y = 0; y < yres; y++)
{
for (int x = 0; x < xres; x++)
{
// Calculate array offset for this pixel
int offset = y * _stride + x * 4;
// Extract individual color channels from pixel value
int pb = bufferPtr[offset];
int pg = bufferPtr[offset + 1];
int pr = bufferPtr[offset + 2];
int alpha = bufferPtr[offset + 3];
// Remove premultiplication
int r = 0, g = 0, b = 0;
if (alpha > 0)
{
r = pr * 255 / alpha;
g = pg * 255 / alpha;
b = pb * 255 / alpha;
}
// Write color channels in desired order
bufferPtr[offset] = (byte)r;
bufferPtr[offset + 1] = (byte)g;
bufferPtr[offset + 2] = (byte)b;
bufferPtr[offset + 3] = (byte)alpha;
}
}
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.