Click here to Skip to main content
15,885,278 members
Articles / Desktop Programming / Win32

Optimized Image Inversion Using SSE2

Rate me:
Please Sign up or sign in to vote.
4.11/5 (10 votes)
2 May 2009CPOL6 min read 46.1K   971   20  
Fast image inversion forms a good basis for optimizing pixel wise operations. We will discuss the ways to achieve the best speed on this inversion operator.
/*

  This class is simple to use. Just declare a variable(s) as type CPerfTimer,
  call Start() to start timimg and call Stop() to stop timimg. You can pause a
  timer by calling Stop() and then you can call Start() to resume. Retrieve the
  elapsed time by calling an Elapsed..() function. Assignment, addition, 
  subtraction and comparison are supported. There are a few information calls
  available also. All calls except Start and Stop can be performed on a timer
  without stopping it.
  
*/

#ifndef __PERFTIMER_H__
#define __PERFTIMER_H__

#include <windows.h>

class CPerfTimer
{
public:
  CPerfTimer(BOOL bStart = FALSE) {Init(bStart);}

  CPerfTimer(const CPerfTimer& Src); 

  virtual ~CPerfTimer() {;}

  void Start(BOOL bReset = FALSE);   // Start from current value or optionally from 0
  void Stop();                       // Stop timing. Use Start afterwards to continue.
 
  BOOL IsRunning();                  // Returns FALSE if stopped.
  
  BOOL IsSupported();                // Returns FALSE if performance counter not supported.
                                     // Call after constructing at least one CPerfTimer

  const double Resolution();         // Returns timer resolution in seconds
  const double Resolutionms();       // Returns timer resolution in milliseconds
  const double Resolutionus();       // Returns timer resolution in microseconds
  
  const double Elapsed();            // Returns elapsed time in seconds
  const double Elapsedms();          // Returns elapsed time in milliseconds 
  const double Elapsedus();          // Returns elapsed time in microseconds

  const CPerfTimer& operator=(const CPerfTimer& Src); // Assignment operator 

  // Math operators
  CPerfTimer operator+(const CPerfTimer& Src) const;
	CPerfTimer operator-(const CPerfTimer& Src) const;
	const CPerfTimer& operator+=(const CPerfTimer& Src);
	const CPerfTimer& operator-=(const CPerfTimer& Src);
  // For time in seconds
  CPerfTimer operator+(const double Secs) const;
	CPerfTimer operator-(const double Secs) const;
	const CPerfTimer& operator+=(const double Secs);
	const CPerfTimer& operator-=(const double Secs);

  // Boolean comparison operators
	BOOL operator<(const CPerfTimer& Src);
	BOOL operator>(const CPerfTimer& Src);
	BOOL operator<=(const CPerfTimer& Src);
	BOOL operator>=(const CPerfTimer& Src);
  // For time in seconds
  BOOL operator<(const double Secs);
	BOOL operator>(const double Secs);
	BOOL operator<=(const double Secs);
	BOOL operator>=(const double Secs);

  virtual void Lock() const {;}     // Override for thread safe operation
  virtual void Unlock() const {;}     // Override for thread safe operation
protected:
  void Init(BOOL bStart);
  void Copy(const CPerfTimer& Src);

private:
  __int64 m_Start;
  static __int64 m_Freq;   // does not change while system is running
  static __int64 m_Adjust; // Adjustment time it takes to Start and Stop
};

class CPerfTimerT : public CPerfTimer
{ // You only need to use types of this class if a timer is going to be shared between threads
public:
  CPerfTimerT(BOOL bStart = FALSE)
  {
    m_hMutex = CreateMutex(NULL,FALSE,(LPCWSTR)"");
    Init(bStart);
  }

  CPerfTimerT(const CPerfTimerT& Src) 
  { 
    m_hMutex = CreateMutex(NULL,FALSE,(LPCWSTR)"");
    Copy(Src); 
  }

  CPerfTimerT(const CPerfTimer& Src) 
  { 
    m_hMutex = CreateMutex(NULL,FALSE,(LPCWSTR)"");
    Copy(Src); 
  }

  virtual ~CPerfTimerT() 
  { CloseHandle(m_hMutex); }

  const CPerfTimerT& operator=(const CPerfTimerT& Src) // Assignment operator 
  {
    Copy(Src);
    return *this; 
  }
 
  virtual void Lock() const { WaitForSingleObject(m_hMutex,10000); }   
  virtual void Unlock() const { ReleaseMutex(m_hMutex); }   
private:
  HANDLE m_hMutex;
};

inline void CPerfTimer::Init(BOOL bStart)
{
  if (!m_Freq) 
  { // Initialization should only run once
    QueryPerformanceFrequency((LARGE_INTEGER *)&m_Freq); 
    if (!m_Freq)
      m_Freq = 1; // Timer will be useless but will not cause divide by zero
    m_Start = 0; 
    m_Adjust = 0; 
    Start();            // Time a Stop
    Stop(); 
    m_Adjust = m_Start;
  }
  // This is the only part that normally runs
  m_Start = 0; 
  if (bStart)
    Start(); 
}

inline CPerfTimer::CPerfTimer(const CPerfTimer& Src)  
{
  Copy(Src);
}

inline void CPerfTimer::Copy(const CPerfTimer& Src)
{
  if (&Src == this) 
    return; // avoid deadlock if someone tries to copy it to itself
  Src.Lock();
  Lock();
  m_Start = Src.m_Start; 
  Unlock();
  Src.Unlock();
}

inline void CPerfTimer::Start(BOOL bReset) 
{ // Start from current value or optionally from 0
  __int64 i;
  QueryPerformanceCounter((LARGE_INTEGER *)&i);
  Lock();
  if ((!bReset) && (m_Start < 0))
    m_Start += i;   // We are starting with an accumulated time
  else 
    m_Start = i;    // Starting from 0
  Unlock();
} 

inline void CPerfTimer::Stop() 
{ // Stop timing. Use Start afterwards to continue
  Lock();
  if (m_Start <= 0)
  {
    Unlock();
    return;          // Was not running
  }
  __int64 i;
  QueryPerformanceCounter((LARGE_INTEGER *)&i); 
  m_Start += -i;          // Stopped timer keeps elapsed timer ticks as a negative 
  if (m_Start < m_Adjust) // Do not overflow
    m_Start -= m_Adjust;  // Adjust for time timer code takes to run
  else 
    m_Start = 0;          // Stop must have been called directly after Start
  Unlock();
} 

inline BOOL CPerfTimer::IsRunning() 
{ // Returns FALSE if stopped.
  Lock();
  BOOL bRet = (m_Start > 0); // When < 0, holds elpased clicks
  Unlock();
  return bRet;   
}
 inline const double CPerfTimer::Elapsed()
{ // Returns elapsed time in seconds
  CPerfTimer Result(*this);
  Result.Stop();
  return (double)(-Result.m_Start)/(double)m_Freq; 
}

inline const double CPerfTimer::Elapsedms() 
{ // Returns elapsed time in milliseconds
  CPerfTimer Result(*this);
  Result.Stop();
  return (-Result.m_Start*1000.0)/(double)m_Freq; 
}

inline const double CPerfTimer::Elapsedus() 
{ // Returns elapsed time in microseconds
  CPerfTimer Result(*this);
  Result.Stop();
  return (-Result.m_Start * 1000000.0)/(double)m_Freq; 
}


// Assignment operator
inline const CPerfTimer& CPerfTimer::operator=(const CPerfTimer& Src) 
{
  Copy(Src);
  return *this; 
}


// Math operators
inline CPerfTimer CPerfTimer::operator+(const CPerfTimer& Src) const
{
  CPerfTimer Result(*this);
  Result += Src; 
  return Result; 
}

inline CPerfTimer CPerfTimer::operator-(const CPerfTimer& Src) const
{
  CPerfTimer Result(*this);
  Result -= Src; 
  return Result; 
}

inline const CPerfTimer& CPerfTimer::operator+=(const CPerfTimer& Src)
{
  CPerfTimer SrcStop(Src);  // Temp is necessary in case Src is not stopped
  SrcStop.Stop();
  Lock();
  m_Start += SrcStop.m_Start;
  Unlock();
  return *this; 
}

inline const CPerfTimer& CPerfTimer::operator-=(const CPerfTimer& Src)
{
  CPerfTimer SrcStop(Src);  // Temp is necessary in case Src is not stopped
  SrcStop.Stop();
  Lock();
  m_Start -= SrcStop.m_Start; 
  Unlock();
  return *this; 
}

// For time in seconds
inline CPerfTimer CPerfTimer::operator+(const double Secs) const
{
  CPerfTimer Result(*this);
  Result += Secs; 
  return Result; 
}

inline CPerfTimer CPerfTimer::operator-(const double Secs) const
{
  CPerfTimer Result(*this);
  Result += Secs; 
  return Result; 
}

inline const CPerfTimer& CPerfTimer::operator+=(const double Secs)
{
  Lock();
  m_Start -= (__int64)(Secs*(double)m_Freq);
  Unlock();
  return *this; 
}

inline const CPerfTimer& CPerfTimer::operator-=(const double Secs)
{
  Lock();
  m_Start += (__int64)(Secs*(double)m_Freq);
  Unlock();
  return *this; 
}



// Boolean comparison operators
inline BOOL CPerfTimer::operator<(const CPerfTimer& Src)
{ 
  BOOL bRet; 
  CPerfTimer Temp(Src);
  Lock();
  if (m_Start <= 0)
  {
    Temp.Stop();
    bRet = (m_Start > Temp.m_Start); 
    Unlock();
    return bRet;
  }
  else
  if (Temp.m_Start > 0)
  {
    bRet = (m_Start < Temp.m_Start); 
    Unlock();
    return bRet;
  }
  else
  {
    Unlock();
    CPerfTimer ThisStop(*this);
    ThisStop.Stop();
    return (ThisStop.m_Start > Temp.m_Start); 
  }
}

inline BOOL CPerfTimer::operator>(const CPerfTimer& Src)
{ 
  BOOL bRet; 
  CPerfTimer Temp(Src);
  Lock();
  if (m_Start <= 0)
  {
    Temp.Stop();
    bRet = (m_Start < Temp.m_Start); 
    Unlock();
    return bRet;
  }
  else
  if (Temp.m_Start > 0)
  {
    bRet = (m_Start > Temp.m_Start); 
    Unlock();
    return bRet;
  }
  else
  {
    Unlock();
    CPerfTimer ThisStop(*this);
    ThisStop.Stop();
    return (ThisStop.m_Start < Temp.m_Start); 
  }
}

inline BOOL CPerfTimer::operator<=(const CPerfTimer& Src)
{ 
  return !(*this > Src);
}

inline BOOL CPerfTimer::operator>=(const CPerfTimer& Src)
{ 
  return !(*this < Src);
}

// For time in seconds
inline BOOL CPerfTimer::operator<(const double Secs)
{ 
  BOOL bRet; 
  Lock();
  if (m_Start <= 0)
  {
    bRet = (m_Start > (__int64)(-Secs*(double)m_Freq)); 
    Unlock();
    return bRet;
  }
  else
  {
    Unlock();
    CPerfTimer ThisStop(*this);
    ThisStop.Stop();
    return (ThisStop.m_Start > (__int64)(-Secs*(double)m_Freq)); 
  }
}

inline BOOL CPerfTimer::operator>(const double Secs)
{ 
  BOOL bRet; 
  Lock();
  if (m_Start <= 0)
  {
    bRet = (m_Start < (__int64)(-Secs*(double)m_Freq)); 
    Unlock();
    return bRet;
  }
  else
  {
    Unlock();
    CPerfTimer ThisStop(*this);
    ThisStop.Stop();
    return (ThisStop.m_Start < (__int64)(-Secs*(double)m_Freq)); 
  }
}

inline BOOL CPerfTimer::operator<=(const double Secs)
{ 
  return !(*this > Secs);
}

inline BOOL CPerfTimer::operator>=(const double Secs)
{ 
  return !(*this < Secs);
}


#endif //__PERFTIMER_H__

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO Gravi Information Technologies and Consultancy Ltd
Turkey Turkey
Currently, also an MSc. student in Technical University of Munich, I develop practical application in computer vision for more than 5 years. I design real-time solutions to industrial and practical vision problems, both 3D and 2D. Very interested in developing algorithms in C relating math and vision.

Please visit Gravi's web page (http://www.gravi.com.tr) and my page (http://www.tbirdal.me) to learn more about what we develop.

I admire performance in algorithms.

"Great minds never die, they just tend to infinity..."

Comments and Discussions