PVCAM  3.9.x
Programmable Virtual Camera Access Method library
Image Sequence
Warning
Please note that the example below describes an obsolete acquisition technique. This mode may not work reliably for large frames and fast frame rates and will not be supported by future PVCAM revisions. Please refer to Single Image Callbacks for a recommended way to acquire single frames.

This sample application demonstrates how to acquire a finite number of images. This example is similar to the single image acquisition example - the only difference is in the pl_exp_setup_seq function parameters where we request multiple images. The READOUT_COMPLETE flag is reported only once, after the whole sequence finishes. For this reason, if the application wants to track the acquisition progress, it has to calculate the current frame number based on the number of bytes received (using the pl_exp_check_status) or by periodically reading PARAM_BOF_EOF_COUNT - as shown in this example.

The code snippet below initializes PVCAM and opens the first available camera. Please refer to the actual code sample in the SDK installation directory for more details about the common helper functions used in this documentation.

std::vector<CameraContext*> contexts;
if (!InitAndOpenOneCamera(contexts, cSingleCamIndex))
return APP_EXIT_ERROR;
CameraContext* ctx = contexts[cSingleCamIndex];

To check the progress of the sequence acquisition we need to monitor the EOF counter. PVCAM has three parameters to control and manipulate BOF and EOF counters: PARAM_BOF_EOF_ENABLE, PARAM_BOF_EOF_CLR and PARAM_BOF_EOF_COUNT. All three parameters are needed in this example, therefore we make sure the parameters are available.

if (!IsParamAvailable(ctx->hcam, PARAM_BOF_EOF_ENABLE, "PARAM_BOF_EOF_ENABLE")
|| !IsParamAvailable(ctx->hcam, PARAM_BOF_EOF_CLR, "PARAM_BOF_EOF_CLR")
|| !IsParamAvailable(ctx->hcam, PARAM_BOF_EOF_COUNT, "PARAM_BOF_EOF_COUNT"))
{
CloseAllCamerasAndUninit(contexts);
return APP_EXIT_ERROR;
}

Next, enable BOF/EOF counters:

uns32 paramEofEnable = END_FRAME_IRQS;
(void*)&paramEofEnable))
{
PrintErrorMessage(pl_error_code(),
"pl_set_param(PARAM_BOF_EOF_ENABLE) error");
CloseAllCamerasAndUninit(contexts);
return APP_EXIT_ERROR;
}
Note
Please, refer to the Getting Error Messages section.

Clear the BOF/EOF counters. This should be done before every acquisition, but never during the acquisition.

rs_bool bofEofClear = TRUE;
if (PV_OK != pl_set_param(ctx->hcam, PARAM_BOF_EOF_CLR, (void*)&bofEofClear))
{
PrintErrorMessage(pl_error_code(),
"pl_set_param(PARAM_BOF_EOF_CLR) error");
CloseAllCamerasAndUninit(contexts);
return APP_EXIT_ERROR;
}
// Call this after each clearing of the BOF/EOF counter
if (PV_OK != pl_exp_abort(ctx->hcam, CCS_HALT))
{
PrintErrorMessage(pl_error_code(), "pl_exp_abort() error");
CloseAllCamerasAndUninit(contexts);
return APP_EXIT_ERROR;
}

Prepare the acquisition - the framesToAcquire specifies the number of frames to acquire in this sequence. The exposureBytes then holds the size of the whole buffer for all the images in the sequence. See Buffer Size and Frame Count Limitations section for possible limitations.

uns32 exposureBytes;
const uns32 exposureTime = 40; // milliseconds
const uns16 framesToAcquire = 5;
if (PV_OK != pl_exp_setup_seq(ctx->hcam, framesToAcquire, 1, &ctx->region,
exposureMode, exposureTime, &exposureBytes))
{
PrintErrorMessage(pl_error_code(), "pl_exp_setup_seq() error");
CloseAllCamerasAndUninit(contexts);
return APP_EXIT_ERROR;
}

We can calculate the size of each frame that is needed later:

const uns32 oneFrameBytes = exposureBytes / framesToAcquire;

Now allocate the buffer memory to the size reported by pl_exp_setup_seq function.

uns8* frameInMemory = new (std::nothrow) uns8[exposureBytes];
if (!frameInMemory)
{
printf("Unable to allocate buffer for camera %d\n", ctx->hcam);
CloseAllCamerasAndUninit(contexts);
return APP_EXIT_ERROR;
}

Start the acquisition. Since the pl_exp_start_seq was configured to use the internal camera trigger, the acquisition is started immediately. In hardware triggering modes the camera would wait for an external trigger signal.

if (PV_OK != pl_exp_start_seq(ctx->hcam, (void*)frameInMemory))
{
PrintErrorMessage(pl_error_code(), "pl_exp_start_seq() error");
CloseAllCamerasAndUninit(contexts);
delete [] frameInMemory;
return APP_EXIT_ERROR;
}

Monitor the acquisition progress with pl_exp_check_status and PARAM_BOF_EOF_COUNT.

int16 status;
uns32 byte_cnt;
uns32 eofCount = 0;
uns32 oldEofCount = 0;
while (PV_OK == pl_exp_check_status(ctx->hcam, &status, &byte_cnt)
&& status != READOUT_COMPLETE && status != READOUT_NOT_ACTIVE
&& !ctx->threadAbortFlag)
{
// In each loop we can optionally make this call to see how many frames
// have been acquired so far
(void*)&eofCount))
{
PrintErrorMessage(pl_error_code(),
"pl_get_param(PARAM_BOF_EOF_COUNT) error, ignored");
}
else if (eofCount > oldEofCount)
{
oldEofCount = eofCount;
printf("Acquired frame #%u out of %u on camera %d\n",
eofCount, framesToAcquire, ctx->hcam);
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
if (ctx->threadAbortFlag)
{
// This flag is set on ctrl+c, but in this sample we have to handle
// the acquisition abort explicitly
if (PV_OK != pl_exp_abort(ctx->hcam, CCS_HALT))
{
PrintErrorMessage(pl_error_code(), "pl_exp_abort() error");
errorOccured = true;
}
printf("Processing aborted on camera %d\n", ctx->hcam);
}
else if (status == READOUT_FAILED)
{
printf("Frame readout failed on camera %d\n", ctx->hcam);
errorOccured = true;
}

If no error occurred or the user did not abort the acquisition, then everything completed successfully. For the last frame, we should do the same call as in the while loop above, because EOF counter was incremented only after the READOUT_COMPLETE status was reported and the loop exited.

(void*)&eofCount))
{
PrintErrorMessage(pl_error_code(), "pl_get_param(PARAM_BOF_EOF_COUNT) error");
errorOccured = true;
}

Now we can finally walk through the buffer and process all frames:

for (uns32 i = 0; i < framesToAcquire; i++)
{
printf("Frame #%u readout completed on camera %d\n", i + 1, ctx->hcam);
ShowImage(ctx, frameInMemory + i * oneFrameBytes, exposureBytes);
}

When acquiring sequences, call pl_exp_finish_seq before accessing the frame buffer.

if (PV_OK != pl_exp_finish_seq(ctx->hcam, frameInMemory, 0))
PrintErrorMessage(pl_error_code(), "pl_exp_finish_seq() error");
imageCounter++;
} // End of while loop

For completeness, we do a cleanup. Please, refer to the Closing Camera and Uninitializing PVCAM section.

delete [] frameInMemory;
CloseAllCamerasAndUninit(contexts);
if (errorOccured)
return APP_EXIT_ERROR;
return 0;