I'm trying to use the SDK of a sensor for intraoral x-ray. I managed to save the image, but the image doubled.
This is the function to save the image.
private void SaveImage(short[] data, int widht, int height)
{
Bitmap pic = new Bitmap(widht, height);
Rectangle dimension = new Rectangle(0, 0, pic.Width, pic.Height);
BitmapData picData = pic.LockBits(dimension, ImageLockMode.ReadWrite, pic.PixelFormat);
IntPtr pixelStartAddress = picData.Scan0;
Marshal.Copy(data, 0, pixelStartAddress, data.Length);
pic.UnlockBits(picData);
pic.Save(#"C:\Users\WIM\Desktop\teste\teste\teste.jpeg", ImageFormat.Jpeg);
}
And this is the image saved
I'm not used to coding in C#. So I'm not sure if I do this right, and if the problem is on the function where i save the image or on the way as populated short array (short[] data);
[Update]
As suggested, I added PixelFormat.Format16bppGrayScale. and the function was like this:
private void SaveImage(short[] data, int widht, int height)
{
Bitmap pic = new Bitmap(widht, height, PixelFormat.Format16bppGrayScale);
Rectangle dimension = new Rectangle(0, 0, pic.Width, pic.Height);
BitmapData picData = pic.LockBits(dimension, ImageLockMode.ReadWrite, pic.PixelFormat) ;
IntPtr pixelStartAddress = picData.Scan0;
Marshal.Copy(data, 0, pixelStartAddress, data.Length);
pic.UnlockBits(picData);
pic.Save(#"C:\Users\WIM\Desktop\teste\teste\teste.jpeg", ImageFormat.Jpeg);
}
And I got this error:
System.Runtime.InteropServices.ExternalException: 'GDI+ generic error.'
In this line:
pic.Save(#"C:\Users\WIM\Desktop\teste\teste\teste.jpeg", ImageFormat.Jpeg);
[Update]
I tried to modify the pixel format, and I tested all the other 16bpp. This is the result:
Format16bpp565
Format16bpp555
And for Format16bppArgb1555 result a transparent image.
The pixel format Format16bppGrayScale exists in System.Drawing, but it is not actually implemented or supported. That's why it gives an error when trying to save it.
If this is indeed 16 bpp greyscale data, the only way to solve this in System.Drawing namespace is to reduce your data from 16-bit to 8-bit, treat it as an indexed (paletted) image, and just give it a grey fade from [0,0,0] to [255,255,255] as colour palette.
public static void SaveImage(short[] data, int width, int height, string path)
{
int dataLen = data.Length;
// This might not equal the width.
int inputStride = dataLen / height;
byte[] sourceData = new byte[dataLen];
// Reduce Int16 to bytes by downshifting the data by 8 bits.
// Effectively this divides the number by 256.
for (int i = 0; i < dataLen; ++i)
sourceData[i] = (Byte) (data[i] >> 8);
// Make an 8bpp image
using (Bitmap pic = new Bitmap(width, height, PixelFormat.Format8bppIndexed))
{
BitmapData picData = pic.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, pic.PixelFormat);
// Get actual stride from BitmapData
Int32 targetStride = picData.Stride;
Int64 scan0 = picData.Scan0.ToInt64();
// Stride is ALWAYS rounded up to the next multiple of 4, so copy line by line to avoid issues.
for (int y = 0; y < height; ++y)
Marshal.Copy(sourceData, y * inputStride, new IntPtr(scan0 + y * targetStride), width);
pic.UnlockBits(picData);
// Requesting Bitmap.Palette makes a COPY, so get it out, edit it, and then reassign it.
ColorPalette pal = pic.Palette;
for (int i = 0; i < 256; ++i)
pal.Entries[i] = Color.FromArgb(i, i, i);
pic.Palette = pal;
pic.Save(path, ImageFormat.Png);
}
}
Related
I am trying to extract a specific area from a bitmap for further processing. In rare cases an error occurs when Marshal.Copy is called. This can be reproduced with the following example code:
Bitmap bitmap = new Bitmap(1741, 2141, PixelFormat.Format1bppIndexed);
int zoneWidth = 50;
int zoneHeight = 50;
int x = 168;
int y = bitmap.Height - zoneHeight;
Rectangle zone = new Rectangle(x, y, zoneWidth, zoneHeight);
BitmapData bitmapData = bitmap.LockBits(zone, ImageLockMode.ReadOnly, bitmap.PixelFormat);
int byteCount = Math.Abs(bitmapData.Stride) * bitmapData.Height;
byte[] pixels = new byte[byteCount];
Marshal.Copy(bitmapData.Scan0, pixels, 0, byteCount);
// some further processing
bitmap.UnlockBits(bitmapData);
In other posts I have read that Stride can be negative. That is not the case here.
Why does the error occur and how can I prevent it?
Edit 1:
I have implemented the second suggestion of JonasH. But that also fails with the AccessViolationException. Probably I did not do that correctly.
Bitmap bitmap = new Bitmap(1741, 2141, PixelFormat.Format1bppIndexed);
int zoneWidth = 50;
int zoneHeight = 50;
int zoneX = 168;
int zoneY = bitmap.Height - zoneHeight;
Rectangle zone = new Rectangle(zoneX, zoneY, zoneWidth, zoneHeight);
BitmapData bitmapData = bitmap.LockBits(zone, ImageLockMode.ReadOnly, bitmap.PixelFormat);
int rowSize = Math.Abs(bitmapData.Stride);
byte[] pixels = new byte[bitmapData.Height * rowSize];
IntPtr iptr = bitmapData.Scan0;
for (int y = 0; y < bitmapData.Height; y++)
{
Marshal.Copy(IntPtr.Add(iptr, y * rowSize),
pixels,
y * rowSize,
rowSize);
}
bitmap.UnlockBits(bitmapData);
This is probably because you are only locking part of the bitmap. Replace the zone with new Rectangle(0, 0, bitmap.Width , bitmap.Height); and I would expect your problem to disappear.
The alternative would be to restrict the copy-operation to the locked part of the bitmap, but that would require copying row by row and not the entire bitmap at once.
Copying row by row needs careful usage of offsets, you need to keep track of both the horizontal and vertical offsets of both the source and target data. I think something like this should work:
for (int y = 0; y < zoneHeight ; y++)
{
Marshal.Copy(
IntPtr.Add(iptr,(y + zoneY ) * bitmapData.Stride + zoneX)
pixels,
y * zoneWidth,
zoneWidth );
}
I can't quite seem to wrap my brain around images and converting them from a byte[] of raw RGB colors to a BitMap. I found one solution that allows me to convert an RGB 24bpp byte[] to a BitMap using SetPixel, but I have read that using LockBits is much faster, so I am trying to figure out how to do it that way.
Using the SetPixel method, I am getting an inverted image using:
public static Bitmap CreateBitmap24bppRgb(byte[] bmpData, int width, int height)
{
var bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
var pos = 0;
for (var y = 0; y < height; y++)
{
for (var x = 0; x < width; x++)
{
bmp.SetPixel(x, y, Color.FromArgb(bmpData[pos], bmpData[pos + 1], bmpData[pos + 2]));
pos += 3;
}
}
return bmp;
}
Which I can't quite seem to figure out how to invert. But when I try to use LockBits, the image is just black, and I am unsure what I am doing wrong, it seems quite straight forward.
public static Bitmap CreateBitmap24bppRgb(byte[] data, int width, int height)
{
var bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
//Create a BitmapData and Lock all pixels to be written
var bmpData = bmp.LockBits(
new Rectangle(0, 0, bmp.Width, bmp.Height),
ImageLockMode.WriteOnly, bmp.PixelFormat);
//Copy the data from the byte array into BitmapData.Scan0
for (int y = 0; y < bmp.Height - 1; y++)
{
Marshal.Copy(data, y * bmp.Width, bmpData.Scan0 bmpData.Stride);
}
//Unlock the pixels
bmp.UnlockBits(bmpData);
return bmp;
}
I'm just curious what is going wrong here?
If you're creating a new bitmap, instead of modifying an existing one, there's no reason to use LockBits or Marshal.Copy.
Just go with the Bitmap constructor that takes a pointer to pixel data.
public static Bitmap CreateBitmap24bppRgb(byte[] data, int width, int height)
{
GCHandle pin = GCHandle.Alloc(data, GCHandleType.Pinned);
var bmp = new Bitmap(width, height,
(width * 3 + 3) / 4 * 4,
PixelFormat.Format24bppRgb,
Marshal.UnsafeAddrOfPinnedArrayElement(data, 0));
bmp = (Bitmap)bmp.Clone(); // workaround the requirement that the memory address stay valid
// the clone step can also crop and/or change PixelFormat, if desired
GCHandle.Free(pin);
return bmp;
}
(or use an unsafe block, pinned keyword, and a pointer)
I need to create an image in memory (can be huge image!) and to extract from it byte array in the size of width x height. Each byte must have value of 0-255 (256 gray scale values: 0 for white and 255 for black).
The part of creating the image is easy, here is a simple example of my code:
img = new Bitmap(width, height);
drawing = Graphics.FromImage(img);
drawing.Clear(Color.Black);// paint the background
drawing.DrawString(text, font, Brushes.White, 0, 0);
Problem is to convert it to "my" special gray scale byte array. When I'm using any pixel format other then Format8bppIndexed, the byte array I'm getting from the bitmap is not in the size I need (width*length) so I need a conversion that takes too much time. When I'm using Format8bppIndexed I'm getting the byte array very fast and in the right size, but each byte/pixel is 0-15.
Changing the bitmap palette has no affect:
var pal = img.Palette;
for (int i = 1; i < 256; i++){
pal.Entries[i] = Color.FromArgb(255, 255, 255);
}
img.Palette = pal;
Any idea how to do it?
Edit: Full code:
// assume font can be Times New Roman, size 7500!
static private Bitmap DrawText(String text, Font font)
{
//first, create a dummy bitmap just to get a graphics object
var img = new Bitmap(1, 1);
var drawing = Graphics.FromImage(img);
//measure the string to see how big the image needs to be
var textSize = drawing.MeasureString(text, font);
//free up the dummy image and old graphics object
img.Dispose();
drawing.Dispose();
//create a new image of the right size (must be multiple of 4)
int width = (int) (textSize.Width/4) * 4;
int height = (int)(textSize.Height / 4) * 4;
img = new Bitmap(width, height);
drawing = Graphics.FromImage(img);
// paint the background
drawing.Clear(Color.Black);
drawing.DrawString(text, font, Brushes.White, 0, 0);
var bmpData = img.LockBits(new Rectangle(0, 0, img.Width, img.Height), ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);
var newBitmap = new Bitmap(width, height, bmpData.Stride, PixelFormat.Format8bppIndexed, bmpData.Scan0);
drawing.Dispose();
return newBitmap;
}
private static byte[] GetGrayscleBytesFastest(Bitmap bitmap)
{
BitmapData bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
int numbytes = bmpdata.Stride * bitmap.Height;
byte[] bytedata = new byte[numbytes];
IntPtr ptr = bmpdata.Scan0;
Marshal.Copy(ptr, bytedata, 0, numbytes);
bitmap.UnlockBits(bmpdata);
return bytedata;
}
You probably want to do this in two steps. First, create a 16bpp grayscale copy of your original image as described in Convert an image to grayscale.
Then, create your 8bpp image with the appropriate color table and draw the 16bpp grayscale image onto that image. That will do the conversion for you, converting the 16-bit grayscale values to your 256 different colors.
You should then have an 8bpp image with your 256 different shades of gray. You can then call LockBits to get access to the bitmap bits, which will be index values in the range 0 to 255.
I have solved this problem with ImageSharp
I calculate the gray value from the rgb values and then add it to the array.
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
private static byte[] GetImageData(byte[] imageData)
{
using (var image = Image.Load<Rgba32>(imageData))
{
var buffer = new byte[image.Width * image.Height];
var index = 0;
image.ProcessPixelRows(accessor =>
{
for (int y = 0; y < accessor.Height; y++)
{
Span<Rgba32> pixelRow = accessor.GetRowSpan(y);
for (int x = 0; x < pixelRow.Length; x++)
{
ref Rgba32 pixel = ref pixelRow[x];
buffer[index] = (byte)((pixel.R + pixel.G + pixel.B) / 3);
index++;
}
}
});
return buffer;
}
}
I am trying to combine 3 grayscale bitmaps into one color bitmap. All three grayscale images are the same size (this is based off of data from the Hubble). My logic is:
Load "blue" image and convert to PixelFormat.Format24bppRgb. Based off of that create a new byte array that is 4 times as large as the blue data array length/3 (so it will be one byte for blue, one byte for green, one byte for red, one byte for alpha per pixel since my system is little endian). Populate the "blue" bytes of the array from the "blue" bytes of the blue image (and in this first loop set the alpha byte to 255). I then load the green and red bitmaps, convert them to PixelFormat.Format24bppRgb, and pull the g/r value and add it to the correct place in the data array. The final data array then has the bgra bytes set correctly from what I can tell.
When I have the data array populated, I have used it to:
Create a PixelFormats.Bgra32 BitmapSource then convert that to a Bitmap.
Create a PixelFormat.Format32bppArgb Bitmap using the Bitmap constructor (width, height, stride, PixelForma, IntPtr)
Create a PixelFormat.Format32bppArgb Bitmap using pointers
All three ways of creating a return bitmap result in the image being "skewed" (sorry, I don't know of a better word).
The actual output (of all three ways of generating the final bitmap) is: Actual output
The desired output is something like (this was done in photoshop so it is slightly different): Desired output
The three file names (_blueFileName, _greenFileName, _redFileName) are set in the constructor and I check to make sure the files exist before creating the class. I can post that code if anyone wants it.
Can anyone tell me what I am doing wrong? I am guessing that is is due to the stride or something like that?
Note: I can't post the links to the images I am using as input as I don't have 10 reputation points. Maybe I could send the links via email or something if someone wants them as well.
Here is my code (with some stuff commented out, the comments describe what happens if each commented out block is used instead):
public Bitmap Merge()
{
// Load original "blue" bitmap.
Bitmap tblueBitmap = (Bitmap)Image.FromFile(_blueFileName);
int width = tblueBitmap.Width;
int height = tblueBitmap.Height;
// Convert to 24 bpp rgb (which is bgr on little endian machines)
Bitmap blueBitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb);
using (Graphics gr = Graphics.FromImage(blueBitmap))
{
gr.DrawImage(tblueBitmap, 0, 0, width, height);
}
tblueBitmap.Dispose();
// Lock and copy to byte array.
BitmapData blueData = blueBitmap.LockBits(new Rectangle(0, 0, blueBitmap.Width, blueBitmap.Height), ImageLockMode.ReadOnly,
blueBitmap.PixelFormat);
int numbBytes = blueData.Stride*blueBitmap.Height;
byte[] blueBytes = new byte[numbBytes];
Marshal.Copy(blueData.Scan0, blueBytes, 0, numbBytes);
blueBitmap.UnlockBits(blueData);
blueData = null;
blueBitmap.Dispose();
int mult = 4;
byte[] data = new byte[(numbBytes/3)*mult];
int count = 0;
// Copy every third byte starting at 0 to the final data array (data).
for (int i = 0; i < data.Length / mult; i++)
{
// Check for overflow
if (blueBytes.Length <= count*3 + 2)
{
continue;
}
// First pass, set Alpha channel.
data[i * mult + 3] = 255;
// Set blue byte.
data[i*mult] = blueBytes[count*3];
count++;
}
// Cleanup.
blueBytes = null;
int generation = GC.GetGeneration(this);
GC.Collect(generation);
Bitmap tgreenBitmap = (Bitmap)Image.FromFile(_greenFileName);
Bitmap greenBitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb);
using (Graphics gr = Graphics.FromImage(greenBitmap))
{
gr.DrawImage(tgreenBitmap, 0, 0, width, height);
}
tgreenBitmap.Dispose();
BitmapData greenData = greenBitmap.LockBits(new Rectangle(0, 0, greenBitmap.Width, greenBitmap.Height), ImageLockMode.ReadOnly,
greenBitmap.PixelFormat);
numbBytes = greenData.Stride * greenBitmap.Height;
byte[] greenBytes = new byte[numbBytes];
Marshal.Copy(greenData.Scan0, greenBytes, 0, numbBytes);
greenBitmap.UnlockBits(greenData);
greenData = null;
greenBitmap.Dispose();
count = 0;
for (int i = 0; i < data.Length / mult; i++)
{
if (greenBytes.Length <= count * 3 + 1)
{
continue;
}
// Set green byte
data[i * mult + 1] = greenBytes[count * 3 + 1];
count++;
}
greenBytes = null;
generation = GC.GetGeneration(this);
GC.Collect(generation);
Bitmap tredBitmap = (Bitmap)Image.FromFile(_redFileName);
Bitmap redBitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb);
using (Graphics gr = Graphics.FromImage(redBitmap))
{
gr.DrawImage(tredBitmap, 0, 0, width, height);
}
tredBitmap.Dispose();
BitmapData redData = redBitmap.LockBits(new Rectangle(0, 0, redBitmap.Width, redBitmap.Height), ImageLockMode.ReadOnly,
redBitmap.PixelFormat);
numbBytes = redData.Stride * redBitmap.Height;
byte[] redBytes = new byte[numbBytes];
Marshal.Copy(redData.Scan0, redBytes, 0, numbBytes);
redBitmap.UnlockBits(redData);
redData = null;
redBitmap.Dispose();
count = 0;
for (int i = 0; i < data.Length / mult; i++)
{
if (redBytes.Length <= count * 3+2)
{
count++;
continue;
}
// set red byte
data[i * mult + 2] = redBytes[count * 3 + 2];
count++;
}
redBytes = null;
generation = GC.GetGeneration(this);
GC.Collect(generation);
int stride = (width*32 + 7)/8;
var bi = BitmapSource.Create(width, height, 96, 96, PixelFormats.Bgra32, null, data, stride);
// uncomment out below to see what a bitmap source to bitmap does. So far, it is exactly the same as
// the uncommented out lines below.
// ---------------------------------------------------------------------------------------------------
//return BitmapImage2Bitmap(bi);
unsafe
{
fixed (byte* p = data)
{
IntPtr ptr = (IntPtr)p;
// Trying the commented out lines returns the same bitmap as the uncommented out lines.
// ------------------------------------------------------------------------------------
byte* p2 = (byte*)ptr;
Bitmap retBitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
BitmapData fData = retBitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite,
PixelFormat.Format32bppArgb);
unsafe
{
for (int i = 0; i < fData.Height; i++)
{
byte* imgPtr = (byte*)(fData.Scan0 + (fData.Stride * i));
for (int x = 0; x < fData.Width; x++)
{
for (int ii = 0; ii < 4; ii++)
{
*imgPtr++ = *p2++;
}
//*imgPtr++ = 255;
}
}
}
retBitmap.UnlockBits(fData);
//Bitmap retBitmap = new Bitmap(width, height, GetStride(width, PixelFormat.Format32bppArgb),
// PixelFormat.Format32bppArgb, ptr);
return retBitmap;
}
}
}
private Bitmap BitmapImage2Bitmap(BitmapSource bitmapSrc)
{
using (MemoryStream outStream = new MemoryStream())
{
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bitmapSrc));
enc.Save(outStream);
Bitmap bitmap = new Bitmap(outStream);
return new Bitmap(bitmap);
}
}
private int GetStride(int width, PixelFormat pxFormat)
{
int bitsPerPixel = ((int)pxFormat >> 8) & 0xFF;
int validBitsPerLine = width * bitsPerPixel;
int stride = ((validBitsPerLine + 31) / 32) * 4;
return stride;
}
You are missing the gap between the lines. The Stride value is not the amount of data in a line, it's the distance between the start of one line to the next. There may be a gap at the end of each line to align the next line on an even address boundary.
The Stride value can even be negative, then the image is stored upside down in memory. To get the data without the gaps and to handle all cases you need to copy one line at a time:
BitmapData blueData = blueBitmap.LockBits(new Rectangle(0, 0, blueBitmap.Width, blueBitmap.Height), ImageLockMode.ReadOnly, blueBitmap.PixelFormat);
int lineBytes = blueBitmap.Width * 3;
int numbBytes = lineBytes * blueBitmap.Height;
byte[] blueBytes = new byte[numbBytes];
for (int y = 0; y < blueBitmap.Height; y++) {
Marshal.Copy(blueData.Scan0 + y * blueData.Stride, blueBytes, y * lineBytes, lineBytes);
}
blueBitmap.UnlockBits(blueData);
blueBitmap.Dispose();
I have 3 System.Drawing.Bitmap objects. A RGB foreground, RGB background, and a single byte per pixel mask image where 0 means take the background pixel and 1 means take the foreground pixel. All three are the same dimensions.
I chose to use the Bitmap objects because I need to eventually run this code in MonoTouch and MonoDroid. I can rethink that if needed.
The code I have is optimized but still seems slow. This is also the slowest part of the whole operation so I would like to optimize it more. I also can't help but think there is some secret method that will do all this for me.
If it helps. Prior to this point all 3 are byte[]'s which I turn into images and re-size to uniform dimensions. If I could do things better one step back then let me know.
The code below is what I am currently using and essentially updates the background image with the appropriate foreground pixels.
BitmapData backgroundData = background.LockBits(new System.Drawing.Rectangle(0, 0, background.Width, background.Height), ImageLockMode.ReadOnly, background.PixelFormat);
int backgroundPixelSize = GetPixelSize(backgroundData);
BitmapData foregroundData = foreground.LockBits(new System.Drawing.Rectangle(0, 0, foreground.Width, foreground.Height), ImageLockMode.ReadOnly, foreground.PixelFormat);
int foregroundPixelSize = GetPixelSize(foregroundData);
BitmapData maskData = mask.LockBits(new System.Drawing.Rectangle(0, 0, mask.Width, mask.Height), ImageLockMode.ReadOnly, mask.PixelFormat);
//int maskPixelSize = GetPixelSize(maskData);
for (int y = 0; y < background.Height; y++)
{
byte* backgroundRow = (byte*)backgroundData.Scan0 + (y * backgroundData.Stride);
byte* foregroundRow = (byte*)foregroundData.Scan0 + (y * foregroundData.Stride);
byte* maskRow = (byte*)maskData.Scan0 + (y * maskData.Stride);
for (int x = 0; x < background.Width; x++)
{
// Check if the mask byte is set
if (maskRow[x] > 0)
{
// Copy the bytes over
for (int p = 0; p < backgroundPixelSize; p++)
{
backgroundRow[x * backgroundPixelSize + p] = foregroundRow[x * foregroundPixelSize + p];
}
}
}
}
Update:
The two images are 3 bytes per pixel and the mask image is 1 byte per pixel.
You can try this code. I think it's more fastly and clear (in case of all three images have same sizes).
BitmapData backgroundData = background.LockBits(
new System.Drawing.Rectangle(0, 0, background.Width, background.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
BitmapData foregroundData = foreground.LockBits(
new System.Drawing.Rectangle(0, 0, foreground.Width, foreground.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
BitmapData maskData = mask.LockBits(
new System.Drawing.Rectangle(0, 0, mask.Width, mask.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
uint* backgroundPtr = (uint*)backgroundData.Scan0;
uint* foregroundPtr = (uint*)foregroundData.Scan0;
uint* maskPtr = (uint*)maskData.Scan0;
int dataLength = backgroundData.Height * backgroundData.Width;
for (int i = 0; i < dataLength; i++)
if (maskPtr[i] > 0)
backgroundPtr[i] = foregroundPtr[i];
UPDATE
Also it is possible to use mask PixelFormat:
BitmapData maskData = mask.LockBits(
new System.Drawing.Rectangle(0, 0, mask.Width, mask.Height),
ImageLockMode.ReadOnly, mask.PixelFormat);
byte* maskPtr = (byte*)maskData.Scan0;
int dataLength = backgroundData.Height * backgroundData.Width;
for (int i = 0; i < dataLength; i++)
if (maskPtr[i] > 0)
backgroundPtr[i] = foregroundPtr[i];