[Matlab/C++] VirCam Server To Matlab

This post will illustrate how to use a virtual camera server (in this case one over ethernet) with Matlab. This example makes use of the VirCam server and VirCam SDK for usage with FLIR infrared (thermal) camera’s. Only in this way is it possible to control and observe the camera live through Matlab. It makes use of shared memory.

Framework

What you do, is you take the SDK and compile it in VisualCPP. This will be your ‘server’. When you run this program, it will connect to the camera and, for example, obtain images. These will then be put into virtual memory, making use of the OpenCV framework for digital images.
Then, in Matlab, you will compile a ‘MEX’ file that then obtains these images from the shared memory that were created in your own ‘server’ that you just compiled and started. Then the MEX function returns this image to Matlab. Put this in a loop, and you can view your live feed from the camera through your interface with 0 lag and no speed limitations.

VirCam

“VCamServer is a COM interface Server allowing third part software to manage a Cedip camera through the
distributed object. VCamServer is a synchronised and multi-threaded process so several client can connect to the
camera in parallel.”

Dependencies

This is made for the Windows OS, because that’s what the VirCam SDK works with.
You need the VirCam SDK (this can be bought with FLIR).
You need to install OpenCV (Free, google it.)
You need VisualC++ (Express for example) (Free, google it)

The Code

Below is all the code. You will probably figure it out, given you have some programming knowledge. If not, don’t bother or contact me.

main.cpp

#include<iostream>
#include <stdio.h>
#include <stdlib.h>
#include "C:Program Files (x86)FLIR SystemsVirCamSDKIncludes_VCamServer_i.c"
#include "C:Program Files (x86)FLIR SystemsVirCamSDKIncludes_VCamServer.h"
#include "C:Program Files (x86)FLIR SystemsVirCamSDKIncludesVirCamConst.h"
#include<cstring>
#include<ctime>
#include <windows.h>
#include <memory.h>
#include <conio.h>
#include <tchar.h>
#include "opencv2corecore.hpp"
#include "opencv2highguihighgui.hpp"
 
using namespace cv;
using namespace std;
 
#define NBR_SHARED_MEM	2
#define	IMG_SHARED_MEM	0
#define INF_SHARED_MEM	1
 
//Shared memory structure
typedef struct{
		string						strSharedName;	//Shared memory name
		HANDLE						hSharedMem;			//Handel
		void						* pMemBuffer;			//Data
}structSharedMem;
 
structSharedMem m_sSharedMem[NBR_SHARED_MEM];
 
bool AllocSharedMemory(DWORD dwSizeByte, string & strSharedName, HANDLE & hSharedMem, void *& pMemBuffer)
{
	strSharedName	=	_T("");
	hSharedMem		=	INVALID_HANDLE_VALUE;
	pMemBuffer		=	NULL;
 
	//search free name
	bool bFoundFreeName	=	FALSE;
	strSharedName="GlobalSharedMem";
	for(int i = 0; i< 10000; i++)
	{
 
		//strSharedName.Format("SharedMem%x%x", rand(), rand());
		strSharedName.append("0");
		//cout << " Testing Name =" << strSharedName.c_str() << endl;
		HANDLE hFile	=	OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, strSharedName.c_str());
		if (hFile == NULL)
		{	//found free name
			cout << "Found Free Name =" << strSharedName.c_str() << endl;
			bFoundFreeName	=	TRUE;
			break;
		} else {
			CloseHandle(hFile);
		}
	}
	if (!bFoundFreeName) {
		cout << "Error: Could not find a free name!" << endl;
		return FALSE;
	}
 
 
	//create shared mem
	hSharedMem = CreateFileMapping (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, dwSizeByte, strSharedName.c_str());
	if(!hSharedMem){
		printf("CreateFileMapping failed: %dn", GetLastError());
		cout << "Error: Failed create FileMapping!" << endl;
		return FALSE;
	}
	pMemBuffer = MapViewOfFile( hSharedMem, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
	if(!pMemBuffer)
	{
		printf("MapViewOfFile failed: %dn", GetLastError());
		cout << "Error: Failed creating MapViewOfFile!" << endl;
		CloseHandle(hSharedMem);
		hSharedMem	=	NULL;
		return FALSE;
	}
 
	//To close this shared mem use : CloseHandle(hSharedMem);
 
	return TRUE;
}
 
bool FreeSharedMemory(HANDLE  hSharedMem, void * pMemBuffer)
{
	BOOL bReturn	=	TRUE;
	if (pMemBuffer)
		bReturn	&=	UnmapViewOfFile(pMemBuffer);
 
	bReturn	&=	CloseHandle(hSharedMem);
 
	return bReturn;
}
 
// Free Image and info shared memory
bool FreeSharedMem(void)
{
 
	for(int i = 0; i < NBR_SHARED_MEM; i++){
		if(m_sSharedMem[i].hSharedMem && m_sSharedMem[i].pMemBuffer){
			if(!FreeSharedMemory(m_sSharedMem[i].hSharedMem, m_sSharedMem[i].pMemBuffer))
				return FALSE;
		}
		m_sSharedMem[i].hSharedMem =	NULL;
		m_sSharedMem[i].pMemBuffer	=	NULL;
	}
	return TRUE;
}
 
 
BSTR ConvertMBSToBSTR(const std::string& str)
{
    int wslen = ::MultiByteToWideChar(CP_ACP, 0 /* no flags */,
                                      str.data(), str.length(),
                                      NULL, 0);
 
    BSTR wsdata = ::SysAllocStringLen(NULL, wslen);
    ::MultiByteToWideChar(CP_ACP, 0 /* no flags */,
                          str.data(), str.length(),
                          wsdata, wslen);
    return wsdata;
}
 
 
//****************************************************************************************
 
int main(void)
{
	cout << "(c) Tim Zaman 2013, TU Delft" << endl;
	cout << "Starting Camera Connection Test.." << endl;
 
	IVirtualCam* m_pVirtualCam;
 
	// Initialize COM library
	HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
	if (FAILED(hr)) //if initialization fails then exit
	{
		cout << "Failed to initialize COM library" << endl;
	}
	m_pVirtualCam = NULL;
 
	//Create the COM
	hr = CoCreateInstance( CLSID_CVirtualCam, NULL,
		CLSCTX_LOCAL_SERVER ,IID_IVirtualCam,
		(void**) &m_pVirtualCam);
 
 
 
 
	// Initialize
	unsigned long bAuto=true;
	unsigned long bReturn;
 
	hr = m_pVirtualCam->Init(bAuto, &bReturn);
 
	if (bReturn){
		cout << "Initialization Succesful" << endl;
	} else {
		cout << "Initialization Failed" << endl;
	}
 
	//Check initialization
	unsigned long pbInitialized;
	hr = m_pVirtualCam->IsIni(&pbInitialized, &bReturn);
	if (bReturn){
		cout << "Checking Initialization Succesful" << endl;
		if (pbInitialized){
			cout << " Initialization Indeed Succesful" << endl;
		} else {
			cout << " Initialization Indeed Failed" << endl;
		}
	} else {
		cout << "Checking Initialization Failed" << endl;
	}
 
 
	//Check if the server is running
	hr = m_pVirtualCam->IsServerRunning();
	cout << "Server Running: " << hr << endl;
 
	//Get Version
	unsigned long pdwVersionMajor,pdwVersionMinor,pdwVersionBuild;
	hr = m_pVirtualCam->GetVersion(&pdwVersionMajor,&pdwVersionMinor,&pdwVersionBuild);
	cout << "Version=" << pdwVersionMajor <<"."<<pdwVersionMinor << " build=" << pdwVersionBuild << endl;
 
 
	//Scan Cameras
	hr = m_pVirtualCam->ScanCams(&bReturn);
	if (bReturn){
		cout << "Camera Scan Succesful" << endl;
	} else {
		cout << "Camera Scan Failed" << endl;
	}
 
	long nCount;
	hr = m_pVirtualCam->GetScannedCamCount(&nCount);
	cout << "Cameras found: " << nCount << endl;
 
 
	long nIdxScannedCam=0; // Evaluate this camera idx
 
	BSTR strCamSn = SysAllocString( L"XXXXXXXXXX" );
	BSTR strInterface = SysAllocString( L"XXXXXXXXXX" );
	hr = m_pVirtualCam->GetScannedInterfaceBasicInfo(nIdxScannedCam, &strCamSn, &strInterface, &bReturn);
 
	if (bReturn){
		cout << "Obtaining Basic Info Succesful" << endl;
		wcout << " CamSN=" << strCamSn << " strInterface=" << strInterface << endl;
	} else {
		cout << "Obtaining Basic Info Failed" << endl;
	}
 
 
	//Now connect to camera
 
	hr = m_pVirtualCam->ConnectToCamScanned(nIdxScannedCam, &bReturn);
	if (bReturn){
		cout << "Connecting to Scanned Camera Succesful" << endl;
	} else {
		cout << "Connecting to Scanned Camera Failed" << endl;
	}
 
 
 
	//Check if framegrabber is avaiable
	unsigned long pbCandoIt;
	BSTR pstrReason = SysAllocString( L"XXXXXXXXXX" );
	hr = m_pVirtualCam->IsGrabberCap(&pbCandoIt, &pstrReason, &bReturn);
 
	if (bReturn){
		cout << "Grabber Checking Succesful" << endl;
		if (pbCandoIt){
			cout << "Frame Grabber Available" << endl;
		} else {
			cout << "Frame Grabber NOT Available" << endl;
			wcout << "Error =" <<  pstrReason << endl;
		}
	} else {
		cout << "Grabber Checking Failed" << endl;
	}
 
 
	//Performing Filter Test
	for (int i=0;i<2;i++){
		hr = m_pVirtualCam->SetCurrentFilter(i,&bReturn);
		if (bReturn){
				cout << "Filter Change Test Succesful" << endl;
		} else {
				cout << "Filter Change Test Failed" << endl;
		}
	}
 
 
 
	cout << "Checking Window Size" << endl;
	long nCurrentWindowIdx;
	unsigned long dwWidth, dwHeigth, dwLeft, dwTop;
	hr =	m_pVirtualCam->GetCurrentWindow(&nCurrentWindowIdx, &dwWidth, &dwHeigth, &dwLeft, &dwTop, &bReturn);
	if (bReturn){
			cout << "Current Window Acquisition Succesful" << endl;
	} else {
			cout << "Current Window Acquisition Failed" << endl;
	}
	cout << " nCurrentWindowIdx=" << nCurrentWindowIdx << endl;
	cout << " (x,y)=(" << dwWidth << "," << dwHeigth << ") (left,top)=(" << dwLeft << "," << dwTop << ")" << endl;
 
	cout << "Checking Integration Time" << endl;
	unsigned long pdwIt, pdwDelay;
	hr =	m_pVirtualCam->GetCurrentIT(&pdwIt, &pdwDelay, &bReturn);
	if (bReturn){
			cout << "Integration Time Acquisition Succesful" << endl;
	} else {
			cout << "Integration Time Acquisition Failed" << endl;
	}
	cout << " IT=" << pdwIt << " delay=" << pdwDelay << endl;
 
	//////////////////////////////////
 
	//Get Image
	cout << "Grabbing Image.." << endl;
	unsigned long nNumberImagePacket;
	hr = m_pVirtualCam->GetNumberImagePacket(&nNumberImagePacket, &bReturn);
	cout << "NumberImagePacket=" << nNumberImagePacket << endl;
	if (bReturn){
			cout << "Image Packet Number Acquisition Succesful" << endl;
	} else {
			cout << "Image Packet Number Acquisition Failed" << endl;
	}
 
 
 
 
	//////////////////////////////////////////////
	//Shared Memory
	for(int i = 0; i < NBR_SHARED_MEM; i++){
		m_sSharedMem[i].hSharedMem			=	NULL;
		m_sSharedMem[i].pMemBuffer			=	NULL;
		m_sSharedMem[i].strSharedName		=	"";
	}
 
	if(!FreeSharedMem())
		cout << "FreeSharedMem FAILED" << endl;
 
	if(!AllocSharedMemory((dwWidth * dwHeigth) * sizeof(WORD), m_sSharedMem[IMG_SHARED_MEM].strSharedName, m_sSharedMem[IMG_SHARED_MEM].hSharedMem, m_sSharedMem[IMG_SHARED_MEM].pMemBuffer))
			cout << "AllocSharedMemory (IMG) FAILED" << endl;
 
	if(!AllocSharedMemory(sizeof(InfoImageStruct), m_sSharedMem[INF_SHARED_MEM].strSharedName, m_sSharedMem[INF_SHARED_MEM].hSharedMem, m_sSharedMem[INF_SHARED_MEM].pMemBuffer))
			cout << "AllocSharedMemory (INFO) FAILED" << endl;
	((InfoImageStruct*)m_sSharedMem[INF_SHARED_MEM].pMemBuffer)->wStructSize	=	sizeof(InfoImageStruct);
 
 
	BSTR		bstrNextImageBuffer	=	ConvertMBSToBSTR(m_sSharedMem[IMG_SHARED_MEM].strSharedName);
	BSTR		bstrNextInfoBuffer	=	ConvertMBSToBSTR(m_sSharedMem[INF_SHARED_MEM].strSharedName);
 
	//for(int k=0;k<50;k++){
	while (1){
		//cout << "k=" << k << ".." << endl;
		hr = m_pVirtualCam->GetImage(dwWidth, dwHeigth, nNumberImagePacket, bstrNextImageBuffer, 0, bstrNextInfoBuffer, 0, 2000, &bReturn);
 
		SysFreeString(bstrNextImageBuffer);
		SysFreeString(bstrNextInfoBuffer);
 
		WORD* test = ((WORD*)m_sSharedMem[IMG_SHARED_MEM].pMemBuffer);
 
		Mat mImage = Mat::ones(dwHeigth, dwWidth, CV_16U);
 
 
 
		int i=0;
		for (int x=0; x<dwHeigth; x++){
			for (int y=0; y<dwWidth; y++){
				mImage.at<word>(x,y) = *(test+i);
				//mImage.data[mImage.rows*x+y] = *(test+i); //This has got 16bit issues
				//cout << "i=" << i << " "<< *(test+i) << " -> " << mImage.at<word>(x,y) << endl;
				i++;
			}
		}
 
		//normalize(mImage, mImage, 0, 65535, NORM_MINMAX, CV_16U);
 
		//imwrite("disp16.tiff",mImage);
		//namedWindow("Image Dialog");
		//imshow("Image Dialog", mImage);
		//waitKey(0);
		//destroyWindow("Image Dialog");
	}
 
 
 
	InfoImageStruct*	pInfoImage	=	((InfoImageStruct*)m_sSharedMem[INF_SHARED_MEM].pMemBuffer);
	if(pInfoImage){
 
		cout << pInfoImage->dwStructCaps << endl;
		cout << pInfoImage->qwImageTime << endl;
		cout << pInfoImage->fDetectorTemp << endl;
		cout << pInfoImage->fSensorTemp[0] << endl;
		/*CString strValue;
		strValue.Format("X%.8X", pInfoImage->dwStructCaps);
		m_ctlImageInfo.SetItemText(Info_StructCaps, 1, strValue );
		strValue.Format("%I64u", pInfoImage->qwImageTime);
		m_ctlImageInfo.SetItemText(Info_ImageTime, 1, strValue );
		strValue.Format("%I64u", pInfoImage->qwImageCounter);
		m_ctlImageInfo.SetItemText(Info_ImageCounter, 1, strValue );
		strValue.Format("%d", pInfoImage->wMultiItNumber);
		m_ctlImageInfo.SetItemText(Info_MultiItNumber, 1, strValue );
		strValue.Format("%d", pInfoImage->wAnalogicalVideoITChannel);
		m_ctlImageInfo.SetItemText(Info_AnalogicalVideoITChannel, 1, strValue );
		strValue.Format("%d", pInfoImage->wNumericalVideoITChannel);
		m_ctlImageInfo.SetItemText(Info_NumericalVideoITChannel, 1, strValue );
		strValue.Format("%d", pInfoImage->wNucIndex);
		m_ctlImageInfo.SetItemText(Info_NucIndex, 1, strValue );
		strValue.Format("%d", pInfoImage->byPageIndex);
		m_ctlImageInfo.SetItemText(Info_PageIndex, 1, strValue );
 
		strValue.Format("%.1f", pInfoImage->fDetectorTemp);
		m_ctlImageInfo.SetItemText(Info_DetectorTemp, 1, strValue );
		strValue.Format("%.1f", pInfoImage->fSensorTemp[0]);
		m_ctlImageInfo.SetItemText(Info_SensorTemp1, 1, strValue );
		strValue.Format("%.1f", pInfoImage->fSensorTemp[1]);
		m_ctlImageInfo.SetItemText(Info_SensorTemp2, 1, strValue );
		strValue.Format("%.1f", pInfoImage->fSensorTemp[2]);
		m_ctlImageInfo.SetItemText(Info_SensorTemp3, 1, strValue );
		strValue.Format("%.1f", pInfoImage->fSensorTemp[3]);
		m_ctlImageInfo.SetItemText(Info_SensorTemp4, 1, strValue );
		strValue.Format("%.0f", pInfoImage->fMasterClock);
		m_ctlImageInfo.SetItemText(Info_MasterClock, 1, strValue );
		strValue.Format("%f", pInfoImage->fIntegrationTime);
		m_ctlImageInfo.SetItemText(Info_IntegrationTime, 1, strValue );
		strValue.Format("%.1f", pInfoImage->fFrameRate);
		m_ctlImageInfo.SetItemText(Info_FrameRate, 1, strValue );
		strValue.Format("%d", pInfoImage->byFilterPosition);
		m_ctlImageInfo.SetItemText(Info_FilterPos, 1, strValue );
		strValue.Format("%d", pInfoImage->bExternalTrigger);
		m_ctlImageInfo.SetItemText(Info_ExternalTrigger, 1, strValue );
		strValue.Format("%d", pInfoImage->byTrigInput);
		m_ctlImageInfo.SetItemText(Info_TriggerInput, 1, strValue);
 
		strValue.Format("%d", pInfoImage->wLockinBoxVersion);
		m_ctlImageInfo.SetItemText(Info_LockinVersion, 1, strValue );
		strValue.Format("%d", pInfoImage->dwLockinPeriod);
		m_ctlImageInfo.SetItemText(Info_LockinPeriod, 1, strValue );
		strValue.Format("%d", pInfoImage->dwLockinPhase);
		m_ctlImageInfo.SetItemText(Info_LockinPhase, 1, strValue );
		strValue.Format("%d", pInfoImage->bLockinMin);
		m_ctlImageInfo.SetItemText(Info_LockinMin, 1, strValue );
		strValue.Format("%d", pInfoImage->bLockinMax);
		m_ctlImageInfo.SetItemText(Info_LockinMax, 1, strValue );
		strValue.Format("%d", pInfoImage->bySignalNumber);
		m_ctlImageInfo.SetItemText(Info_LockinSignalNumber, 1, strValue );
		strValue.Format("%d", pInfoImage->wLockinMeanValue[0]);
		m_ctlImageInfo.SetItemText(Info_LockinSignal1, 1, strValue );
		strValue.Format("%d", pInfoImage->wLockinMeanValue[1]);
		m_ctlImageInfo.SetItemText(Info_LockinSignal2, 1, strValue );
		strValue.Format("%d", pInfoImage->wLockinMeanValue[2]);
		m_ctlImageInfo.SetItemText(Info_LockinSignal3, 1, strValue );
		strValue.Format("%d", pInfoImage->wLockinMeanValue[3]);
		m_ctlImageInfo.SetItemText(Info_LockinSignal4, 1, strValue );*/
	}
 
 
 
 
 
 
 
 
 
 
 
 
	if (bReturn){
			cout << "Image Acquisition Succesful" << endl;
	} else {
			cout << "Image Acquisition Failed" << endl;
	}
 
 
	//Free the COM
	cout << "Freeing COM.." << endl;
	if (m_pVirtualCam){
		m_pVirtualCam->Release();
		m_pVirtualCam = NULL;
	}
	CoUninitialize();
 
	cout << "Done." << endl;
 
	//system("PAUSE");
 
}

mex.cpp

#include <math.h>
#include <matrix.h>
#include <mex.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <ctime>
#include <windows.h>
#include <memory.h>
#include <conio.h>
#include <tchar.h>
 
using namespace std;
 
#define BUF_SIZE 655360
 
 
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
	TCHAR szName[]=TEXT("GlobalSharedMem0");
	HANDLE hMapFile;
	LPCTSTR pBuf;
 
	hMapFile = OpenFileMapping(
				   FILE_MAP_ALL_ACCESS,   // read/write access
				   FALSE,                 // do not inherit the name
				   szName);               // name of mapping object
 
	if (hMapFile == NULL)
	{
	  _tprintf(TEXT("Could not open file mapping object (%d).n"),
			 GetLastError());
	  //return 1;
	}
 
	pBuf = (LPTSTR) MapViewOfFile(hMapFile, // handle to map object
			   FILE_MAP_ALL_ACCESS,  // read/write permission
			   0,
			   0,
			   BUF_SIZE);
 
	if (pBuf == NULL)
	{
	  _tprintf(TEXT("Could not map view of file (%d).n"),
			 GetLastError());
 
	  CloseHandle(hMapFile);
 
	  //return 1;
	}
 
	WORD* test = ((WORD*)pBuf);
 
	//mexPrintf(char(*(test)));
	//cout << *(test) << endl;
 
 
	mxArray *c_out_m;
	c_out_m = plhs[0] = mxCreateNumericMatrix(640, 512, mxUINT16_CLASS, mxREAL);
	double *mImage;
	mImage = mxGetPr(c_out_m);
 
 
	//mImage[1]=*(test+0);
 
	memcpy(mImage, test , sizeof(unsigned short)*640*512);
 
	int i=0;
	for (int x=0; x<512; x++){
		for (int y=0; y<640; y++){
			//mexPrintf("i=%d;(x,y)=(%d,%d)=%dn",i,x,y,*(test+i));
			//mImage[i]=*(test+i);
			//mImage
			//mImage.at<word>(x,y) = *(test+i);
			//cout << "i=" << i << " "<< *(test+i) << " -> " << mImage.at<word>(x,y) << endl;
			i++;
		}
	}
 
 
	UnmapViewOfFile(pBuf);
 
	CloseHandle(hMapFile);
 
	//mexPrintf("Done.n");
}

test.m

%(c) Tim Zaman 2013
imagesc(mexTest);

Tim Zaman

MSc Biorobotics. Specialization in computer vision and deep learning. Works at NVIDIA.

You may also like...