/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016 Raytrix GmbH. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/************************************************************************/
/* This example demonstrates: */
/* - Working with one camera with multiple GPUs */
/************************************************************************/
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// namespace: Example.LFR.CS.BasicD
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Example.LFR.CS.CameraC
{
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// Multiple Cameras one GPU synchronous.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class Example
{
/// The CUDA compute class.
Rx.LFR.Net.CudaCompute[] m_pxCudaCompute;
/// The visualization handles.
int m_iHandle;
/// The camera server class that is able to find attached cameras.
Rx.LFR.Net.CameraServer m_xCamServer;
/// The camera buffers.
Rx.LFR.Net.ImageQueue m_xCamBuffer;
/// The camera buffers.
Rx.LFR.Net.ImageQueue m_xComputedBuffer;
/// The threads.
System.Threading.Thread[] m_xThreads;
/// true to stop thread.
bool m_bStopThread = false;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// Executes the image captured action.
///
///
/// The image.
/// The camera index.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void OnImageCaptured(Rx.LFR.Net.ConstImage xConstImage, uint uCameraIndex)
{
/************************************************************************/
/* Image Captured */
/************************************************************************/
// ATTENTION:
// All processing done in this callback would prevents the camera from capturing the next image.
// Therefore it's advisable to BUFFER the image here and to process it in another thread.
/************************************************************************/
/* Write into buffer */
/************************************************************************/
if (!m_xCamBuffer.CopyIn(xConstImage))
{
// Buffer is full and overwrite is disabled
// This is a lost frame
return;
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// Process the image.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ProcessImage(object uCudaDevice)
{
// As long as this application is not stopped
while (!m_bStopThread)
{
try
{
// Wait for the image buffer to be not empty
if (m_xCamBuffer.WaitForNotEmpty(1000))
{
Console.WriteLine("Buffer not empty");
// Get the first image in the Queue
Rx.Net.Image xImage = new Rx.Net.Image();
if (!m_xCamBuffer.MoveOut(xImage))
{
// Wait again! This functions says that it waits until a frame is available
continue;
}
Console.WriteLine("Getting Cuda Device with index {0}", (int) uCudaDevice);
// Get the CUDA compute class for this camera
Rx.LFR.Net.CudaCompute xCudaCompute = m_pxCudaCompute[(int) uCudaDevice];
Console.WriteLine("Uploading image ...");
// Upload the captured image as the new raw image of all further CUDA computations
xCudaCompute.UploadRawImage(xImage);
Console.WriteLine("Processing image ...");
// Calculate the desired images
xCudaCompute.Compute_PreProcess();
xCudaCompute.Compute_RefocusBasic();
xCudaCompute.Compute_DepthRay();
xCudaCompute.Compute_DepthMap(Rx.LFR.Net.ESpace.View_Object_Pinhole);
xCudaCompute.Compute_TotalFocus(Rx.LFR.Net.ESpace.View_Object_Pinhole);
xCudaCompute.Compute_Depth3D();
xCudaCompute.Compute_DepthColorCode(Rx.LFR.Net.ESpace.View_Object_Pinhole);
// Get the image access interface. This interface allows:
// * Download CUDA image into host memory
// * Upload a host image to CUDA to overwrite a certain CUDA image
// * Access to CUDA device pointer to do own CUDA image processing
Rx.LFR.Net.ICudaDataImages xImages = (xCudaCompute.GetInterface(Rx.LFR.Net.Interfaces.ECudaCompute.Images)) as Rx.LFR.Net.ICudaDataImages;
Console.WriteLine("Downloading image ...");
using (Rx.Net.Image xImgDepthMapColor = new Rx.Net.Image())
{
// Download images into the host memory
xImages.Download(Rx.LFR.Net.EImage.DepthMapColored_View_Object_Pinhole, xImgDepthMapColor);
// Move image into computed buffer
m_xComputedBuffer.MoveIn(xImgDepthMapColor);
}
}
}
catch (Rx.Net.RxException ex)
{
Console.WriteLine("Exception");
Console.WriteLine("\n\n\nOnImageCaptured Exception:\n\n\n{0}\n\n\n", ex.ToString(true));
Environment.Exit(-1);
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// Process the image.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ShowImage()
{
// As long as this application is not stopped
while (!m_bStopThread)
{
try
{
// Wait for the image buffer to be not empty
if (m_xComputedBuffer.WaitForNotEmpty(1000))
{
Console.WriteLine("Computed image buffer not empty");
// Get the first image in the Queue
using (Rx.Net.Image xImage = new Rx.Net.Image())
{
if (!m_xComputedBuffer.MoveOut(xImage))
{
// Wait again! This functions says that it waits until a frame is available
continue;
}
CLUViz.Net.Tool.ViewSetImage(m_iHandle, xImage);
}
}
}
catch (Rx.Net.RxException ex)
{
Console.WriteLine("Exception");
Console.WriteLine("\n\n\nOnImageCaptured Exception:\n\n\n{0}\n\n\n", ex.ToString(true));
Environment.Exit(-1);
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// Runs this example.
///
///
/// The return code.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public int Run()
{
Console.WriteLine("Initializing visualization...");
CLUViz.Net.Tool.Init();
/************************************************************************/
/* Authenticate LFR */
/************************************************************************/
Rx.LFR.Net.LightFieldRuntime.Authenticate();
/// Initialize the calibration manager.
Rx.LFR.Net.CalibrationManager.Initialize();
// Enumerate all CUDA devices at the beginning
Rx.LFR.Net.Cuda.EnumerateCudaDevices();
uint uBufferSize = System.Convert.ToUInt32(5);
bool bOverwrite = false;
System.Console.WriteLine("Please enter depth settings path: ");
System.String xDepthSettingsPath = System.Console.ReadLine();
if (!System.IO.File.Exists(xDepthSettingsPath))
{
System.Console.WriteLine("File does not exist!");
return -1;
}
/************************************************************************/
/* CUDA */
/************************************************************************/
int iCudaDevices = Rx.LFR.Net.Cuda.GetDeviceCount();
m_pxCudaCompute = new Rx.LFR.Net.CudaCompute[iCudaDevices];
m_xThreads = new System.Threading.Thread[iCudaDevices];
Console.WriteLine("CUDA Devices");
for (int iIdx = 0; iIdx < Rx.LFR.Net.Cuda.GetDeviceCount(); iIdx++)
{
Rx.LFR.Net.CudaDevice xCuda = Rx.LFR.Net.Cuda.GetDevice(iIdx);
string sName;
xCuda.GetParams().GetValue(Rx.LFR.Net.Params.ECudaDevice.Name, out sName);
double dClockMHz;
xCuda.GetParams().GetValue(Rx.LFR.Net.Params.ECudaDevice.ClockFrequencyMHz, out dClockMHz);
double dGlobalMemMB;
xCuda.GetParams().GetValue(Rx.LFR.Net.Params.ECudaDevice.TotalGlobalMemoryMB, out dGlobalMemMB);
Console.WriteLine("{0}: {1}, Clock: {2} MHz, Memory: {3} MB", iIdx, sName, dClockMHz, dGlobalMemMB);
}
/************************************************************************/
/* Find Cameras */
/************************************************************************/
Console.WriteLine("Find Cameras");
// Add a status message callback if you are interested in status messages sent by the camera server while finding cameras
m_xCamServer = new Rx.LFR.Net.CameraServer();
// Start to find cameras. This is an synchronous call and we wait here until the find process has been finished
m_xCamServer.FindCameras();
// Quit the application if there is no camera
if (m_xCamServer.GetCameraCount() == 0)
{
Console.Write("No camera found\n");
return -1;
}
/************************************************************************/
/* Start Cameras */
/************************************************************************/
Console.WriteLine("Start Cameras");
int iAssignedCudaDevice = 0;
/************************************************************************/
/* Initialize Buffer */
/************************************************************************/
// Create buffer within the given size and with the given overwrite flag
m_xCamBuffer = new Rx.LFR.Net.ImageQueue();
m_xCamBuffer.Initialize(uBufferSize, bOverwrite);
// Get the camera from our camera server
Rx.LFR.Net.Camera xCamera = m_xCamServer.GetCamera(0);
// Load the default calibration of the camera (and load the gray image too)
Rx.LFR.Net.Calibration xDefaultCalibration = new Rx.LFR.Net.Calibration();
Rx.LFR.Net.CalibrationManager.LoadDefaultCalibration(xDefaultCalibration, xCamera, true);
// Open the camera. This prepares the communication with the camera and checks the connection of GigE cameras
// This does NOT start the camera stream
xCamera.Open();
// Add a image captured callback. This method gets called for every captured camera image and more details are given there
xCamera.ImageCaptured += OnImageCaptured;
string sCudaName;
(Rx.LFR.Net.Cuda.GetDevice((int) iAssignedCudaDevice)).GetParams().GetValue(Rx.LFR.Net.Params.ECudaDevice.Name, out sCudaName);
// Create the visualization
// If there is one image buffer per camera set the view caption to the camera name;
string sCameraName = Rx.LFR.Net.CalibrationManager.GetCameraName(xCamera);
m_iHandle = CLUViz.Net.Tool.CreateViewImage((int) 0, 0, 1000, 800, sCameraName);
float fMin = 0.0f;
float fMax = 0.0f;
xCamera.GetPropertyRange(Rx.InteropNet.Runtime30.Camera.EProperty.Framerate, out fMin, out fMax);
xCamera.SetProperty(Rx.InteropNet.Runtime30.Camera.EProperty.Framerate, fMax);
Console.WriteLine("Setting Camera {0} to its max FPS: {1}", sCameraName, fMax);
xCamera.GetPropertyRange(Rx.InteropNet.Runtime30.Camera.EProperty.Exposure, out fMin, out fMax);
// Start the camera. Depending on the given trigger mode, the camera starts to capture images or waits for a trigger
xCamera.Start(Rx.InteropNet.Runtime30.Camera.ETriggerMode.Camera_FreeRun);
for (int iIdx = 0; iIdx < Rx.LFR.Net.Cuda.GetDeviceCount(); iIdx++)
{
// Assign the CUDA device and the calibration
m_pxCudaCompute[iIdx] = new Rx.LFR.Net.CudaCompute();
m_pxCudaCompute[iIdx].SetCudaDevice(Rx.LFR.Net.Cuda.GetDevice((int) iAssignedCudaDevice));
m_pxCudaCompute[iIdx].ApplyCalibration(xDefaultCalibration, true);
m_pxCudaCompute[iIdx].GetParams().ImportFromFile(xDepthSettingsPath);
m_xThreads[iIdx] = new System.Threading.Thread(ProcessImage);
m_xThreads[iIdx].Start(iIdx);
}
// Start visualization thread
m_xComputedBuffer = new Rx.LFR.Net.ImageQueue();
m_xComputedBuffer.Initialize(uBufferSize, bOverwrite);
System.Threading.Thread xVisioThread = new System.Threading.Thread(ShowImage);
xVisioThread.Start();
Console.WriteLine("--------------------------------------------------------------------------------------------------");
Console.WriteLine("Camera {0} with Index {1} is assigned to cuda device {2} with index {3}.", sCameraName, 0, sCudaName, iAssignedCudaDevice);
Console.WriteLine("--------------------------------------------------------------------------------------------------");
if (iAssignedCudaDevice < iCudaDevices - 1)
{
iAssignedCudaDevice++;
}
/************************************************************************/
/* Wait */
/************************************************************************/
// Press any key to stop the capturing
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
/************************************************************************/
/* Stop Threads */
/************************************************************************/
m_bStopThread = true;
foreach (System.Threading.Thread xThread in m_xThreads)
{
xThread.Join();
}
xVisioThread.Join();
/************************************************************************/
/* Close Cameras */
/************************************************************************/
Console.WriteLine("Close Cameras");
for (uint uCameraIndex = 0; uCameraIndex < m_xCamServer.GetCameraCount(); uCameraIndex++)
{
// Stop the capture of the camera
m_xCamServer.GetCamera(uCameraIndex).Stop();
// Close the cameras and release the communication and its required memory
m_xCamServer.GetCamera(uCameraIndex).Close();
}
// Release the camera server to free all found cameras. All cameras are invalid after this call
m_xCamServer.Release();
return 0;
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// A program.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static class Program
{
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// The main entry point for the application.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void Main()
{
new Example().Run();
}
}
}