⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 realtimedemo.cpp

📁 BCAM 1394 Driver
💻 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 + -