示例#1
0
        private void chunkGrabImageMethod()
        {
            string triggerSelectorValue = "FrameStart";             /* Preselect the trigger for image acquisition */

            /* Check the available camera trigger mode(s) to select the appropriate one:
             * acquisition start trigger mode (used by previous cameras;
             * do not confuse with acquisition start command) or
             * frame start trigger mode (equivalent to previous acquisition start trigger mode). */


            bool isAvailAcquisitionStart = Pylon.DeviceFeatureIsAvailable(_pylonDevHandle, "EnumEntry_TriggerSelector_AcquisitionStart");
            bool isAvailFrameStart       = Pylon.DeviceFeatureIsAvailable(_pylonDevHandle, "EnumEntry_TriggerSelector_FrameStart");

            /* Check to see if the camera implements the acquisition start trigger mode only. */
            bool isAcqStartTriggerModeOnly = (isAvailAcquisitionStart && !isAvailFrameStart);

            if (isAcqStartTriggerModeOnly)
            {
                /* Camera uses the acquisition start trigger as the only trigger mode. */
                Pylon.DeviceFeatureFromString(_pylonDevHandle, "TriggerSelector", "AcquisitionStart");
                Pylon.DeviceFeatureFromString(_pylonDevHandle, "TriggerMode", "On");
                triggerSelectorValue = "AcquisitionStart";
            }
            else
            {
                /* Camera may have the acquisition start trigger mode and the frame start trigger mode implemented.
                 * In this case, the acquisition trigger mode must be switched off. */
                if (isAvailAcquisitionStart)
                {
                    Pylon.DeviceFeatureFromString(_pylonDevHandle, "TriggerSelector", "AcquisitionStart");
                    Pylon.DeviceFeatureFromString(_pylonDevHandle, "TriggerMode", "Off");
                }
                /* To trigger each single frame by software or external hardware trigger: Enable the frame start trigger mode. */
                Pylon.DeviceFeatureFromString(_pylonDevHandle, "TriggerSelector", "FrameStart");
                Pylon.DeviceFeatureFromString(_pylonDevHandle, "TriggerMode", "On");
            }

            /* Note: the trigger selector must be set to the appropriate trigger mode
             * before setting the trigger source or issuing software triggers.
             * Frame start trigger mode for newer cameras, acquisition start trigger mode for previous cameras. */
            Pylon.DeviceFeatureFromString(_pylonDevHandle, "TriggerSelector", triggerSelectorValue);

            /* Enable software triggering. */
            /* ... Select the software trigger as the trigger source. */
            Pylon.DeviceFeatureFromString(_pylonDevHandle, "TriggerSource", "Software");

            /* When using software triggering, the Continuous frame mode should be used. Once
             * acquisition is started, the camera sends one image each time a software trigger is
             * issued. */
            Pylon.DeviceFeatureFromString(_pylonDevHandle, "AcquisitionMode", "Continuous");


            //********************************************************************************************************
            setChunkModeFeatures();

            /* The data block containing the image chunk and the other chunks has a self-descriptive layout.
             * A chunk parser is used to extract the appended chunk data from the grabbed image frame.
             * Create a chunk parser. */
            PYLON_CHUNKPARSER_HANDLE hChunkParser = Pylon.DeviceCreateChunkParser(_pylonDevHandle);

            if (!hChunkParser.IsValid)
            {
                /* The transport layer doesn't provide a chunk parser. */
                throw new Exception("No chunk parser available.");
            }


            /* Image grabbing is done using a stream grabber.
             * A device may be able to provide different streams. A separate stream grabber must
             * be used for each stream. In this sample, we create a stream grabber for the default
             * stream, i.e., the first stream ( index == 0 ).
             */

            /* Get the number of streams supported by the device and the transport layer. */
            var nStreams = Pylon.DeviceGetNumStreamGrabberChannels(_pylonDevHandle);

            if (nStreams < 1)
            {
                throw new Exception("The transport layer doesn't support image streams.");
            }

            /* Create and open a stream grabber for the first channel. */
            uint firstChannel = 0;
            PYLON_STREAMGRABBER_HANDLE hGrabber = Pylon.DeviceGetStreamGrabber(_pylonDevHandle, firstChannel);

            Pylon.StreamGrabberOpen(hGrabber);

            /* Get a handle for the stream grabber's wait object. The wait object
             * allows waiting for buffers to be filled with grabbed data. */
            PYLON_WAITOBJECT_HANDLE hWait = Pylon.StreamGrabberGetWaitObject(hGrabber);

            /* Determine the required size of the grab buffer. Since activating chunks will increase the
             * payload size and thus the required buffer size, do this after enabling the chunks. */
            uint payloadSize = checked ((uint)Pylon.DeviceGetIntegerFeature(_pylonDevHandle, "PayloadSize"));

            /* We must tell the stream grabber the number and size of the buffers
             *      we are using. */
            /* .. We will not use more than NUM_BUFFERS for grabbing. */
            uint NUM_BUFFERS = 2;

            Pylon.StreamGrabberSetMaxNumBuffer(hGrabber, NUM_BUFFERS);

            /* .. We will not use buffers bigger than payloadSize bytes. */
            Pylon.StreamGrabberSetMaxBufferSize(hGrabber, payloadSize);

            /*  Allocate the resources required for grabbing. After this, critical parameters
            *       that impact the payload size must not be changed until FinishGrab() is called. */
            Pylon.StreamGrabberPrepareGrab(hGrabber);

            /* Before using the buffers for grabbing, they must be registered at
             * the stream grabber. For each registered buffer, a buffer handle
             * is returned. After registering, these handles are used instead of the
             * buffer objects pointers. The buffer objects are held in a dictionary,
             * that provides access to the buffer using a handle as key.
             */
            var buffers = new Dictionary <PYLON_STREAMBUFFER_HANDLE, PylonBuffer <Byte> >();

            for (int i = 0; i < NUM_BUFFERS; ++i)
            {
                PylonBuffer <Byte>        buffer = new PylonBuffer <byte>(payloadSize, true);
                PYLON_STREAMBUFFER_HANDLE handle = Pylon.StreamGrabberRegisterBuffer(hGrabber, ref buffer);
                buffers.Add(handle, buffer);
            }

            /* Feed the buffers into the stream grabber's input queue. For each buffer, the API
             * allows passing in an integer as additional context information. This integer
             * will be returned unchanged when the grab is finished. In our example, we use the index of the
             * buffer as context information. */
            var index = 0;

            foreach (KeyValuePair <PYLON_STREAMBUFFER_HANDLE, PylonBuffer <Byte> > pair in buffers)
            {
                Pylon.StreamGrabberQueueBuffer(hGrabber, pair.Key, index++);
            }

            /* Issue an acquisition start command. Because the trigger mode is enabled, issuing the start command
             * itself will not trigger any image acquisitions. Issuing the start command simply prepares the camera.
             * Once the camera is prepared it will acquire one image for every trigger it receives. */
            Pylon.DeviceExecuteCommandFeature(_pylonDevHandle, "AcquisitionStart");

            /* Trigger the first image. */
            Pylon.DeviceExecuteCommandFeature(_pylonDevHandle, "TriggerSoftware");

            /* Grab NUM_GRABS images. */
            PylonGrabResult_t grabResult;
            int NUM_GRABS = 1;
            int nGrabs    = 0;                                    /* Counts the number of images grabbed. */

            while (nGrabs < NUM_GRABS)
            {
                int bufferIndex;                              /* Index of the buffer. */

                /* Wait for the next buffer to be filled. Wait up to 1000 ms. */
                bool isReady = Pylon.WaitObjectWait(hWait, 1000);

                if (!isReady)
                {
                    /* Timeout occurred. */
                    throw new Exception("Grab timeout occurred.\n");
                }

                /* Since the wait operation was successful, the result of at least one grab
                 * operation is available. Retrieve it. */
                isReady = Pylon.StreamGrabberRetrieveResult(hGrabber, out grabResult);

                if (!isReady)
                {
                    /* Oops. No grab result available? We should never have reached this point.
                     * Since the wait operation above returned without a timeout, a grab result
                     * should be available. */
                    throw new Exception("Failed to retrieve a grab result.\n");
                }

                nGrabs++;

                /* Trigger the next image. Since we passed more than one buffer to the stream grabber,
                 * the triggered image will be grabbed while the image processing is performed.  */
                Pylon.DeviceExecuteCommandFeature(_pylonDevHandle, "TriggerSoftware");

                /* Get the buffer index from the context information. */
                bufferIndex = (int)grabResult.Context;

                /* Check to see if the image was grabbed successfully. */

                if (grabResult.Status == EPylonGrabStatus.Grabbed)
                {
                    /*  The grab is successful.  */

                    PylonBuffer <Byte> buffer;                           /* Reference to the buffer attached to the grab result. */

                    /* Get the buffer from the dictionary. Since we also got the buffer index,
                     * we could alternatively use an array, e.g. buffers[bufferIndex]. */
                    if (!buffers.TryGetValue(grabResult.hBuffer, out buffer))
                    {
                        /* Oops. No buffer available? We should never have reached this point. Since all buffers are
                         * in the dictionary. */
                        throw new Exception("Failed to find the buffer associated with the handle returned in grab result.");
                    }

                    //Console.WriteLine("Grabbed frame {0} into buffer {1}.", nGrabs, bufferIndex);



                    /* Check to see if we really got image data plus chunk data. */
                    if (grabResult.PayloadType != EPylonPayloadType.PayloadType_ChunkData)
                    {
                        Console.WriteLine("Received a buffer not containing chunk data?");
                    }
                    else
                    {
                        /* Process the chunk data. This is done by passing the grabbed image buffer
                         * to the chunk parser. When the chunk parser has processed the buffer, the chunk
                         * data can be accessed in the same manner as "normal" camera parameters.
                         * The only exception is the CRC checksum feature. There are dedicated functions for
                         * checking the CRC checksum. */

                        bool hasCRC;

                        /* Let the parser extract the data. */
                        Pylon.ChunkParserAttachBuffer(hChunkParser, buffer);


                        /* Check the CRC checksum. */
                        hasCRC = Pylon.ChunkParserHasCRC(hChunkParser);
                        bool isOk = (hasCRC) ? Pylon.ChunkParserCheckCRC(hChunkParser) : true;

                        bool isAvail = Pylon.DeviceFeatureIsAvailable(_pylonDevHandle, "ChunkWidth");
                        long chunkWidth = 0, chunkHeight = 0;
                        //Console.WriteLine("Frame {0} {1} a frame width chunk.", nGrabs, isAvail ? "contains" : "doesn't contain");
                        if (isAvail)
                        {
                            /* ... Get the value. */
                            chunkWidth = Pylon.DeviceGetIntegerFeature(_pylonDevHandle, "ChunkWidth");

                            //Console.WriteLine("Width of frame {0}: {1}.", nGrabs, chunkWidth);
                        }

                        /* Retrieve the chunk height value. */
                        /* ... Check the availability. */
                        isAvail = Pylon.DeviceFeatureIsAvailable(_pylonDevHandle, "ChunkHeight");

                        Console.WriteLine("Frame {0} {1} a frame height chunk.", nGrabs, isAvail ? "contains" : "doesn't contain");
                        if (isAvail)
                        {
                            /* ... Get the value. */
                            chunkHeight = Pylon.DeviceGetIntegerFeature(_pylonDevHandle, "ChunkHeight");

                            //Console.WriteLine("Height of frame {0}: {1}.", nGrabs, chunkHeight);
                        }

                        if (isOk)
                        {
                            _latestImage = new HImage("byte", (int)chunkWidth, (int)chunkHeight, buffer.Pointer);
                        }
                    }
                    /* Before requeueing the buffer, you should detach it from the chunk parser. */
                    Pylon.ChunkParserDetachBuffer(hChunkParser);                      /* Now the chunk data in the buffer is no longer accessible. */
                }
                else if (grabResult.Status == EPylonGrabStatus.Failed)
                {
                    Console.Error.WriteLine("Frame {0} wasn't grabbed successfully.  Error code = {1}", nGrabs, grabResult.ErrorCode);
                }

                /* Once finished with the processing, requeue the buffer to be filled again. */
                Pylon.StreamGrabberQueueBuffer(hGrabber, grabResult.hBuffer, bufferIndex);
            }
        }
示例#2
0
        const uint NUM_BUFFERS = 2;         /* Number of buffers used for grabbing. */

        static void Main(string[] args)
        {
            PYLON_DEVICE_HANDLE hDev = new PYLON_DEVICE_HANDLE(); /* Handle for the pylon device. */

            try
            {
                uint numDevices;                                                     /* Number of available devices. */
                PYLON_STREAMGRABBER_HANDLE hGrabber;                                 /* Handle for the pylon stream grabber. */
                PYLON_CHUNKPARSER_HANDLE   hChunkParser;                             /* Handle for the parser extracting the chunk data. */
                PYLON_WAITOBJECT_HANDLE    hWait;                                    /* Handle used for waiting for a grab to be finished. */
                uint payloadSize;                                                    /* Size of an image frame in bytes. */
                Dictionary <PYLON_STREAMBUFFER_HANDLE, PylonBuffer <Byte> > buffers; /* Holds handles and buffers used for grabbing. */
                PylonGrabResult_t grabResult;                                        /* Stores the result of a grab operation. */
                int    nGrabs;                                                       /* Counts the number of buffers grabbed. */
                uint   nStreams;                                                     /* The number of streams the device provides. */
                bool   isAvail;                                                      /* Used for checking feature availability */
                bool   isReady;                                                      /* Used as an output parameter */
                int    i;                                                            /* Counter. */
                string triggerSelectorValue = "FrameStart";                          /* Preselect the trigger for image acquisition */
                bool   isAvailFrameStart;                                            /* Used for checking feature availability */
                bool   isAvailAcquisitionStart;                                      /* Used for checking feature availability */

#if DEBUG
                /* This is a special debug setting needed only for GigE cameras.
                 * See 'Building Applications with pylon' in the programmers guide */
                Environment.SetEnvironmentVariable("PYLON_GIGE_HEARTBEAT", "300000" /*ms*/);
#endif

                /* Before using any pylon methods, the pylon runtime must be initialized. */
                Pylon.Initialize();

                /* Enumerate all camera devices. You must call
                 * PylonEnumerateDevices() before creating a device. */
                numDevices = Pylon.EnumerateDevices();

                if (0 == numDevices)
                {
                    throw new Exception("No devices found!");
                }

                /* Get a handle for the first device found.  */
                hDev = Pylon.CreateDeviceByIndex(0);

                /* Before using the device, it must be opened. Open it for configuring
                 * parameters and for grabbing images. */
                Pylon.DeviceOpen(hDev, Pylon.cPylonAccessModeControl | Pylon.cPylonAccessModeStream);

                /* Set the pixel format to Mono8, where gray values will be output as 8 bit values for each pixel. */
                /* ... Check first to see if the device supports the Mono8 format. */
                isAvail = Pylon.DeviceFeatureIsAvailable(hDev, "EnumEntry_PixelFormat_Mono8");

                if (!isAvail)
                {
                    /* Feature is not available. */
                    throw new Exception("Device doesn't support the Mono8 pixel format.");
                }
                /* ... Set the pixel format to Mono8. */
                Pylon.DeviceFeatureFromString(hDev, "PixelFormat", "Mono8");

                /* Check the available camera trigger mode(s) to select the appropriate one: acquisition start trigger mode (used by previous cameras;
                *  do not confuse with acquisition start command) or frame start trigger mode (equivalent to previous acquisition start trigger mode). */
                isAvailAcquisitionStart = Pylon.DeviceFeatureIsAvailable(hDev, "EnumEntry_TriggerSelector_AcquisitionStart");
                isAvailFrameStart       = Pylon.DeviceFeatureIsAvailable(hDev, "EnumEntry_TriggerSelector_FrameStart");

                /* Check to see if the camera implements the acquisition start trigger mode only. */
                if (isAvailAcquisitionStart && !isAvailFrameStart)
                {
                    /* Camera uses the acquisition start trigger as the only trigger mode. */
                    Pylon.DeviceFeatureFromString(hDev, "TriggerSelector", "AcquisitionStart");
                    Pylon.DeviceFeatureFromString(hDev, "TriggerMode", "On");
                    triggerSelectorValue = "AcquisitionStart";
                }
                else
                {
                    /* Camera may have the acquisition start trigger mode and the frame start trigger mode implemented.
                     * In this case, the acquisition trigger mode must be switched off. */
                    if (isAvailAcquisitionStart)
                    {
                        Pylon.DeviceFeatureFromString(hDev, "TriggerSelector", "AcquisitionStart");
                        Pylon.DeviceFeatureFromString(hDev, "TriggerMode", "Off");
                    }

                    /* Disable frame burst start trigger if available */
                    isAvail = Pylon.DeviceFeatureIsAvailable(hDev, "EnumEntry_TriggerSelector_FrameBurstStart");
                    if (isAvail)
                    {
                        Pylon.DeviceFeatureFromString(hDev, "TriggerSelector", "FrameBurstStart");
                        Pylon.DeviceFeatureFromString(hDev, "TriggerMode", "Off");
                    }

                    /* To trigger each single frame by software or external hardware trigger: Enable the frame start trigger mode. */
                    Pylon.DeviceFeatureFromString(hDev, "TriggerSelector", "FrameStart");
                    Pylon.DeviceFeatureFromString(hDev, "TriggerMode", "On");
                }

                /* Note: the trigger selector must be set to the appropriate trigger mode
                 * before setting the trigger source or issuing software triggers.
                 * Frame start trigger mode for newer cameras, acquisition start trigger mode for previous cameras. */
                Pylon.DeviceFeatureFromString(hDev, "TriggerSelector", triggerSelectorValue);

                /* Enable software triggering. */
                /* ... Select the software trigger as the trigger source. */
                Pylon.DeviceFeatureFromString(hDev, "TriggerSource", "Software");

                /* When using software triggering, the Continuous frame mode should be used. Once
                 * acquisition is started, the camera sends one image each time a software trigger is
                 * issued. */
                Pylon.DeviceFeatureFromString(hDev, "AcquisitionMode", "Continuous");

                /* For GigE cameras, we recommend increasing the packet size for better
                 * performance. If the network adapter supports jumbo frames, set the packet
                 * size to a value > 1500, e.g., to 8192. In this sample, we only set the packet size
                 * to 1500. */
                /* ... Check first to see if the GigE camera packet size parameter is supported and if it is writable. */
                isAvail = Pylon.DeviceFeatureIsWritable(hDev, "GevSCPSPacketSize");

                if (isAvail)
                {
                    /* ... The device supports the packet size feature. Set a value. */
                    Pylon.DeviceSetIntegerFeature(hDev, "GevSCPSPacketSize", 1500);
                }

                /* Before enabling individual chunks, the chunk mode in general must be activated. */
                isAvail = Pylon.DeviceFeatureIsWritable(hDev, "ChunkModeActive");

                if (!isAvail)
                {
                    throw new Exception("The device doesn't support the chunk mode.");
                }

                /* Activate the chunk mode. */
                Pylon.DeviceSetBooleanFeature(hDev, "ChunkModeActive", true);

                /* Enable some individual chunks... */

                /* ... The frame counter chunk feature. */
                /* Is the chunk feature available? */
                isAvail = Pylon.DeviceFeatureIsAvailable(hDev, "EnumEntry_ChunkSelector_Framecounter");

                if (isAvail)
                {
                    /* Select the frame counter chunk feature. */
                    Pylon.DeviceFeatureFromString(hDev, "ChunkSelector", "Framecounter");

                    /* Can the chunk feature be activated? */
                    isAvail = Pylon.DeviceFeatureIsWritable(hDev, "ChunkEnable");

                    if (isAvail)
                    {
                        /* Activate the chunk feature. */
                        Pylon.DeviceSetBooleanFeature(hDev, "ChunkEnable", true);
                    }
                }
                /* ... The CRC checksum chunk feature. */

                /*  Note: Enabling the CRC checksum chunk feature is not a prerequisite for using
                 * chunks. Chunks can also be handled when the CRC checksum chunk feature is disabled. */
                isAvail = Pylon.DeviceFeatureIsAvailable(hDev, "EnumEntry_ChunkSelector_PayloadCRC16");

                if (isAvail)
                {
                    /* Select the CRC checksum chunk feature. */
                    Pylon.DeviceFeatureFromString(hDev, "ChunkSelector", "PayloadCRC16");

                    /* Can the chunk feature be activated? */
                    isAvail = Pylon.DeviceFeatureIsWritable(hDev, "ChunkEnable");

                    if (isAvail)
                    {
                        /* Activate the chunk feature. */
                        Pylon.DeviceSetBooleanFeature(hDev, "ChunkEnable", true);
                    }
                }

                /* The data block containing the image chunk and the other chunks has a self-descriptive layout.
                 * A chunk parser is used to extract the appended chunk data from the grabbed image frame.
                 * Create a chunk parser. */
                hChunkParser = Pylon.DeviceCreateChunkParser(hDev);

                if (!hChunkParser.IsValid)
                {
                    /* The transport layer doesn't provide a chunk parser. */
                    throw new Exception("No chunk parser available.");
                }


                /* Image grabbing is done using a stream grabber.
                 * A device may be able to provide different streams. A separate stream grabber must
                 * be used for each stream. In this sample, we create a stream grabber for the default
                 * stream, i.e., the first stream ( index == 0 ).
                 */

                /* Get the number of streams supported by the device and the transport layer. */
                nStreams = Pylon.DeviceGetNumStreamGrabberChannels(hDev);

                if (nStreams < 1)
                {
                    throw new Exception("The transport layer doesn't support image streams.");
                }

                /* Create and open a stream grabber for the first channel. */
                hGrabber = Pylon.DeviceGetStreamGrabber(hDev, 0);
                Pylon.StreamGrabberOpen(hGrabber);

                /* Get a handle for the stream grabber's wait object. The wait object
                 * allows waiting for buffers to be filled with grabbed data. */
                hWait = Pylon.StreamGrabberGetWaitObject(hGrabber);

                /* Determine the required size of the grab buffer. Since activating chunks will increase the
                 * payload size and thus the required buffer size, do this after enabling the chunks. */
                payloadSize = checked ((uint)Pylon.DeviceGetIntegerFeature(hDev, "PayloadSize"));

                /* We must tell the stream grabber the number and size of the buffers
                 *  we are using. */
                /* .. We will not use more than NUM_BUFFERS for grabbing. */
                Pylon.StreamGrabberSetMaxNumBuffer(hGrabber, NUM_BUFFERS);

                /* .. We will not use buffers bigger than payloadSize bytes. */
                Pylon.StreamGrabberSetMaxBufferSize(hGrabber, payloadSize);

                /*  Allocate the resources required for grabbing. After this, critical parameters
                *   that impact the payload size must not be changed until FinishGrab() is called. */
                Pylon.StreamGrabberPrepareGrab(hGrabber);

                /* Before using the buffers for grabbing, they must be registered at
                 * the stream grabber. For each registered buffer, a buffer handle
                 * is returned. After registering, these handles are used instead of the
                 * buffer objects pointers. The buffer objects are held in a dictionary,
                 * that provides access to the buffer using a handle as key.
                 */
                buffers = new Dictionary <PYLON_STREAMBUFFER_HANDLE, PylonBuffer <Byte> >();
                for (i = 0; i < NUM_BUFFERS; ++i)
                {
                    PylonBuffer <Byte>        buffer = new PylonBuffer <byte>(payloadSize, true);
                    PYLON_STREAMBUFFER_HANDLE handle = Pylon.StreamGrabberRegisterBuffer(hGrabber, ref buffer);
                    buffers.Add(handle, buffer);
                }

                /* Feed the buffers into the stream grabber's input queue. For each buffer, the API
                 * allows passing in an integer as additional context information. This integer
                 * will be returned unchanged when the grab is finished. In our example, we use the index of the
                 * buffer as context information. */
                i = 0;
                foreach (KeyValuePair <PYLON_STREAMBUFFER_HANDLE, PylonBuffer <Byte> > pair in buffers)
                {
                    Pylon.StreamGrabberQueueBuffer(hGrabber, pair.Key, i++);
                }

                /* Issue an acquisition start command. Because the trigger mode is enabled, issuing the start command
                 * itself will not trigger any image acquisitions. Issuing the start command simply prepares the camera.
                 * Once the camera is prepared it will acquire one image for every trigger it receives. */
                Pylon.DeviceExecuteCommandFeature(hDev, "AcquisitionStart");

                /* Trigger the first image. */
                Pylon.DeviceExecuteCommandFeature(hDev, "TriggerSoftware");

                /* Grab NUM_GRABS images. */
                nGrabs = 0;                           /* Counts the number of images grabbed. */
                while (nGrabs < NUM_GRABS)
                {
                    int  bufferIndex;     /* Index of the buffer. */
                    Byte min = 255, max = 0;
                    long chunkWidth  = 0; /* data retrieved from the chunk parser */
                    long chunkHeight = 0; /* data retrieved from the chunk parser */

                    /* Wait for the next buffer to be filled. Wait up to 1000 ms. */
                    isReady = Pylon.WaitObjectWait(hWait, 1000);

                    if (!isReady)
                    {
                        /* Timeout occurred. */
                        throw new Exception("Grab timeout occurred.\n");
                    }

                    /* Since the wait operation was successful, the result of at least one grab
                     * operation is available. Retrieve it. */
                    isReady = Pylon.StreamGrabberRetrieveResult(hGrabber, out grabResult);

                    if (!isReady)
                    {
                        /* Oops. No grab result available? We should never have reached this point.
                         * Since the wait operation above returned without a timeout, a grab result
                         * should be available. */
                        throw new Exception("Failed to retrieve a grab result.\n");
                    }

                    nGrabs++;

                    /* Trigger the next image. Since we passed more than one buffer to the stream grabber,
                     * the triggered image will be grabbed while the image processing is performed.  */
                    Pylon.DeviceExecuteCommandFeature(hDev, "TriggerSoftware");

                    /* Get the buffer index from the context information. */
                    bufferIndex = (int)grabResult.Context;

                    /* Check to see if the image was grabbed successfully. */
                    if (grabResult.Status == EPylonGrabStatus.Grabbed)
                    {
                        /*  The grab is successful.  */

                        PylonBuffer <Byte> buffer;        /* Reference to the buffer attached to the grab result. */

                        /* Get the buffer from the dictionary. Since we also got the buffer index,
                         * we could alternatively use an array, e.g. buffers[bufferIndex]. */
                        if (!buffers.TryGetValue(grabResult.hBuffer, out buffer))
                        {
                            /* Oops. No buffer available? We should never have reached this point. Since all buffers are
                             * in the dictionary. */
                            throw new Exception("Failed to find the buffer associated with the handle returned in grab result.");
                        }

                        Console.WriteLine("Grabbed frame {0} into buffer {1}.", nGrabs, bufferIndex);

                        /* Check to see if we really got image data plus chunk data. */
                        if (grabResult.PayloadType != EPylonPayloadType.PayloadType_ChunkData)
                        {
                            Console.WriteLine("Received a buffer not containing chunk data?");
                        }
                        else
                        {
                            /* Process the chunk data. This is done by passing the grabbed image buffer
                             * to the chunk parser. When the chunk parser has processed the buffer, the chunk
                             * data can be accessed in the same manner as "normal" camera parameters.
                             * The only exception is the CRC checksum feature. There are dedicated functions for
                             * checking the CRC checksum. */

                            bool hasCRC;

                            /* Let the parser extract the data. */
                            Pylon.ChunkParserAttachBuffer(hChunkParser, buffer);


                            /* Check the CRC checksum. */
                            hasCRC = Pylon.ChunkParserHasCRC(hChunkParser);

                            if (hasCRC)
                            {
                                bool isOk = Pylon.ChunkParserCheckCRC(hChunkParser);

                                Console.WriteLine("Frame {0} contains a CRC checksum. The checksum {1} ok.", nGrabs, isOk ? "is" : "is not");
                            }

                            /* Retrieve the frame counter value. */
                            /* ... Check the availability. */
                            isAvail = Pylon.DeviceFeatureIsAvailable(hDev, "ChunkFramecounter");

                            Console.WriteLine("Frame {0} {1} a frame counter chunk.", nGrabs, isAvail ? "contains" : "doesn't contain");
                            if (isAvail)
                            {
                                /* ... Get the value. */
                                long counter;
                                counter = Pylon.DeviceGetIntegerFeature(hDev, "ChunkFramecounter");

                                Console.WriteLine("Frame counter of frame {0}: {1}.", nGrabs, counter);
                            }

                            /* Retrieve the chunk width value. */
                            /* ... Check the availability. */
                            isAvail = Pylon.DeviceFeatureIsAvailable(hDev, "ChunkWidth");

                            Console.WriteLine("Frame {0} {1} a frame width chunk.", nGrabs, isAvail ? "contains" : "doesn't contain");
                            if (isAvail)
                            {
                                /* ... Get the value. */
                                chunkWidth = Pylon.DeviceGetIntegerFeature(hDev, "ChunkWidth");

                                Console.WriteLine("Width of frame {0}: {1}.", nGrabs, chunkWidth);
                            }

                            /* Retrieve the chunk height value. */
                            /* ... Check the availability. */
                            isAvail = Pylon.DeviceFeatureIsAvailable(hDev, "ChunkHeight");

                            Console.WriteLine("Frame {0} {1} a frame height chunk.", nGrabs, isAvail ? "contains" : "doesn't contain");
                            if (isAvail)
                            {
                                /* ... Get the value. */
                                chunkHeight = Pylon.DeviceGetIntegerFeature(hDev, "ChunkHeight");

                                Console.WriteLine("Height of frame {0}: {1}.", nGrabs, chunkHeight);
                            }
                        }

                        /* Perform the image processing. */
                        getMinMax(buffer.Array, chunkWidth, chunkHeight, out min, out max);
                        Console.WriteLine("Min. gray value  = {0}, Max. gray value = {1}", min, max);

                        /* Before requeueing the buffer, you should detach it from the chunk parser. */
                        Pylon.ChunkParserDetachBuffer(hChunkParser);  /* Now the chunk data in the buffer is no longer accessible. */
                    }
                    else if (grabResult.Status == EPylonGrabStatus.Failed)
                    {
                        Console.Error.WriteLine("Frame {0} wasn't grabbed successfully.  Error code = {1}", nGrabs, grabResult.ErrorCode);
                    }

                    /* Once finished with the processing, requeue the buffer to be filled again. */
                    Pylon.StreamGrabberQueueBuffer(hGrabber, grabResult.hBuffer, bufferIndex);
                }

                /* Clean up. */

                /*  ... Stop the camera. */
                Pylon.DeviceExecuteCommandFeature(hDev, "AcquisitionStop");

                /* ... We must issue a cancel call to ensure that all pending buffers are put into the
                 * stream grabber's output queue. */
                Pylon.StreamGrabberCancelGrab(hGrabber);

                /* ... The buffers can now be retrieved from the stream grabber. */
                do
                {
                    isReady = Pylon.StreamGrabberRetrieveResult(hGrabber, out grabResult);
                } while (isReady);

                /* ... When all buffers are retrieved from the stream grabber, they can be deregistered.
                 *     After deregistering the buffers, it is safe to free the memory */

                foreach (KeyValuePair <PYLON_STREAMBUFFER_HANDLE, PylonBuffer <Byte> > pair in buffers)
                {
                    Pylon.StreamGrabberDeregisterBuffer(hGrabber, pair.Key);
                    pair.Value.Dispose();
                }
                buffers = null;

                /* ... Release grabbing related resources. */
                Pylon.StreamGrabberFinishGrab(hGrabber);


                /* After calling PylonStreamGrabberFinishGrab(), parameters that impact the payload size (e.g.,
                 * the AOI width and height parameters) are unlocked and can be modified again. */

                /* ... Close the stream grabber. */
                Pylon.StreamGrabberClose(hGrabber);


                /* ... Release the chunk parser. */
                Pylon.DeviceDestroyChunkParser(hDev, hChunkParser);


                /*  Disable the software trigger and chunk mode. */
                if (hDev.IsValid)
                {
                    Pylon.DeviceSetBooleanFeature(hDev, "ChunkModeActive", false);
                    Pylon.DeviceFeatureFromString(hDev, "TriggerMode", "Off");
                }

                /* ... Close and release the pylon device. The stream grabber becomes invalid
                 * after closing the pylon device. Don't call stream grabber related methods after
                 * closing or releasing the device. */
                Pylon.DeviceClose(hDev);
                Pylon.DestroyDevice(hDev);

                /* ... Shut down the pylon runtime system. Don't call any pylon method after
                 * calling PylonTerminate(). */
                Pylon.Terminate();

                Console.Error.WriteLine("\nPress enter to exit.");
                Console.ReadLine();
            }
            catch (Exception e)
            {
                /* Retrieve more details about the error.
                 * /* Retrieve the error message. */
                string msg = GenApi.GetLastErrorMessage() + "\n" + GenApi.GetLastErrorDetail();
                Console.Error.WriteLine("Exception caught:");
                Console.Error.WriteLine(e.Message);
                if (msg != "\n")
                {
                    Console.Error.WriteLine("Last error message:");
                    Console.Error.WriteLine(msg);
                }

                try
                {
                    if (hDev.IsValid)
                    {
                        /*  Disable the software trigger. */
                        Pylon.DeviceFeatureFromString(hDev, "TriggerMode", "Off");
                        /* ... Close and release the pylon device. */
                        if (Pylon.DeviceIsOpen(hDev))
                        {
                            Pylon.DeviceClose(hDev);
                        }
                        Pylon.DestroyDevice(hDev);
                    }
                }
                catch (Exception)
                {
                    /*No further handling here.*/
                }

                Pylon.Terminate();  /* Releases all pylon resources. */

                Console.Error.WriteLine("\nPress enter to exit.");
                Console.ReadLine();

                Environment.Exit(1);
            }
        }