I am working with a vimba camera, and I am trying to set up a histogram that gets updated on every frame incoming from the camera, in order to detect saturation of pixels (color value = 255). Incomming frames from the camera are placed in bitmaps with PixelFormat = fromat8bppIndexed
(grayscale) at a 15-20 FPS rate.
The way my histogram works is the following : I lock bits from a bitmap, sweeps across the image, retrieve the colour info for each pixel, and increments the corresponding index in an array (ex : if a pixel has got a color intensity of 126, I increment array[126] by one). At the end of the sweep, I have an array[256], and each of its value corresponds to the number of pixels with that particular color intensity. I then just have to draw my histogram using the array index as X, and the array values as y. I tested the code on random bitmaps (not from the camera), and it works perfectly.
The histogram code is placed inside the OnFrameReceived(Frame)
function from the Vimba API, which use is the following : "Event will be triggered when a Frame buffer is filled with data" (from Vimba API manual). I know there is no problem with the delegate because part of the code inside the function works perfectly.
I had written a previous version of the code using GetPixels
, but I read that it was a very slow way to retrieve data from an image, so I switched to using LockBits
instead. I know I got the syntax right because I tested it outside of the OnFrameReceived
function, and it works (way faster than GetPixels
).
Now my problem is that, when I start the acquisition, the histogram doesn't fill with the data.
Here is the code :
private void OnFrameReceived(Frame frame)
{
Bitmap myBitmap = null;
if (true == m_Acquiring)
{
mycamera.QueueFrame(frame);
}
frame.Fill(ref myBitmap);
pictureBoxLiveCamera.Image = myBitmap;
SaveBitmap = myBitmap; //Up to here the code works perfectly, as I can use SaveBitmap correctly later in my program
//Emptying chartInit
Array.Clear(PixelColorCount, 0, 256);
foreach (var Series in chartHist.Series)
{
Series.Points.Clear();
}
//Retrieving pixels data
unsafe
{
int width = SaveBitmap.Width;
int height = SaveBitmap.Height;
int bytesPerPixel = 1;
int maxPointerLength = width * height * bytesPerPixel;
int stride = width * bytesPerPixel;
System.Drawing.Imaging.BitmapData bData = SaveBitmap.LockBits(new System.Drawing.Rectangle(0, 0, SaveBitmap.Width, SaveBitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, SaveBitmap.PixelFormat);
byte* scan0 = (byte*)bData.Scan0.ToPointer();
byte B;
for (int i = 1; i < maxPointerLength; i++)
{
B = scan0[i];
PixelColorCount[B] += 1;
}
SaveBitmap.UnlockBits(bData);
}
//Plotting the pixel counter, to detect saturation
for (int i = 0; i < PixelColorCount.Length; i++)
{
chartHist.Series["Pixel count"].Points.AddXY(i, PixelColorCount[i]);
}
}
Does anyone have an idea what could be wrong with my code ? If nothing's wrong, could this have something to do with the computing time being to long and the frame being refreshed too fast ? How to check for this ? What could I do to fix it ?
Thanks !
EDIT : The call for the OnFrameReceived
event is triggered on the Button Click event, here is the code with the handler :
this.m_Acquiring = true;
mycamera.OnFrameReceived += new Camera.OnFrameReceivedHandler(this.OnFrameReceived);
mycamera.StartContinuousImageAcquisition(1);
I just did a few tests with breakdown points in the code, and it seems that the Emptying chartInit
part runs (breakdown points reached), but the foreach
loop runs indefinitely. This is probably the problem.