well i'm developing an eyetracker. So i manage to get my 2 cams going, but when i call the following method the program throws "Object is currently in use elsewhere" exception on Application.Run(...).
public void processImage(Bitmap bitmap)
{
Bitmap aq = bitmap.Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), PixelFormat.Format24bppRgb);
Invert a = new Invert();
aq = a.Apply(aq);
AForge.Imaging.Image.FormatImage(ref aq);
IFilter filter = Grayscale.CommonAlgorithms.BT709;
aq = filter.Apply(aq);
Threshold th = new Threshold(200);
aq = th.Apply(aq);
//find the biggest blob
BlobCounter bl = new BlobCounter(aq);
int i = bl.ObjectsCount;
Blob bigblob = null;
int areaant = 0;
Blob[] blobs = bl.GetObjects(aq, true);
for (int j = 0; j < i; j++)
{
if (blobs[j].Area == 1116)
{
j++;
if (j == i)
break;
}
if (blobs[j].Area > areaant)
{
areaant = blobs[j].Area;
bigblob = blobs[j];
}
}
Bitmap bitmap2 = bitmap.Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), PixelFormat.Format24bppRgb);
Graphics g = Graphics.FromImage(bitmap2);
int radius = 1;
int x = 0;
int y = 0;
int h = 25;
Pen redPen = new Pen(Color.Red, 2);
if (i > 1)
{
Blob fil2 = bigblob;
x = fil2.CenterOfGravity.X;
y = fil2.CenterOfGravity.Y;
g.DrawEllipse(redPen,
(int)(x - radius),
(int)(y - radius),
(int)(radius * 5),
(int)(radius * 5));
}
redPen.Dispose();
g.Dispose();
pictureBox1.Image = bitmap2;
pictureBox2.Image = aq;
}
So i imagine it has to do with the bitmap cloning method, because sometimes it throws the exception there.
Reading diferent problems of other people and their soultion, i've tried several things:
-Starting each cam with a diferent thread with the same form
-in other solution they suggested that the problem was that the two threads where accesing the bitmap. So i separate the forms, one for each camera (thread), and then i tried to use the method procesImage(..) in only one thread. Didn't work.
Any help would be much appreciated
Related
I have a question that how can we get pixels of only last row of an image and display that row in a picturebox of C# application.
The easiest (but also fastest) way I see is to use the following Bitmap Constructor (Int32, Int32, Int32, PixelFormat, IntPtr) overload in combination with Bitmap.LockBits / Bitmap.UnlockBits like this
static Bitmap GetLastRow(Bitmap source)
{
var data = source.LockBits(new Rectangle(0, source.Height - 1, source.Width, 1), ImageLockMode.ReadOnly, source.PixelFormat);
try { return new Bitmap(data.Width, data.Height, data.Stride, data.PixelFormat, data.Scan0); }
finally { source.UnlockBits(data); }
}
In general you can use this code to crop any rectangular part of a bitmap by just changing the new Rectangle(...) part.
Update: It turns out that there is even a predefined method - Bitmap.Clone(Rectangle, PixelFormat), so the code could be simply
Bitmap source = ...;
var lastRow = source.Clone(new Rectangle(0, source.Height - 1, source.Width, 1), source.PixelFormat);
public Bitmap LastRow(Bitmap source)
{
int y = source.Height - 1;
Bitmap newSource = new Bitmap(source.Width, 1);
for (int x = 0; x < source.Width; x++)
{
NewSource.SetPixel(x, y, Source.GetPixel(x, y));
}
return newSource;
}
Sample usage:
pictureBox1.Image = LastRow(yourImage);
Probably not the fastest way, but should work:
Bitmap image1 = new Bitmap(#"picture.bmp");
Bitmap image2 = new Bitmap(image1.Width, 1, image1.PixelFormat);
for (int i = 0; i < image1.Width; i++)
{
image2.SetPixel(i, 0, image1.GetPixel(i, image1.Height - 1));
}
pictureBox1.Image = image2;
I'm trying to convert an array of bytes to Bitmap image using following code:
using (Graphics g = Graphics.FromImage(tilePage))
g.Clear(Color.Black);
for (int i = 0; i + offset < ROM.Length && i < tilePage.Height; i++)
{
int I = i * tilePage.Width + offset; //+Offset;
for (int j = 0; j < tilePage.Width; j++)
{
if (I + j >= ROM.Length)
goto finishRender;
tilePage.SetPixel(j, i, RPallete.getColor(ROM[I + j]));
}
}
finishRender:
picTileView.Image = tilePage;
but it renders too slow (2-3 seconds for 256*512 resolution). How to make it faster for example as in TileLayer?
P.S.: Sorry for bad English...
You can use pointer. I used recently this code. You can improve as you wish
add picturebox that named pctResim
Check allow unsafe on project properties
Try this :
byte siyah=0;
int dizisayisi;
IntPtr baslangic;
byte[] rgbdeger;
Bitmap resim;
Rectangle rct;
BitmapData bmData;
resim = new Bitmap(#"C:\YazilimGrubu.jpg");
rct = new Rectangle(0, 0, resim.Width, resim.Height);
bmData = resim.LockBits(rct, ImageLockMode.ReadWrite, resim.PixelFormat);
baslangic = bmData.Scan0;
dizisayisi = bmData.Stride * resim.Height;
rgbdeger = new byte[dizisayisi];
Marshal.Copy(baslangic, rgbdeger, 0, dizisayisi);
for (int i = 2; i < rgbdeger.Length; i += 3)
{
siyah = (Byte)Math.Abs((Byte.Parse(rgbdeger[i - 2].ToString()) + Byte.Parse(rgbdeger[i - 1].ToString()) + Byte.Parse(rgbdeger[i].ToString())) / 3);
rgbdeger[i - 2] = siyah;
rgbdeger[i - 1] = siyah;
rgbdeger[i] = siyah;
}
Marshal.Copy(rgbdeger, 0, baslangic, dizisayisi);
resim.UnlockBits(bmData);
pctResim.Image = resim;
I have some c# code that works fine on Vista & Windows 7 but throws a GDI+ Error on Windows XP (with service pack 3 installed).
Error thrown on XP
System.Runtime.INteropServices.ExternalException(0x80004005): A generic error occured in GDI+
at System.Drawing.Graphics.CheckErrorStatus(Int32Status)
at System.Drawing.Graphics.DrawImage(Image image, Int32 x, Int32 y)
At System.Drawing.Graphics.DrawImageUnscaled(Image image, Int32 x,Int 32 y)
at mysolution.Core.ImageTools.ConvertToBitonal(Bitmap orginal, Int32 threshold)
Code breaks on this line:
using (var g = Graphics.FromImage(source))
{
g.DrawImageUnscaled(original, 0, 0); // Error Is Thrown Here
}
WpFAppTestingConvertToBitonalCS
....
Below is the full function I'm calling.
public static Bitmap ConvertToBitonal(Bitmap original, int threshold)
{
Bitmap source;
// If original bitmap is not already in 32 BPP, ARGB format, then convert
if (original.PixelFormat != PixelFormat.Format32bppArgb)
{
source = new Bitmap(original.Width, original.Height, PixelFormat.Format32bppArgb);
source.SetResolution(original.HorizontalResolution, original.VerticalResolution);
using (var g = Graphics.FromImage(source))
{
g.DrawImageUnscaled(original, 0, 0);
}
}
else
{
source = original;
}
// Lock source bitmap in memory
var sourceData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
// Copy image data to binary array
var imageSize = sourceData.Stride * sourceData.Height;
var sourceBuffer = new byte[imageSize];
Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, imageSize);
// Unlock source bitmap
source.UnlockBits(sourceData);
// Create destination bitmap
var destination = new Bitmap(source.Width, source.Height, PixelFormat.Format1bppIndexed);
destination.SetResolution(original.HorizontalResolution, original.VerticalResolution);
// Lock destination bitmap in memory
var destinationData = destination.LockBits(new Rectangle(0, 0, destination.Width, destination.Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);
// Create destination buffer
imageSize = destinationData.Stride * destinationData.Height;
var destinationBuffer = new byte[imageSize];
var sourceIndex = 0;
var destinationIndex = 0;
var pixelTotal = 0;
byte destinationValue = 0;
var pixelValue = 128;
var height = source.Height;
var width = source.Width;
// Iterate lines
for (var y = 0; y < height; y++)
{
sourceIndex = y * sourceData.Stride;
destinationIndex = y * destinationData.Stride;
destinationValue = 0;
pixelValue = 128;
// Iterate pixels
for (var x = 0; x < width; x++)
{
// Compute pixel brightness (i.e. total of Red, Green, and Blue values) - Thanks murx
// B G R
pixelTotal = sourceBuffer[sourceIndex] + sourceBuffer[sourceIndex + 1] + sourceBuffer[sourceIndex + 2];
if (pixelTotal > threshold)
{
destinationValue += (byte)pixelValue;
}
if (pixelValue == 1)
{
destinationBuffer[destinationIndex] = destinationValue;
destinationIndex++;
destinationValue = 0;
pixelValue = 128;
}
else
{
pixelValue >>= 1;
}
sourceIndex += 4;
}
if (pixelValue != 128)
{
destinationBuffer[destinationIndex] = destinationValue;
}
}
// Copy binary image data to destination bitmap
Marshal.Copy(destinationBuffer, 0, destinationData.Scan0, imageSize);
// Unlock destination bitmap
destination.UnlockBits(destinationData);
// Dispose of source if not originally supplied bitmap
if (source != original)
{
source.Dispose();
}
// Return
return destination;
}
I hate GDI+ exception handling, the only error it fires is A generic error occured in GDI+, Try this
Bitmap source = new Bitmap(0, 0);
using (Graphics g = Graphics.FromImage(source))
{ g.Clear(Color.White);
g.Graphics.DrawImageUnscaled(your original source,0,0);
}
I have some code which has the error "AccessViolationException was unhandled by user code: Attempted to read or write protected memory..."
A trimmed down version of the offending function is as follows:
protected override void OnPaint(PaintEventArgs pe)
{
if ((updatingFastBackground) || (Calculating)) return; //ADDED FOR DEBUGGING, SEE BELOW
BitmapData canvasData = Canvas.LockBits(new Rectangle(Point.Empty, Canvas.Size), ImageLockMode.WriteOnly, FastPixelFormat);
BitmapData fbgData = fastBackground.LockBits(new Rectangle(Point.Empty, fastBackground.Size), ImageLockMode.ReadOnly, FastPixelFormat);
try
{
unsafe
{
byte* canvasDataScan0 = (byte*)canvasData.Scan0.ToPointer();
byte* fbgDataScan0 = (byte*)fbgData.Scan0.ToPointer();
Rectangle spriteBounds = new Rectangle(Point.Empty, ButtonImages.ImageSize);
for (int i = 0; i < ButtonImages.Images.Count; i++)
{
// Button offset location
Point l = new Point(
(int)((i % columnCount) * hStep + myIVM.Location.X),
(int)((i / columnCount) * vStep + myIVM.Location.Y));
// Paint at current location?
if (buttonPaintBounds.Contains(l))
{
BitmapData spriteData = buttonBitmaps[i].LockBits(spriteBounds, ImageLockMode.ReadOnly, FastPixelFormat);
try
{
int spriteLeft = Math.Max(l.X, 0);
int spriteRight = Math.Min(l.X + ButtonImages.ImageSize.Width, canvasData.Width);
int spriteTop = Math.Max(l.Y, 0);
int spriteBottom = Math.Min(l.Y + ButtonImages.ImageSize.Height, canvasData.Height);
int spriteWidth = spriteRight - spriteLeft;
int spriteHeight = spriteBottom - spriteTop;
byte* canvasRowLeft = canvasDataScan0 + (spriteTop * canvasData.Stride) + spriteLeft * 4;
byte* spriteRowLeft =
(byte*)spriteData.Scan0.ToPointer() +
Math.Max((spriteTop - l.Y), 0) * spriteData.Stride +
Math.Max((spriteLeft - l.X), 0) * 4;
for (int y = 0; y < spriteHeight; y++)
{
canvasRowLeft += canvasData.Stride;
spriteRowLeft += spriteData.Stride;
Byte* canvasWalk = (Byte*)canvasRowLeft;
Byte* spriteWalk = (Byte*)spriteRowLeft;
for (int x = 0; x < spriteWidth; x++)
{
if (spriteWalk[3] != 255)
{
canvasWalk[0] = (byte)(canvasWalk[0] * spriteWalk[3] / 255 + spriteWalk[0]);
canvasWalk[1] = (byte)(canvasWalk[1] * spriteWalk[3] / 255 + spriteWalk[1]);
canvasWalk[2] = (byte)(canvasWalk[2] * spriteWalk[3] / 255 + spriteWalk[2]);
}
canvasWalk += 4;
spriteWalk += 4;
}
}
thesePoints.Add(l);
}
finally
{
buttonBitmaps[i].UnlockBits(spriteData);
}
}
The error occurs on the line:
canvasWalk[0] = (byte)(canvasWalk[0] * spriteWalk[3] / 255 + spriteWalk[0]);
and even when replaced with:
canvasWalk[0] = 0;
The iteration variables y and x have different values each time it crashes so this leads me to believe an external function is modifying the Canvas bitmap.
IF this is in fact my problem, is there a way to prevent fastBackground and Canvas from being externally modified? I thought LockBits was supposed to do that that...
If that's not enough to answer, here's some more I've tried:
I added the line
if ((updatingFastBackground) || (Calculating)) return;
to exit OnPaint if fastBackground Canvas or dimensions are being modified by other functions.
I could use a mutex to prevent the functions that modify the bitmaps fastBackground and Canvas from being run at the same time as paint (as I think they must be) but I'd rather block them another way as Canvas is public and I don't want to require passing a mutex out of the class.
per #usr 's suggestion, this further trimmed down version doesn't fail... Must have been a PTD error. (programmer too dumb) i.e. arithmetic error
protected override void OnPaint(PaintEventArgs pe)
{
if ((updatingFastBackground) || (Calculating)) return; //ADDED FOR DEBUGGING, SEE BELOW
BitmapData canvasData = Canvas.LockBits(new Rectangle(Point.Empty, Canvas.Size), ImageLockMode.WriteOnly, FastPixelFormat);
BitmapData fbgData = fastBackground.LockBits(new Rectangle(Point.Empty, fastBackground.Size), ImageLockMode.ReadOnly, FastPixelFormat);
try
{
unsafe
{
byte* canvasDataScan0 = (byte*)canvasData.Scan0.ToPointer();
byte* fbgDataScan0 = (byte*)fbgData.Scan0.ToPointer();
Rectangle spriteBounds = new Rectangle(Point.Empty, ButtonImages.ImageSize);
for (int i = 0; i < ButtonImages.Images.Count; i++)
{
// Button offset location
Point l = new Point(
(int)((i % columnCount) * hStep + myIVM.Location.X),
(int)((i / columnCount) * vStep + myIVM.Location.Y));
// Paint at current location?
if (buttonPaintBounds.Contains(l))
{
BitmapData spriteData = buttonBitmaps[i].LockBits(spriteBounds, ImageLockMode.ReadOnly, FastPixelFormat);
try
{
byte* canvasRowLeft = canvasDataScan0;
byte* spriteRowLeft = (byte*)spriteData.Scan0.ToPointer();
for (int y = 0; y < 145; y++)
{
canvasRowLeft += canvasData.Stride;
spriteRowLeft += spriteData.Stride;
Byte* canvasWalk = (Byte*)canvasRowLeft;
Byte* spriteWalk = (Byte*)spriteRowLeft;
for (int x = 0; x < 145; x++)
{
if (spriteWalk[3] != 255)
{
canvasWalk[0] = 0;
canvasWalk[1] = 0;
canvasWalk[2] = 0;
}
canvasWalk += 4;
spriteWalk += 4;
}
}
thesePoints.Add(l);
}
finally
{
buttonBitmaps[i].UnlockBits(spriteData);
}
}
Moving my comment into an answer because it helped solve the problem:
Fixed is not required for the buffer returned by LockBits because it is unmanaged memory. Your pointer arithmetic is wrong. Find the bug. Create a simple repro to help find the bug.
I'm trying to produce an image from the kinect where all pixel that do not represent a player will be set to black.
My idea is to use the data produced by the depthstream with player index along with the videostream to accomplish this task.
My hope was to do something like this:
byte[] pixelData = video.imageFrame.Bits;
byte[] depthData = depth.imageFrame.Bits;
var depthIndex = 0;
for (var y = 0; y < height; y++)
{
var heightOffset = y * width;
for (var x = 0; x < width; x++)
{
var index = (x + heightOffset) * 4;
var distance = GetDistanceWithPlayerIndex(depthData[depthIndex], depthData[depthIndex + 1]);
if (GetPlayerIndex(depthData[depthIndex]) == 0)
{
pixelData[index + BlueIndex] = 0;
pixelData[index + GreenIndex] = 0;
pixelData[index + RedIndex] = 0;
}
}
}
The issue that I am currently working on it trying to get the videostream data to have the same resolution as the depthwithplayerindex.
I've tried to piece some stuff together from other posts on here but I can't get it to work:
private byte[] ScaleVideoImage(ImageFrame imageFrame, int newWidth, int newHeight)
{
//convert imageFrame to byte array
Byte[] oPixelData = imageFrame.Image.Bits;
Image tempImage = BytesToImg(oPixelData);
//scale image
Bitmap bmp = new Bitmap(newWidth, newHeight);
using (Graphics graphics = Graphics.FromImage(bmp))
{
graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
graphics.DrawImage(tempImage, 0, 0, bmp.Width, bmp.Height);
}
//Convert image to byte array
MemoryStream ms1 = new MemoryStream();
bmp.Save(ms1, ImageFormat.Jpeg);
byte[] result = ms1.GetBuffer();
bmp.Dispose();
ms1.Close();
return result;
}
Any ideas?
Take a look at the code I've previously shared here: http://channel9.msdn.com/coding4fun/kinect/Display-Kinect-color-image-containing-only-players-aka-background-removal