1

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 OnFrameReceivedfunction, 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 OnFrameReceivedevent 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.

Trion
  • 115
  • 11
  • I can image that 20+ fps is a little too fast, but you still should see at least some data in the chart. What do you see when you set a breakpoint in the last loop? Are the data credible? – TaW Apr 30 '18 at 12:51
  • Also: I'm not really sure about the way you read the pixel data. I don't think there is a guaratee that how the palette is structured or even its size. You probably need to read it first and analyze it. But I never read 8bpp images, so I don't really know. – TaW Apr 30 '18 at 13:03
  • @TaW So, if I put a breakdown in the last `for{}` loop and run the code, it doesn't seem to ever reach the breakpoint. Could that indicate that frames are changing too fast for the code to run properly ? – Trion Apr 30 '18 at 13:07
  • 1
    About the pixel reading method, I get the same result this way that with my old `GetPixel` code, so I guess it is fine. – Trion Apr 30 '18 at 13:08
  • Assuming PixelColorCount.Length is > 0, maybe. Do you ever hit the for loop itself? Also: Do add a little on how the event is called.. – TaW Apr 30 '18 at 13:16
  • @TaW It's done. I also added info about a few breakdown points tests I just did. – Trion Apr 30 '18 at 13:46
  • Hm, is there any kind of mulithreading involved? – TaW Apr 30 '18 at 14:32
  • I never knowingly activated this, and there is no mention of "threads" or "threading" in my code (I searched), so I guess no. I am fairly new with C# and coding as a whole, so I may be wrong. – Trion Apr 30 '18 at 14:44
  • You should check if you are on the main thread before updating any ui controls by [invoking](https://stackoverflow.com/a/14703806) – PSchn Jun 14 '18 at 18:09

0 Answers0