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
CID Format (Recommended)
Format: CID-ActorName-UUID
Components:
- CID - Prefix indicating CID format
- ActorName - Name of the actor owning the sensor
- UUID - Unique identifier (2-digit hex, or random if collision)
Examples:
CID-FusionCamPawn-00
CID-FusionCamPawn-01
CID-Drone_BP-00
CID-MyCameraActor-AB
Generation:
FString FCameraIDManager::GenerateUUID(UFusionCamSensor* Sensor)
{
FString ParentActorName = TEXT("Unknown");
if (IsValid(Sensor))
{
AActor* Owner = Sensor->GetOwner();
if (IsValid(Owner))
{
ParentActorName = Owner->GetName();
}
}
FString GeneratedID;
// Retry with incremental ID first
for (int32 RetryCount = 0; RetryCount < 50; RetryCount++)
{
GeneratedID = FString::Printf(TEXT("CID-%s-%02x"),
*ParentActorName, RetryCount);
if (!UsedCameraIDs.Contains(GeneratedID))
{
break;
}
}
// Fall back to random ID if collision
if (UsedCameraIDs.Contains(GeneratedID))
{
uint32 RandomValue = FMath::Rand() & 0xff;
GeneratedID = FString::Printf(TEXT("CID-%s-%02x"),
*ParentActorName, RandomValue);
}
return GeneratedID;
}
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
Use
GetSensorByAnyID()in new codeKeep integer IDs in existing code
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
Convert all camera references to CID format
Use
GetNewFormatID()to discover CIDsStore 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
Use CID for new development - Stable across sessions - Better debugging
Store CIDs in configs - Not integer indices - Survives engine restarts
Use GetSensorByAnyID() - Works with both formats - Future-proof code
Print mappings during init - For debugging - In development builds
Handle null returns - Always check for nullptr - Provide fallback logic
See Also
UnrealCV Dev for UnrealZoo - UnrealCV Dev For UnrealZoo camera feature summary