Image grabbing¶
The image retrieval process begins when the camera’s sensor data is read out and transferred to the host computer via the GigEVision protocol. This is known as acquisition. The acquisition can run for a specific number of frames or continue indefinitely until manually stopped.
As images arrive at the host, they are collected in an internal queue managed by ItalaApi’s acquisition engine. User application can then retrieve images from this queue one by one.
Warning
The user application is responsible for the lifetime of each image instance. After users are finished with an image, users must release it. This allows its memory to be reused by the acquisition engine for subsequent images.
The following examples demonstrate a basic workflow.
Use IDevice::GetNextImage() to retrieve an image. This method throws a GenICam::TimeoutException if no image is available within the specified timeout.
// Start the acquisition process on the camera
pDevice->StartAcquisition();
for (int i = 0; i < 100; i++)
{
Itala::IImage* pImage = nullptr;
try
{
// Ask for an image, waiting up to 500ms
pImage = pDevice->GetNextImage(500);
// Check if the image is incomplete due to packet loss
if (pImage->IsIncomplete())
{
std::cout << "Incomplete image received. Skipping." << std::endl;
continue; // The 'finally' block will still execute
}
// ... Process the image data via the IImage interface ...
}
catch (const GenICam::TimeoutException& e)
{
std::cout << "Timeout: No image available." << std::endl;
}
finally
{
// CRITICAL: Always dispose of the image to release its buffer
if (pImage)
{
pImage->Dispose();
}
}
}
pDevice->StopAcquisition();
The retrieved image is accessed via the Itala::IImage interface, which provides properties like width, height, pixel format, and a pointer to the data buffer.
Use DEV_GetNextImage() to retrieve an image handle. Check the return code to determine if the operation was successful or timed out.
// Start the acquisition process on the camera
error = DEV_StartAcquisition(hDevice);
for (size_t i = 0; i < 100; i++)
{
H_IMAGE hImage = NULL;
// Ask for an image, waiting up to 500ms
error = DEV_GetNextImage(hDevice, 500, &hImage);
if (error == ItalaErrorTimeout) {
printf("Timeout: No image available.\n");
continue;
}
// Check if the image is incomplete
bool isIncomplete = false;
error = IMG_IsIncomplete(hImage, &isIncomplete);
if (isIncomplete) {
printf("Incomplete image received. Skipping.\n");
} else {
// ... Process the image data using IMG_ functions with hImage ...
}
// CRITICAL: Always dispose of the image to release its buffer
error = IMG_Dispose(hImage);
hImage = NULL;
}
error = DEV_StopAcquisition(hDevice);
The retrieved image is accessed via the H_IMAGE handle, which can be passed to various IMG_ functions to get its properties and data.
Use IDevice.GetNextImage(), which throws an exception on timeout. The recommended approach is to use a using block, which guarantees that Dispose() is called on the image, even if errors occur.
// Start the acquisition process on the camera
device.StartAcquisition();
for (int i = 0; i < 100; i++)
{
try
{
// The 'using' block ensures image.Dispose() is called automatically
using (IImage image = device.GetNextImage(500))
{
// Check if the image is incomplete
if (image.IsIncomplete)
{
Console.WriteLine("Incomplete image received. Skipping.");
continue;
}
// ... Process the image data via the IImage interface ...
}
}
catch (Exception e) // Catch a more specific timeout exception if available
{
Console.WriteLine("No image available.");
continue;
}
}
device.StopAcquisition();
The retrieved image is accessed via the Itala.IImage interface, which provides properties like Width, Height, PixelFormat, and access to the data buffer.
Use IDevice.get_next_image(), which raises an exception on timeout. The recommended Pythonic approach is to use a with statement to ensure the image’s dispose() method is called automatically.
# Start the acquisition process on the camera
device.start_acquisition()
for i in range(100):
try:
# The 'with' statement ensures image.dispose() is called automatically
with device.get_next_image(500) as image:
# Check if the image is incomplete
if image.is_incomplete:
print("Incomplete image received. Skipping.")
continue
# ... Process the image ...
except Exception as e:
print(f"No image available: {e}")
continue
device.stop_acquisition()
The image is accessed via the itala.IImage class.
Working with Image Data
To use the image data with external libraries like NumPy and OpenCV, users must first get a pointer to the raw buffer and then wrap it in an appropriate data structure.
import ctypes
import numpy as np
import cv2
# (Inside the acquisition loop from above)
with device.get_next_image(500) as image:
if image.is_incomplete:
continue
# 1. Get the raw buffer pointer
buffer_ptr = image.get_data()
# 2. Define the buffer type based on image properties (e.g., Mono8)
pixel_format = image.pixel_format # Assuming this returns a known format
height = image.height
width = image.width
if pixel_format == "Mono8": # Example check
buffer_size = width * height
# Create a ctypes array pointer of the correct type and size
c_uint8_p = ctypes.POINTER(ctypes.c_uint8 * buffer_size)
# Cast the raw pointer to the typed pointer and get its contents
data = ctypes.cast(buffer_ptr, c_uint8_p).contents
# 3. Create a NumPy array that shares memory with the buffer (no copy)
numpy_array = np.frombuffer(data, dtype=np.uint8)
# 4. Reshape to image dimensions and use with OpenCV
cv_image = numpy_array.reshape((height, width))
cv2.imwrite("image.jpg", cv_image)
Network configuration for reliability¶
Warning
The filter driver and packet resend functionalities are enabled by default for a more reliable and efficient acquisition. The filter driver component must be installed and enabled on the Network Interface Card (NIC) the camera is connected to. These functionalities can be configured or disabled via the DataStream nodemap.