2

I have a function called: DisplayAndSaveImageFromByteArray.

by its name you probably understand what i am trying to do. In the bytearray the values are pixeldata. so like this 255,220,130,0, etc..

The size of the byte is the Width and the Height of the image times 4. because it works with strides.

public void DisplayAndSaveImageFromByteArray(byte[] byteArray)
{
    try{
        byte[] data = new byte[width * height * 4];
        int o = 0;

        for (int io = 0; io < width * height; io++){
            byte value = byteArray[io];

            data[o++] = value;
            data[o++] = value;
            data[o++] = value;
            data[o++] = 0;
        }
        unsafe
        {
            fixed (byte* ptr = data)
            {
                using (image = new Bitmap((int)width, (int)height, (int)width * 4,System.Drawing.Imaging.PixelFormat.Format32bppRgb, new IntPtr(ptr)))
                {
                    image.Save(@"c:\\testmap\" + nextpicture + ".jpg", ImageFormat.Jpeg);
                    if (nextpicture >= 10)
                    {
                        pbCameraPreview.BeginInvoke(new InvokeDelegate(InvokeMethod));
                    }
                    nextpicture++;
                }
            }
        }
    }
    catch (Exception ex){
        MessageBox.Show(ex.ToString());
    }

}

When i run this code it will work, but only if all values are the same for example: White (255,255,255) or Black (0,0,0). it is able to deviate about 5 up and down in the RGB(A) values until it will stop working. But as soon as the color of the image changes it will stop working without giving me an Exception of anything.

Visual Output Window

The only error/Exception i will get it if i leave it on for a minute and the VS will recognize that the code being executed is not doing anything and will give me a warning. > ContextSwitchDeadlock

What did i do wrong for it to crash? and what is the solution for it? for some reason it wont let me put on the using and namespace name... (updated)Complete code:

    public Form1()
    {
        InitializeComponent();
        pbCameraPreview.Image = defImg;
    }

    #region Global
    int ii;
    object __p1;
    EventArgs __p2;
    string path;
    Image defImg = Image.FromFile(@"c:\\testimg\def.jpg");
    UInt32 width;
    UInt32 height;
    int nextpicture = 0;
    FGNodeInfoContainer InfoContainer = new FGNodeInfoContainer();
    FGNodeInfo NodeInfo = new FGNodeInfo();
    FireWrap_CtrlCenter CtrlCenter;
    enFireWrapResult Result;
    UInt32 XSize = new UInt32();
    UInt32 YSize = new UInt32();
    UInt32 NodeCnt;
    public delegate void InvokeDelegate();
    Bitmap image;
    CameraCode Cam = new CameraCode();
    FGFrame Frame = new FGFrame();
    FGUIntHL Guid = new FGUIntHL();
    #endregion

    public void CheckDirectory()
    {
        path = @"c:\\testmap\" + ii + "\\";
        if (Directory.Exists(@"c:\\testmap\") == false)
        {
            Directory.CreateDirectory(@"c:\\testmap\");
        }

        if (Directory.Exists(path))
        {
            if (File.Exists(path + "0.Jpeg"))
            {
                ii++;
                CheckDirectory();
            }
        }
        else
        {
            Directory.CreateDirectory(path);
        }
    }

    //Haal de images op
    /// <param name="__p1"></param>
    /// <param name="__p2"></param>
    public void btStart_Click(object sender, EventArgs e)
    {
        Debug.WriteLine("btStart_Click is clicked");
        // Init module
        CtrlCenter = FireWrap_CtrlCenter.GetInstance();
        Result = CtrlCenter.FGInitModule();

        // Register frame start event
        CtrlCenter.OnFrameReady += new FireWrap_CtrlCenter.FireWrapEvent(OnFrameReady);

        // Get list of connected nodes
        if (Result == enFireWrapResult.E_NOERROR)
        {
            Result = InfoContainer.FGGetNodeList();
            NodeCnt = InfoContainer.Size();

            // Print Nodecnt
            Console.WriteLine(NodeCnt.ToString() + " camera found");

            // Connect with first node
            InfoContainer.GetAt(NodeInfo, 0);
            Result = Cam.Connect(NodeInfo.Guid);
            if (Result == enFireWrapResult.E_NOERROR)
            {
                Cam.m_Guid = NodeInfo.Guid;
            }

            // Set Format7 Mode0 Y8
            if (Result == enFireWrapResult.E_NOERROR)
            {
                Result = Cam.SetParameter(enFGParameter.E_IMAGEFORMAT,
                        (uint)(((uint)enFGResolution.E_RES_SCALABLE << 16) |
                            ((uint)enColorMode.E_CCOLORMODE_Y8 << 8) |
                                0));
            }

            if (Result != enFireWrapResult.E_NOERROR)
            {
                Result = Cam.SetParameter(enFGParameter.E_IMAGEFORMAT,
                            (uint)(((uint)enFGResolution.E_RES_SCALABLE << 16) |
                                ((uint)enColorMode.E_CCOLORMODE_Y8 << 8) |
                                    1));
            }

            // Start DMA logic
            if (Result == enFireWrapResult.E_NOERROR)
                Result = Cam.OpenCapture();

            // Print device settings
            Result = Cam.GetParameter(enFGParameter.E_XSIZE, ref XSize);
            Result = Cam.GetParameter(enFGParameter.E_YSIZE, ref YSize);
            Debug.WriteLine(Cam.DeviceAll + " [" + Cam.m_Guid.Low.ToString() + "] " + XSize + "x" + YSize);
            width = XSize;
            height = YSize;

            // Start camera
            if (Result == enFireWrapResult.E_NOERROR)
            {
                Result = Cam.StartDevice();
            }          
        }
    }

    public void btStop_Click(object sender, EventArgs e)
    {
        // Stop the device
        Cam.StopDevice();
        // Close capture
        Cam.CloseCapture();
        // Disconnect before ExitModule
        Cam.Disconnect();
        // Exit module
        CtrlCenter.FGExitModule();
    }

    /// <param name="__p1"></param>
    /// <param name="__p2"></param>
    public void OnFrameReady(object __p1,  EventArgs __p2)
    {
        Debug.WriteLine("OnFrameReady is called");
        FGEventArgs args = (FGEventArgs)__p2;
        Guid.High = args.High;
        Guid.Low = args.Low;

        if (Guid.Low == Cam.m_Guid.Low)
        {
            Result = Cam.GetFrame(Frame, 0);
            // Process frame, skip FrameStart notification
            if (Result == enFireWrapResult.E_NOERROR & Frame.Length > 0)
            {
                byte[] data = new byte[Frame.Length];

                // Access to frame data
                if (Frame.CloneData(data))
                {
                    DisplayAndSaveImageFromByteArray(data);
                    // Here you can start your image processsing logic on data
                    string debug = String.Format("[{6}] Frame #{0} length:{1}byte [ {2} {3} {4} {5} ... ]",
                        Frame.Id, Frame.Length, data[0], data[1], data[2], data[3], Cam.m_Guid.Low);
                    Debug.WriteLine(debug);
                }
                // Return frame to module as fast as posible after this the Frame is not valid 
                Result = Cam.PutFrame(Frame);
            }
        }

    }

    public void DisplayAndSaveImageFromByteArray(byte[] byteArray)
    {
        try{
            byte[] data = new byte[width * height * 4];
            int o = 0;

            for (int io = 0; io < width * height; io++){
                byte value = byteArray[io];

                data[o++] = value;
                data[o++] = value;
                data[o++] = value;
                data[o++] = 0;
            }
            unsafe
            {
                fixed (byte* ptr = data)
                {
                    using (image = new Bitmap((int)width, (int)height, (int)width * 4,System.Drawing.Imaging.PixelFormat.Format32bppRgb, new IntPtr(ptr)))
                    {
                        image.Save(@"c:\\testmap\" + nextpicture + ".jpg", ImageFormat.Jpeg);
                        if (nextpicture >= 10)
                        {
                            pbCameraPreview.BeginInvoke(new InvokeDelegate(InvokeMethod));
                        }
                        nextpicture++;
                    }
                }
            }
        }
        catch (Exception ex){
            MessageBox.Show(ex.ToString());
        }

    }
    public void InvokeMethod()
    {
        pbCameraPreview.Image = Image.FromFile(@"c:\\testmap\" + (nextpicture -10) + ".jpg");
    }

}
public class CameraCode : FireWrap_Camera
{
    public FGUIntHL m_Guid;
}}

Threads running: Image threads I recorded it for extra information: https://www.youtube.com/watch?v=i3TxWRyZaIU

  • could you please paste your code as a code and not as a screenshot – Maksim Simkin Dec 19 '16 at 11:08
  • Let me try again, for some reason it wouldn't let me paste it the first time. – ThatInternGuy Dec 19 '16 at 12:20
  • The \\ in the path should be \. Is your `byteArray`grayscale? Because your code tries to convert it to a "color" image (of gray shades) in `data`. And what are the declarations / datatypes of `width`/`height`/`nextImage`? Also, can you create a complete and minimal sample program that reproduces your problem? Anyway, the is most likely not in the pasted code, since I ran it a few million times with random `byte[]` input and it worked (assuming the datatype of the `width` and `height` is `const uint` and both are small enough so that the case cannot create overflows) – mihi Dec 19 '16 at 12:47
  • let me see what i can come up with. might take a while. – ThatInternGuy Dec 19 '16 at 12:49
  • byteArray: the byteArray is a grayscale. Width: is first a Uint32 and is converted to a int for the bitmap. Height: is first a Uint32 and is converted to a int for the bitmap. nextpicture: is just a counter for the amount of images saved. so it will save the next image with a higher value. – ThatInternGuy Dec 19 '16 at 12:58
  • i can't really think of a quick sample but i can show you the complete code? – ThatInternGuy Dec 19 '16 at 13:00

2 Answers2

1

I'm not 100% sure that I have understood your problem, since it is not very clear the format of the input array and how do you have to format it before parsing it into the Bitmap variable... But here we go, I hope these tips can help you. If they don't, please try to provide some extra details on what you are trying to do.

First of all, if I have understood well, you should increase "io" and update the variable "value" each time you assign it to data[o++] in the main loop, otherwise you are assigning the same value to R, G and B pixels, which will always result in a shade of gray.

Secondly, I see a couple things in your code that are not very .net-ly... .Net provides already ways to load an image from a byte array, using Memory Streams and stuff. Take a look at How to create bitmap from byte array?

And be sure to indicate the proper format of your byte array image when instantiating the Bitmap or Image --> https://msdn.microsoft.com/en-us/library/system.drawing.imaging.pixelformat(v=vs.110).aspx

Regards.

Community
  • 1
  • 1
Alicia
  • 496
  • 5
  • 10
  • 1
    Thanks for the reply! First, That is correct i need it to be a shade of grey. Second, I am aware that .Net has a way of providing the easy way and i have used that way in a other Webcam Application but this is using a industrial Camera and provides only pixeldata as bytearray. – ThatInternGuy Dec 19 '16 at 12:15
  • and if you have paid close attention to the code you might have noticed that i used the exact code someone posted there. – ThatInternGuy Dec 19 '16 at 12:23
  • 1
    Oh... Ok, I didn't got it right the first time. I'm so sorry, I don't have any advice in this case. – Alicia Dec 19 '16 at 12:36
0
  • If you have trouble posting your code in StackOverflow, make sure each line is indented by at least 4 spaces (mark the code in Visual Studio, press Tab, then copy it) and separated by any other paragraphs by at least one empty line. Alternatively add a line of three backticks (`) at the beginning and and of the code.

  • When looking at your code, it seems to me that you are using a third-party control inside a Windows Form and try to bind the event of it to one of your Windows Forms event handlers. In that case you have to be aware that Windows Forms expect that all events are handled single-threaded (in the Event Dispatch Thread), so you should check (Debug.WriteLine) in your OnFrameReady method if InvokeRequired is true and if yes you have to take a few precautions:

    • Never access any of the Form's internal members (like pbCameraPreview) without wrapping the call into Invoke or BeginInvoke. Keep in mind that every Invoke call will effectively block until the single event-dispatch thread is available, so it will cost you a lot of performance to do invoke synchronously.

    • When accessing your own members (like width, height or nextpicture), make sure you use appropriate locking to avoid situations where one thread/callback changes the value in a situation where you don't expect it. In particular, since you have multiple cams but only a single width/height variable, if the resolutions differ, one camera callback could change the width while the other camera callback has just allocated the byte array but before passing the width to the Bitmap constructor, most likely resulting in a hang, crash, or memory access violation. Avoid this by passing width and heigth as variables into your method instead of using the global ones.

  • Your form's event handler (btStart_Click) contains a busy-wait loop. This has multiple problems:

    • As stated before, every Form event handler runs in the same thread (and every Invoke as well). So as long as your loop is busy-waiting, no other events can be handled and the UI will be completely frozen. If code uses Invoke, that code will also eventually have to wait and be blocked, too.
    • Busy wait loops without any sleep code in it will cause your processor to run at the full cpu speed and it will eat 100% of that core, causing battery drain on notebooks and high power consumption and probably loud fans on other machines. Just don't do that.

In your concrete example, just remove the loop and move everything after the loop into the stop button instead. To avoid the problems with Windows Forms and invoking, I'd suggest to put all the image handling logic into a separate class that does its own locking (each instance of the class handling one camera only), and just call into it to start the process. You might even prefer to do your app as a Console application first to avoid any event-dispatching issues and later convert it to a Windows Forms application once it is working as you desire.

mihi
  • 5,951
  • 1
  • 36
  • 45
  • Thanks for the reply! The code was from an example of a SDK i am using. (FireWrap.Net from AlliedVision) It was originally in a console application and i tried to convert it to a Windows Forms Application for a GUI. I will try to "Clean the code". The code may seem it was intended for multiple camera's but i am only using one camera, i have not yet fixed all those things. i was first worried about the image saving problem so i tried to search help for it. Thanks for the advice. – ThatInternGuy Dec 19 '16 at 14:31
  • @ThatInternGuy Have you tried breaking the program when it hangs and get a thread stacktrace where it is exactly? – mihi Dec 20 '16 at 13:20
  • yes, i have tried but it just freezes. As soon as i move my camera to a lighter spot, the pixeldata changes and it will do about 10 more frames but then it will hang. I know where it stops, it stops at the 10th onframeready call after i changed the lighting in the room. I do not get an error when it happens. – ThatInternGuy Dec 20 '16 at 13:32
  • This is the only call stack i could find > Camera.exe!Camera.Program.Main() Line 16 C# – ThatInternGuy Dec 20 '16 at 13:59
  • No more frames? And no other threads running? Then probably the third party webcam library crashed or does not call your callback any more? Perhaps ask their support? :D -> The code you posted looks fine, the problem is most likely elsewhere... – mihi Dec 20 '16 at 14:09
  • Well, thanks for your time and effort! I shall try to get further help at the Support of this SDK. If i do find the solution with the support i shall update that here. – ThatInternGuy Dec 20 '16 at 14:25