“Connect, Set, Decode!”

In the following section, we present a small sample program (“Connect, Set, Decode!”). This sample demonstrates how the CameraSDK and the ImageSDK can be utilized in relation to each other, when connecting to a camera, setting properties, capturing an image and decoding the image.

The application code takes the following actions:

  1. Connects through USB to a camera (to utilize the CameraSDK, at least one camera must be connected to the Host computer). 1. If multiple cameras are connected, the application picks any of the connected cameras, if none are specified.

  2. Set-up of 3 properties: “ISO”, “Aperture” and “Shutter-time” (see Getting / Setting Properties).

  3. Enable image receiving (see Receive Captured Images).

  4. Capture an image (see Triggering a Capture).

  5. Receive the images in-memory (RAM) on the Host computer.

  6. Use the ImageSDK’s Decode pipeline to decode the image into uncompressed Bayer sensor data (see Decode Pipeline).

  7. Use the ImageSDK’s Convert pipeline to scale the image to a width of 1024px, and convert it into an RGB image (see Convert Pipeline).

  8. Save the converted image to a file.

Full Source code

#include <iostream> // Print out messages to the console
#include <fstream> // Save to file
#include <P1Camera.hpp> // CameraSDK
#include <P1Image.hpp> // ImageSDK
#include <chrono>
#include <thread>

// This small program demonstrates the CameraSDK and the ImageSDK and how they can be
// utilized in conjunction with each other.
// !! On IQ4, this code will work only if the exposure program is set to ‘manual’ !!
int main(int argc, const char** argv)
{
	// All calls to the CameraSDK and ImageSDK must be wrapped in a try-catch,
	// because exceptions are used to report errors, etc.
	try
	{
		std::cout << "Connect to camera" << std::endl;
		P1::CameraSdk::Camera camera = P1::CameraSdk::Camera::OpenUsbCamera();

		// prepare to set cameras "exposure program" to manual
		// this will allow us to set ISO, aperture and shutter time manually.
		P1::CameraSdk::PropertyValue exposureProgram;
		exposureProgram.mType = P1::CameraSdk::kPropertyTypeEnum;
		exposureProgram.mInt = 0;
		uint32_t exposureProgramId = 1000;

		// Only change exposure program - if not already 0
		if (camera.Property(1000).mInt != 0)
		{
			camera.SetProperty(exposureProgramId, exposureProgram);
		}

		// Setup ISO, Aperture and Shutter-time
		P1::CameraSdk::PropertyValue isoValue;
		isoValue.mType = P1::CameraSdk::kPropertyTypeFloat64;
		isoValue.mDouble = 200;

		P1::CameraSdk::PropertyValue apertureValue;
		apertureValue.mType = P1::CameraSdk::kPropertyTypeFloat64;
		apertureValue.mDouble = 5.0;

		P1::CameraSdk::PropertyValue shutterTimeValue;
		shutterTimeValue.mType = P1::CameraSdk::kPropertyTypeFloat64;
		shutterTimeValue.mDouble = 0.125;

		// PropertyIDs:
		uint32_t isoId = 120;
		uint32_t apertureId = 1003;
		uint32_t shutterTimeId = 1002;

		camera.SetProperty(isoId, isoValue);
		camera.SetProperty(apertureId, apertureValue);
		camera.SetProperty(shutterTimeId, shutterTimeValue);

		// Set-up so images will be sent to this computer and trig the capture
		std::cout << "Start capture" << std::endl;

		P1::CameraSdk::Listener imgListener;
		imgListener.EnableNotification(camera, P1::CameraSdk::EventType::CameraImageReady);
		camera.Subscriptions()->FullImages()->Subscribe();
		// Necessary to sleep, otherwise TriggerCapture will start before EnableImageReceiving is done
		std::this_thread::sleep_for(std::chrono::milliseconds(200));
		camera.TriggerCapture();

		// Wait for image
		P1::CameraSdk::NotificationEventPtr event = imgListener.WaitForNotification(10000);
		std::cout << "Image received" << std::endl;

		//------
		// We are done with the CameraSDK, and now use our ImageSDK for the rest
		//------

		auto iiqImage = event->FullImage();

		// Parse IIQ file
		P1::ImageSdk::RawImage image(iiqImage->Data(), iiqImage->DataSizeBytes());

		// Decode image data with default values
		P1::ImageSdk::DecodeConfig decodeConfig = P1::ImageSdk::DecodeConfig::Defaults;
		P1::ImageSdk::SensorBayerOutput decodedImage = image.Decode(decodeConfig);
		std::cout << "Decoded image size: " << decodedImage.ByteSize()
			<< " Height=" << decodedImage.FullHeight()
			<< " Width=" << decodedImage.FullWidth() << std::endl;

		// Write decoded bitmap to file
		std::fstream rawFile("bitmapRAW.bin", std::ios::binary | std::ios::trunc |
			std::ios::out);
		rawFile.write((char*)decodedImage.Data().get(), decodedImage.ByteSize());
		rawFile.close();

		// Convert image data to RGB
		P1::ImageSdk::ConvertConfig config;
		config.SetOutputWidth(1024);
		P1::ImageSdk::BitmapImage bitmap = config.ApplyTo(image);

		std::cout << "Output bitmap.bin " << " Height=" << bitmap.Width() << " Width= "
			<< bitmap.Height() << std::endl;

		// Write RGB bitmap to file
		std::fstream rgbFile("bitmapRGB.bin", std::ios::binary | std::ios::trunc |
			std::ios::out);
		rgbFile.write((char*)bitmap.Data().get(), bitmap.ByteSize());
		rgbFile.close();

		std::cout << "Program successfully completed" << std::endl;
		return 0;
	}
	catch (P1::ImageSdk::SdkException exception)
	{
		// Exception from ImageSDK
		std::cout << "ImageSDK Exception: " << exception.what() << " Code:" << exception.mCode <<
			std::endl;
		return -1;
	}
	catch (P1::CameraSdk::SdkException exception)
	{
		// Exception from CameraSDK
		std::cout << "CameraSDK Exception: " << exception.what() << " Code:"
			<< exception.mErrorCode <<
			std::endl;
		return -1;
	}
	catch (...)
	{
		// Any other exception - just in case
		std::cout << "Argh - we got an exception" << std::endl;
		return -1;
	}

}
using System;
using P1.CameraSdk;
using P1.ImageSdk;

namespace TestDocumentation1Cs
{
    class Program
    {
        // This small program demonstrates the CameraSDK and the ImageSDK and how they can be
        // utilized in conjunction with each other.
        // !! On IQ4, this code will only work if the exposure program is set to ‘manual’ !!
        static int Main(string[] args)
        {

            Camera camera = null;
            try
            {
                // All calls to the CameraSDK and ImageSDK must be wrapped in a try-catch,
                // because exceptions are used to report errors, etc.
                Console.WriteLine("Connect to camera");
                camera = Camera.OpenUsbCamera();

                PropertyValue exposureProgram = new PropertyValue(PropertyType.Enum);
                exposureProgram.IntValue = 0; // M
                uint exposureProgramId = 1000;
                camera.SetProperty(exposureProgramId, exposureProgram);

                // Setup ISO, Aperture and Shutter-time
                PropertyValue isoValue = 200.0;
                PropertyValue apertureValue = 5.0;
                PropertyValue shutterTimeValue = 0.125;

                // Property IDs
                uint isoId = 120;
                uint apertureId = 1003;
                uint shutterTimeId = 1002;

                camera.SetProperty(isoId, isoValue);
                camera.SetProperty(apertureId, apertureValue);
                camera.SetProperty(shutterTimeId, shutterTimeValue);

                // Set-up so images will be sent to this computer and trig the capture
                Console.WriteLine("Start capture");

                camera.EnableImageReceiving(true);
                System.Threading.Thread.Sleep(100); // sleep for 100 ms
                camera.TriggerCapture();

                // Wait for image
                IIQImageFile imageFile = camera.WaitForImage(10000);
                Console.WriteLine("Image received");
                camera.Close();

                //------
                // We are done with the CameraSDK, and now use our ImageSDK for the rest
                //------

                // Parse IIQ file
                RawImage image = new RawImage(imageFile.Data.Pointer, (int)imageFile.Data.Length);

                // Decode image data with default values
                DecodeConfig decodeConfig = DecodeConfig.Defaults();
                SensorBayerOutput decodedImage = decodeConfig.ApplyTo(image);
                Console.WriteLine("Decoded image size: {0}, Dimension: {1} x {2}",
                    decodedImage.ByteSize, decodedImage.FullWidth, decodedImage.FullHeight);

                // Write decoded bitmap to file
                System.IO.File.WriteAllBytes("bitmapBayer.bin", decodedImage.Data);

                // Convert image data to RGB
                ConvertConfig config = new ConvertConfig();
                config.SetOutputWidth(1024);
                BitmapImage bitmap = config.ApplyTo(image);
                Console.WriteLine("Output bitmap.bin: {0} x {1}", bitmap.Width, bitmap.Height);

                // Write RGB bitmap to file
                System.IO.File.WriteAllBytes("bitmapRGB.bin", bitmap.Data);

                return 0;
            }
            catch (P1.CameraSdk.SdkException e)
            {
                Console.WriteLine("Camera Sdk error {0} : {1}", e.ErrorCode, e.Message);
                return 1;
            }
            catch (P1.ImageSdk.SdkException e)
            {
                Console.WriteLine("Image Sdk error {0} : {1}", e.Code, e.Message);
                return 1;
            }
            // Added extra catch exception 
            catch (Exception e)
            {
                Console.WriteLine("Output: Any other error: {0}", e.Message);
                return 1;
            }
        } // Main func
    } // Program class
} // namespace

Setting Properties Explanation

When setting properties, both the type and value of the property should be assigned (see Getting / Setting Properties).

// Setup ISO, Aperture and Shutter-time
P1::CameraSdk::PropertyValue isoValue;
isoValue.mType = P1::CameraSdk::kPropertyTypeFloat64;
isoValue.mDouble = 200;

P1::CameraSdk::PropertyValue apertureValue;
apertureValue.mType = P1::CameraSdk::kPropertyTypeFloat64;
apertureValue.mDouble = 5.0;

P1::CameraSdk::PropertyValue shutterTimeValue;
shutterTimeValue.mType = P1::CameraSdk::kPropertyTypeFloat64;
shutterTimeValue.mDouble = 0.125;
// Setup ISO, Aperture and Shutter-time
PropertyValue isoValue = 200.0;
PropertyValue apertureValue = 5.0;
PropertyValue shutterTimeValue = 0.125;

Alternatively, use the conversion operators to assign the properties. This can be seen in the following example, where the type is assigned:

// Setup ISO, Aperture and Shutter-time
P1::CameraSdk::PropertyValue isoValue = (double)200;
P1::CameraSdk::PropertyValue apertureValue = (double)5.0;
P1::CameraSdk::PropertyValue shutterTimeValue = (double)0.125;
// Setup ISO, Aperture and Shutter-time
PropertyValue isoValue1 = (double)200;
PropertyValue apertureValue1 = (double)5.0;
PropertyValue shutterTimeValue1 = (double)0.125;

In C#, typecasting for aperture and shutter time is not strictly necessary in the above example, as 5.0 and 0.125 are already doubles. However, 200 need it, because it will be interpreted as an integer.