Camera ID Format Migration Guide

Overview

UnrealCV supports two camera identification formats: the legacy Integer Format and the new CID (Camera ID) Format. This guide explains both formats and provides migration strategies for existing codebases.

Why Migrate?

  • Integer format is unstable across sessions (order-dependent)

  • CID format is stable and tied to sensor instances

  • CID format supports better debugging and logging

  • Future features will require CID format

Camera ID Formats

Integer Format (Legacy)

Format: 0, 1, 2, …

Description: Cameras are identified by their creation order index. The first camera created is ID 0, second is ID 1, etc.

Example:

vget /camera/0/location
vget /camera/1/view

Issues: - Unstable: Camera order may change between sessions - Unclear: ID doesn’t indicate which camera - Error-prone: Easy to reference wrong camera

Backward Compatibility

All UnrealCV functions accept both formats:

UFusionCamSensor* FCameraIDManager::GetSensorByAnyID(const FString& IDString)
{
   // Detect format automatically
   if (IDString.StartsWith(TEXT("CID")))
   {
      // CID format
      return GetSensorByCID(IDString);
   }
   else
   {
      // Integer format
      int32 Index = FCString::Atoi(*IDString);
      return GetSensorByIndex(Index);
   }
}

API Reference

FCameraIDManager

Header: Source/UnrealCV/Private/BPFunctionLib/SensorBPLib.cpp

GetSensorByAnyID

static UFusionCamSensor* GetSensorByAnyID(const FString& IDString);

Gets a sensor by either integer or CID format.

Parameters:

  • IDString (FString): Camera ID (integer or CID)

Returns: Pointer to sensor, or nullptr if not found

Example:

UFusionCamSensor* Sensor = FCameraIDManager::Get().GetSensorByAnyID("CID-FusionCamPawn-00");
UFusionCamSensor* Sensor = FCameraIDManager::Get().GetSensorByAnyID("0");

GetIndexByAnyID

static int32 GetIndexByAnyID(const FString& IDString);

Gets the integer index for a camera ID.

Parameters:

  • IDString (FString): Camera ID (integer or CID)

Returns: Integer index, or -1 if invalid

GetNewFormatID

static FString GetNewFormatID(UFusionCamSensor* Sensor);

Converts a sensor to CID format.

Parameters:

  • Sensor (UFusionCamSensor*): Sensor to convert

Returns: CID format string

GenerateUUID

static FString GenerateUUID(UFusionCamSensor* Sensor);

Generates a unique CID for a sensor.

Parameters:

  • Sensor (UFusionCamSensor*): Sensor to generate ID for

Returns: Unique CID string

PrintIDMappings

static void PrintIDMappings() const;

Logs all camera ID mappings for debugging.

Output Example:

=== Camera ID Mappings ===
  CID-FusionCamPawn-00
  CID-FusionCamPawn-01
  CID-Drone_BP-00

USensorBPLib Helpers

Header: Source/UnrealCV/Public/BPFunctionLib/SensorBPLib.h

GetFusionSensorList

static TArray<UFusionCamSensor*> GetFusionSensorList();

Gets all sensors in the current world.

Returns: Array of all sensors

GetSensorById

static UFusionCamSensor* GetSensorById(int SensorId);

Gets sensor by integer ID.

Parameters:

  • SensorId (int): Integer camera ID

Returns: Sensor pointer, or nullptr

GetSensorByAnyID

static UFusionCamSensor* GetSensorByAnyID(const FString& IDString);

Gets sensor by CID or integer format.

GetIndexByAnyID

static int32 GetIndexByAnyID(const FString& IDString);

Gets index for any camera ID format.

GetFusionSensorListWithNewIDs

static TArray<FString> GetFusionSensorListWithNewIDs();

Gets all sensors with their CID format.

Returns: Array of all CIDs

GetSensorNewFormatID

static FString GetSensorNewFormatID(UFusionCamSensor* Sensor);

Gets CID for a specific sensor.

PrintCameraIDMappings

static void PrintCameraIDMappings();

Prints all ID mappings to log.

Migration Strategies

Strategy 1: Gradual Migration

  1. Use GetSensorByAnyID() in new code

  2. Keep integer IDs in existing code

  3. Let the system handle format detection

New Code:

// Works with both formats
UFusionCamSensor* Sensor = USensorBPLib::GetSensorByAnyID("CID-FusionCamPawn-00");

Existing Code:

// Still works
UFusionCamSensor* Sensor = USensorBPLib::GetSensorById(0);

Strategy 2: Full Migration

  1. Convert all camera references to CID format

  2. Use GetNewFormatID() to discover CIDs

  3. Store CIDs in configuration files

Discovery:

// Print all CIDs for configuration
USensorBPLib::PrintCameraIDMappings();

// Get all CIDs programmatically
TArray<FString> AllCIDs = USensorBPLib::GetFusionSensorListWithNewIDs();

Configuration:

{
   "cameras": [
      "CID-FusionCamPawn-00",
      "CID-FusionCamPawn-01"
   ]
}

Strategy 3: UUID-Based Selection

For scripts and automation, use CID format:

from unrealcv import client

# Get camera by CID
res = client.request('vget /camera/CID-FusionCamPawn-00/location')

# List all CIDs
cameras = client.request('vget /camera/list')

Common Migration Patterns

Pattern: Iterate All Cameras

Before (Integer):

for (int32 i = 0; i < CameraCount; i++)
{
   auto Sensor = USensorBPLib::GetSensorById(i);
   // ...
}

After (CID):

TArray<UFusionCamSensor*> Sensors = USensorBPLib::GetFusionSensorList();
for (auto Sensor : Sensors)
{
   FString CID = USensorBPLib::GetSensorNewFormatID(Sensor);
   // ...
}

Pattern: Config-Driven Camera Selection

Before:

{
   "primary_camera": 0,
   "secondary_camera": 1
}

After:

{
   "primary_camera": "CID-FusionCamPawn-00",
   "secondary_camera": "CID-FusionCamPawn-01"
}

Pattern: Dynamic Camera Creation

// Create camera via RecordingBPLib
int32 CameraID = URecordingBPLib::CreateFreeCamera(WorldContext);

// Get CID for new camera
FString CID = USensorBPLib::GetSensorNewFormatID(
   USensorBPLib::GetSensorById(CameraID));

UE_LOG(LogTemp, Log, TEXT("Created camera: %s"), *CID);

Troubleshooting

Problem: Camera Not Found

Solution: Use PrintCameraIDMappings() to verify IDs

USensorBPLib::PrintCameraIDMappings();

Problem: Multiple Sensors with Same CID

Cause: Sensor regeneration without world reset

Solution: Call Sync() to refresh mappings

FCameraIDManager::Get().Sync();

Problem: Integer ID Out of Range

Cause: Camera count changed between sessions

Solution: Use CID format or validate index

int32 Index = USensorBPLib::GetIndexByAnyID("0");
if (Index >= 0)
{
   // Valid
}
else
{
   // Invalid
}

Best Practices

  1. Use CID for new development - Stable across sessions - Better debugging

  2. Store CIDs in configs - Not integer indices - Survives engine restarts

  3. Use GetSensorByAnyID() - Works with both formats - Future-proof code

  4. Print mappings during init - For debugging - In development builds

  5. Handle null returns - Always check for nullptr - Provide fallback logic

See Also