📄 realtimedemo.cpp
字号:
//-----------------------------------------------------------------------------
// (c) 2002 by Basler Vision Technologies
// Section: Vision Components
// Project: BCAM
// $Header: RealtimeDemo.cpp, 6, 02.10.2002 17:22:58, Happe, A.$
//-----------------------------------------------------------------------------
/**
\file RealtimeDemo.cpp
\brief Main implementation file of the realtime demo.
* This program measures the jitter of the wake up time when waiting for
* a new buffer arriving at the completion port.
*
* The image acquisition is done by a separate thread. To reduce the jitter, the
* thread's priority level is raised above 15 (realtime class), without changing
* the priority class of the whole process.
*
* The main thread produces a high computational load.
*/
#include "stdafx.h"
#include <stdio.h>
#include <conio.h>
#include <assert.h>
/// Number of buffers circulating
const int NumImageBuffers = 5;
/// Number of images to acquire
const int NumGrabs = 250;
/// The absolute thread priority of the thread waiting at the completion port
const int GrabThreadPriority = 25;
/// The thread priority of the main thread doing some computatations
//const int MainThreadPriority = THREAD_PRIORITY_IDLE;
//const int MainThreadPriority = THREAD_PRIORITY_TIME_CRITICAL;
const int MainThreadPriority = THREAD_PRIORITY_NORMAL;
/// The priority class of the process
const int ProcessPriorityClass = NORMAL_PRIORITY_CLASS;
//const int ProcessPriorityClass = ABOVE_NORMAL_PRIORITY_CLASS;
//const int ProcessPriorityClass = HIGH_PRIORITY_CLASS;
/// Reduces the stress.
const int SleepTime = 0;
// const int SleepTime = 10;
/// Number of loops the stress function will perform until it eventually sleeps for a while
const int Loops = 10000000L;
/// Enables the search for missing images. Ensure that the walking stripes test image
/// is activated, see below
const bool CheckMissingImages = true;
// const bool CheckMissingImages = false;
/// The walking stripes test image. The value depends on the
/// camera model. Examples: A101fc: TestImage_3, A301fc: TestImage_2
const ImageOnMode Testimage = TestImage_2;
/// Sets the process' priority class
void SetPriorityClass(int PriorityClass)
{
HANDLE hProcess = ::GetCurrentProcess();
BOOL res = ::SetPriorityClass(hProcess, PriorityClass);
assert(res);
int NewPriorityClass = ::GetPriorityClass(hProcess);
assert(NewPriorityClass == PriorityClass);
}
/// Sets the current thread's priority
void SetCurrentThreadPriority(int Priority)
{
HANDLE hThread = ::GetCurrentThread();
BOOL res = ::SetThreadPriority(hThread, Priority);
assert(res);
int NewPriotrity = ::GetThreadPriority(hThread);
assert(NewPriotrity == Priority);
}
/// Evaluates statistics
class CStatistics
{
public:
/// Constructor
CStatistics()
{
Reset();
}
/// Add a sample
void AddSample(double Value)
{
if(m_NumSamples == 0)
{
m_Min = Value;
m_Max = Value;
}
else if(Value > m_Max)
{
m_Max = Value;
}
else if(Value < m_Min)
{
m_Min = Value;
}
m_Sum += Value;
++m_NumSamples;
}
/// Reset the statistics
void Reset()
{
m_NumSamples = 0;
m_Sum = 0.0;
m_Min = 0.0;
m_Max = 0.0;
}
/// Computes the mean
double GetMean()
{
assert(m_NumSamples > 0);
return m_Sum / m_NumSamples;
}
/// Gets the minimum
double GetMin()
{
assert(m_NumSamples > 0);
return m_Min;
}
/// Gets the maximum
double GetMax()
{
assert(m_NumSamples > 0);
return m_Max;
}
protected:
/// Number of samples
long m_NumSamples;
/// Sum of samples
double m_Sum;
/// minimum sample
double m_Min;
/// maximum sample
double m_Max;
};
/// Takes the time
class CStopWatch
{
public:
/// constructor, starts time measurement
CStopWatch()
{
Start();
}
/// Start the stop watch
void Start()
{
QueryPerformanceCounter(&m_StartTime);
}
/// Stop. The elapsed time is returned. The stop watch may be started again
double Stop(bool StartAgain)
{
QueryPerformanceCounter(&m_StopTime);
double theElapsedTime = ElapsedTime();
if(StartAgain)
m_StartTime = m_StopTime;
return theElapsedTime;
}
/// Return the elapsed time in seconds between start() and stop()
double ElapsedTime()
{
LARGE_INTEGER timerFrequency;
QueryPerformanceFrequency(&timerFrequency);
__int64 oldTicks = ((__int64)m_StartTime.HighPart << 32) + (__int64)m_StartTime.LowPart;
__int64 newTicks = ((__int64)m_StopTime.HighPart << 32) + (__int64)m_StopTime.LowPart;
long double timeDifference = (long double) (newTicks - oldTicks);
long double ticksPerSecond = (long double) (((__int64)timerFrequency.HighPart << 32)
+ (__int64)timerFrequency.LowPart);
return (double)(timeDifference / ticksPerSecond);
}
protected:
/// zero-point for time measurment
LARGE_INTEGER m_StartTime;
/// last time stamp
LARGE_INTEGER m_StopTime;
};
/// Encapsulates the acquisition thread waiting at the completion port and feeding in new buffers
class CGrabThread
{
public:
/// constructor
CGrabThread( CBcam* pBcam, BYTE **ppBuffers, unsigned long ImageBufferSize, HANDLE running, HANDLE finished) :
m_pBcam(pBcam),
m_ppBuffers(ppBuffers),
m_ImageBufferSize(ImageBufferSize),
m_Running(running),
m_Finished(finished)
{
}
/// Create the thread
void Create()
{
m_hThread = ::CreateThread(NULL, 0, ThreadMain, (LPVOID)this, 0, &m_ThreadId);
}
/// Wait until the thread terminates
DWORD WaitForDeath(DWORD Timeout)
{
return ::WaitForSingleObject(m_hThread, Timeout);
}
/// Return the thread handle
operator HANDLE() { return m_hThread; }
protected:
/// static thread function caller
static DWORD WINAPI ThreadMain(LPVOID lpData)
{
// call the run function in the obcet's context
CGrabThread *This = (CGrabThread*)lpData;
return This->Run();
}
/// thread function
DWORD Run()
{
int LastPixelValue = -1;
long BufferCounter = 0;
int exitcode = 0;
try
{
// set the thread's priority to the desired value
m_pBcam->SetCurrentThreadPriority(GrabThreadPriority);
printf("GrabThreadPriority= %d\n", GrabThreadPriority);
// start the camera
m_pBcam->ContinuousShot = true;
// signal that we are going to grab
SetEvent(m_Running);
m_StopWatch.Start();
while( BufferCounter < NumGrabs )
{
// Wait for something to arrive at the completion port
FunctionCode_t FunctionCode;
unsigned long ErrorCode;
void *pContext;
m_pBcam->WaitForCompletion(&FunctionCode, &ErrorCode, &pContext, 5000);
if ( ErrorCode != 0 )
{
printf("Error: %d\n", ErrorCode);
exitcode = 1;
break;
}
if ( FunctionCode == AsyncGrabImage )
{
// Take the time
double ElapsedTime = m_StopWatch.Stop(true);
m_Statistics.AddSample(ElapsedTime);
// Grab Counter
++BufferCounter;
// Index of the current buffer
int i = (int)pContext;
// Value of the fist pixel
BYTE CurrentPixelValue = *(m_ppBuffers[i]);
// check for missing images
if(CheckMissingImages && LastPixelValue != -1 )
{
int delta = (256 + CurrentPixelValue - LastPixelValue) % 256;
if ( delta != 1 )
{
printf("==> WARNING : missed %d images\n", delta - 1);
}
}
LastPixelValue = CurrentPixelValue;
// re-queue the buffer
m_pBcam->GrabImageAsync(m_ppBuffers[i], m_ImageBufferSize, (void*)i, false);
}
}
// Signal that we have finished
SetEvent(m_Finished);
// print the overall statistics
printf("================================================================================\n");
printf("Min =%6.2f ms (%+3.1f%%) Mean =%6.2f ms (%4.1f Hz) Max =%6.2f ms (%+3.1f%%)\n",
1000.0 * m_Statistics.GetMin(),
100.0 * ((m_Statistics.GetMin()/ m_Statistics.GetMean()) - 1),
1000.0 * m_Statistics.GetMean(),
1.0 / m_Statistics.GetMean(),
1000.0 * m_Statistics.GetMax(),
100.0 * ((m_Statistics.GetMax()/ m_Statistics.GetMean()) - 1)
);
return exitcode;
}
catch ( BcamException&e )
{
printf("Bcam Exception caught in grab thread: %s (%d)\n", e.Description(), e.Error() );
SetEvent(m_Finished);
return 1;
}
}
/// thread handle
HANDLE m_hThread;
/// thread ID
DWORD m_ThreadId;
/// The BCAM object
CBcam* m_pBcam;
/// The buffers
BYTE **m_ppBuffers;
/// Size of the imagebuffers
unsigned long m_ImageBufferSize;
/// For time measurement
CStopWatch m_StopWatch;
/// For time evaluation
CStatistics m_Statistics;
/// Synchronization objects
HANDLE m_Running, m_Finished;
};
/// Main entry point of the application
void main()
{
try
{
if ( CBcam::DeviceNames().size() == 0 )
{
printf("No camera devices found");
return;
}
CString DeviceName = *(CBcam::DeviceNames().begin());
// Create the driver object and open the driver
CBcam Bcam;
Bcam.Open(DeviceName);
// This yields a max. resolution Mono8/Bayer8 image
Bcam.SetVideoMode(DCS_Format7, DCS_Mode0);
// Make sure the camera will run at full speed
Bcam.FormatSeven[DCS_Mode0].Size = Bcam.FormatSeven[DCS_Mode0].MaxSize();
Bcam.FormatSeven[DCS_Mode0].BytePerPacket = Bcam.FormatSeven[DCS_Mode0].BytePerPacket.Max();
Bcam.Shutter.Raw = Bcam.Shutter.Raw.Min();
// Make the camera show walking stripes
Bcam.TestImage = Testimage;
// Create the image buffers
CSize ImageSize = Bcam.FormatSeven[DCS_Mode0].Size();
unsigned long ImageBufferSize = ImageSize.cx * ImageSize.cy;
PBYTE* ppBuffers = new PBYTE[NumImageBuffers];
for ( int i = 0; i < NumImageBuffers; ++i )
ppBuffers[i] = new BYTE[ImageBufferSize];
printf("NumImageBuffers = %d\n", NumImageBuffers);
printf("ImageSize : W = %d, H = %d\n",ImageSize.cx, ImageSize.cy);
// Allocate Resources (MaxBuffers, MaxBufferSize)
Bcam.AllocateResources(NumImageBuffers, ImageBufferSize);
// Enqueue the buffers for grabbing
for(i=0; i<NumImageBuffers; ++i)
{
Bcam.GrabImageAsync(ppBuffers[i], ImageBufferSize, (void*)i, false);
}
// Create some events for synchronization purposes
CEvent finished; // the thread will signal the event when it finishes the acquisition
finished.Create();
CEvent running; // the thread will signal the event when it enter its run method
// Create and start the thread
CGrabThread Thread(&Bcam, ppBuffers, ImageBufferSize, running, finished );
Thread.Create();
WaitForSingleObject(running, INFINITE); // give the thread a chance to enter its run method
// ... now the buffers are circulating via the thread function ...
// Set the priority of the current thread. The grab thread will set its priority himself
int p = GetThreadPriority(GetCurrentThread());
int c = GetPriorityClass(GetCurrentProcess());
SetPriorityClass(ProcessPriorityClass);
SetCurrentThreadPriority(MainThreadPriority);
// Because we are lifting the priority level of the grab thread up to the realtime priority class,
// we must ensure that we don't slow down the driver's queue server thread. Ensure that the queue server
// thread runs on a higher priority level than our thread
unsigned long QueueServerPriority = Bcam.GetQueueServerPriority();
if ( QueueServerPriority <= GrabThreadPriority )
{
QueueServerPriority = GrabThreadPriority + 1;
if ( QueueServerPriority > 31 )
QueueServerPriority = 31;
Bcam.SetQueueServerPriority(QueueServerPriority);
}
printf("QueueServerPriority= %d\n", QueueServerPriority);
printf("Check for missing images %s\n", CheckMissingImages ? "enabled" : "disabled");
printf("\nPlease stand by while grabbing %d images....\n", NumGrabs);
// As long the thread is grabbing, make some CPU stress
while ( WaitForSingleObject(finished, 0) != WAIT_OBJECT_0 )
{
// make Stress
for(long i=0; i<Loops; ++i)
{
long j = i*i;
}
// reduce stress
if ( SleepTime > 0 )
::Sleep(SleepTime);
}
Thread.WaitForDeath(INFINITE);
// clean up
Bcam.ContinuousShot=false;
Bcam.Close();
for ( i = 0; i < NumImageBuffers; ++i )
delete[] ppBuffers[i];
delete[] ppBuffers;
} catch( BcamException &e )
{
printf( "Exception occurred 0x%X:\n", e.Error() );
printf( "Message: %s\n", (LPCSTR) e.Description() );
printf( "Context: %s\n", (LPCSTR) e.Context() );
}
printf("Press a key exit\n");
_getch();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -