#include <algorithm>
#include "HistogramCanvas.h"
#include <limits>
#include <math.h>

using namespace mvIMPACT::acquire;

//=============================================================================
//================= Implementation HistogramCanvas ============================
//=============================================================================
BEGIN_EVENT_TABLE(HistogramCanvas, ImageAnalysisPlotCanvas)
  EVT_PAINT(HistogramCanvas::OnPaint)
END_EVENT_TABLE()

//-----------------------------------------------------------------------------
HistogramCanvas::HistogramCanvas( wxWindow* parent, const wxString& configName, wxWindowID id /* = -1 */, const wxPoint& pos /* = wxDefaultPosition */,
	const wxSize& size /* = wxDefaultSize */, long style /* = wxSUNKEN_BORDER */, const wxString& name /* = wxT("Histogram") */, bool boActive /* = false */, bool boHandleStandardDeviation /* = false */ ) :
	ImageAnalysisPlotCanvas(parent, configName, id, pos, size, style, name, boActive, 1),
	m_DrawStepWidth(0), m_ppHistogramBuffer(0), m_pHistogramMax(0), m_pHistogramAverage(0), m_pStandardDeviation(0),
	m_boHandleStandardDeviation(boHandleStandardDeviation), m_CurrentMax(1, 1)
//-----------------------------------------------------------------------------
{
	m_plotFeatures.insert( pfPercentageWindow );
	m_plotFeatures.insert( pfProcessBayerParity );
	m_plotFeatures.insert( pfStepWidth );
	SetGridValueFormatString( wxT("%d") );
}

//-----------------------------------------------------------------------------
HistogramCanvas::~HistogramCanvas()
//-----------------------------------------------------------------------------
{
	DeallocateHistogramBuffer();
}

//-----------------------------------------------------------------------------
void HistogramCanvas::CalculateMaxValue( void )
//-----------------------------------------------------------------------------
{
	// evaluate new max value
	m_CurrentMax = PlotPoint(m_ppHistogramBuffer[0][0], 0);
	for( int j=0; j<m_ChannelCount; j++ )
	{
		m_pHistogramMax[j] = PlotPoint(m_ppHistogramBuffer[j][0], 0);
		for( unsigned int i=1; i<m_valCount; i++ )
		{
			if( m_ppHistogramBuffer[j][i] > m_pHistogramMax[j].cnt_ )
			{
				m_pHistogramMax[j] = PlotPoint(m_ppHistogramBuffer[j][i], i);
			}
		}
		const double PIX_CNT = static_cast<double>(m_AOIw * m_AOIh) / ( ( m_bayerParity == bmpUndefined ) ? 1. : 4. );
		m_pHistogramAverage[j] = m_pHistogramAverage[j] / PIX_CNT;
		if( m_pHistogramMax[j].cnt_ == 0 )
		{
			m_pHistogramMax[j].cnt_ = 1;
		}
		if( m_CurrentMax.cnt_ < m_pHistogramMax[j].cnt_ )
		{
			m_CurrentMax = m_pHistogramMax[j];
		}
		if( m_boHandleStandardDeviation )
		{
			double sumOfSquares = 0;
			for( unsigned int i=0; i<m_valCount; i++ )
			{
				if( m_ppHistogramBuffer[j][i] > 0 )
				{
					sumOfSquares += pow(static_cast<double>(i), 2) * m_ppHistogramBuffer[j][i];
				}
			}
			m_pStandardDeviation[j] = sqrt( sumOfSquares / PIX_CNT );
		}
	}
}

//-----------------------------------------------------------------------------
void HistogramCanvas::CalculateNoiseHistogram( const RequestData& data )
//-----------------------------------------------------------------------------
{
	const ImageBuffer* pIB = data.image_.getBuffer();
	switch( pIB->pixelFormat )
	{
	case ibpfMono8:
		{
			unsigned char* pData = 0;
			unsigned char difference = 0;
			if( m_bayerParity == bmpUndefined )
			{
				for( int line=0; line<m_AOIh; line++ )
				{
					pData = static_cast<unsigned char*>(pIB->vpData) + ( ( m_AOIy + line ) * pIB->pChannels[0].iLinePitch ) + ( m_AOIx * pIB->iBytesPerPixel );
					for( int pixel=0; pixel<m_AOIw; pixel++ )
					{
						if( pixel < m_AOIw - 1 )
						{
							difference = abs( *pData - *(pData+1) );
							m_pHistogramAverage[pChannel0Hor] += difference;
							++m_ppHistogramBuffer[pChannel0Hor][difference];
						}
						if( line < m_AOIh - 1 )
						{
							difference = abs( *pData - *(pData+pIB->pChannels[0].iLinePitch) );
							m_pHistogramAverage[pChannel0Ver] += difference;
							++m_ppHistogramBuffer[pChannel0Ver][difference];
						}
						++pData;
					}
				}
			}
			else
			{
				for( int line=0; line<m_AOIh; line++ )
				{
					pData = static_cast<unsigned char*>(pIB->vpData) + ( ( m_AOIy + line ) * pIB->pChannels[0].iLinePitch ) + ( m_AOIx * pIB->iBytesPerPixel );
					for( int pixel=0; pixel<m_AOIw; pixel++ )
					{
						int index = ( ( ( line + m_AOIy ) & 1 ) ? ( ( ( pixel + m_AOIx ) & 1 ) ? pOddOdd : pOddEven ) : ( ( ( pixel + m_AOIx ) & 1 ) ? pEvenOdd : pEvenEven ) );
						if( pixel < m_AOIw - 2 )
						{
							difference = abs( *pData - *(pData+2) );
							m_pHistogramAverage[2*index] += difference;
							++m_ppHistogramBuffer[2*index][difference];
						}
						if( line < m_AOIh - 2 )
						{
							difference = abs( *pData - *(pData+2*pIB->pChannels[0].iLinePitch) );
							m_pHistogramAverage[2*index+1] += difference;
							++m_ppHistogramBuffer[2*index+1][difference];
						}
						++pData;
					}
				}
			}
		}
		break;
	case ibpfMono10:
	case ibpfMono12:
	case ibpfMono14:
	case ibpfMono16:
		{
			unsigned short* pData = 0;
			unsigned short difference = 0;
			if( m_bayerParity == bmpUndefined )
			{
				for( int line=0; line<m_AOIh; line++ )
				{
					pData = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(pIB->vpData) + ( ( m_AOIy + line ) * pIB->pChannels[0].iLinePitch ) + ( m_AOIx * pIB->iBytesPerPixel ));
					for( int pixel=0; pixel<m_AOIw; pixel++ )
					{
						unsigned short current_pixel = saveAssign( *pData, static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) );
						if( pixel < m_AOIw - 1 )
						{
							unsigned short next_pixel_right = saveAssign( *(pData+1), static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) );
							difference = abs( current_pixel - next_pixel_right );
							m_pHistogramAverage[pChannel0Hor] += difference;
							++m_ppHistogramBuffer[pChannel0Hor][difference];
						}
						if( line < m_AOIh - 1 )
						{
							unsigned short next_pixel_down = saveAssign( *reinterpret_cast<unsigned short*>(reinterpret_cast<unsigned char*>(pData)+pIB->pChannels[0].iLinePitch), static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) );
							difference = abs( current_pixel - next_pixel_down );
							m_pHistogramAverage[pChannel0Ver] += difference;
							++m_ppHistogramBuffer[pChannel0Ver][difference];
						}
						++pData;
					}
				}
			}
			else
			{
				for( int line=0; line<m_AOIh; line++ )
				{
					pData = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(pIB->vpData) + ( ( m_AOIy + line ) * pIB->pChannels[0].iLinePitch ) + ( m_AOIx * pIB->iBytesPerPixel ));
					for( int pixel=0; pixel<m_AOIw; pixel++ )
					{
						unsigned short current_pixel = saveAssign( *pData, static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) );
						int index = ( ( ( line + m_AOIy ) & 1 ) ? ( ( ( pixel + m_AOIx ) & 1 ) ? pOddOdd : pOddEven ) : ( ( ( pixel + m_AOIx ) & 1 ) ? pEvenOdd : pEvenEven ) );
						if( pixel < m_AOIw - 2 )
						{
							unsigned short next_pixel_right = saveAssign( *(pData+2), static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) );
							difference = abs( current_pixel - next_pixel_right );
							m_pHistogramAverage[2*index] += difference;
							++m_ppHistogramBuffer[2*index][difference];
						}
						if( line < m_AOIh - 2 )
						{
							unsigned short next_pixel_down = saveAssign( *reinterpret_cast<unsigned short*>(reinterpret_cast<unsigned char*>(pData)+2*pIB->pChannels[0].iLinePitch), static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) );
							difference = abs( current_pixel - next_pixel_down );
							m_pHistogramAverage[2*index+1] += difference;
							++m_ppHistogramBuffer[2*index+1][difference];
						}
						++pData;
					}
				}
			}
		}
		break;
	case ibpfMono12Packed_V2:
		{
			unsigned short difference = 0;
			unsigned char* pData = static_cast<unsigned char*>(pIB->vpData);
			if( m_bayerParity == bmpUndefined )
			{
				for( int line=0; line<m_AOIh; line++ )
				{
					const int pixOffset = ( m_AOIy + line ) * pIB->iWidth;
					for( int pixel=0; pixel<m_AOIw; pixel++ )
					{
						unsigned short current_pixel = GetMonoPacked_V2Pixel( pData, pixOffset + m_AOIx + pixel, 4 );
						if( pixel < m_AOIw - 1 )
						{
							unsigned short next_pixel_right = GetMonoPacked_V2Pixel( pData, pixOffset + m_AOIx + pixel + 1, 4 );
							difference = abs( current_pixel - next_pixel_right );
							m_pHistogramAverage[pChannel0Hor] += difference;
							++m_ppHistogramBuffer[pChannel0Hor][difference];
						}
						if( line < m_AOIh - 1 )
						{
							unsigned short next_pixel_down = GetMonoPacked_V2Pixel( pData, pixOffset + pIB->iWidth + m_AOIx + pixel, 4 );
							difference = abs( current_pixel - next_pixel_down );
							m_pHistogramAverage[pChannel0Ver] += difference;
							++m_ppHistogramBuffer[pChannel0Ver][difference];
						}
					}
				}
			}
			else
			{
				for( int line=0; line<m_AOIh; line++ )
				{
					unsigned char* pData = static_cast<unsigned char*>(pIB->vpData);
					for( int pixel=0; pixel<m_AOIw; pixel++ )
					{
						const int pixOffset = ( m_AOIy + line ) * pIB->iWidth;
						unsigned short current_pixel = GetMonoPacked_V2Pixel( pData, pixOffset + m_AOIx + pixel, 4 );
						int index = ( ( ( line + m_AOIy ) & 1 ) ? ( ( ( pixel + m_AOIx ) & 1 ) ? pOddOdd : pOddEven ) : ( ( ( pixel + m_AOIx ) & 1 ) ? pEvenOdd : pEvenEven ) );
						if( pixel < m_AOIw - 2 )
						{
							unsigned short next_pixel_right = GetMonoPacked_V2Pixel( pData, pixOffset + m_AOIx + pixel + 2, 4 );
							difference = abs( current_pixel - next_pixel_right );
							m_pHistogramAverage[2*index] += difference;
							++m_ppHistogramBuffer[2*index][difference];
						}
						if( line < m_AOIh - 2 )
						{
							unsigned short next_pixel_down = GetMonoPacked_V2Pixel( pData, pixOffset + 2*pIB->iWidth + m_AOIx + pixel, 4 );
							difference = abs( current_pixel - next_pixel_down );
							m_pHistogramAverage[2*index+1] += difference;
							++m_ppHistogramBuffer[2*index+1][difference];
						}
					}
				}
			}
		}
		break;
	case ibpfBGR888Packed:
	case ibpfYUV444_UYVPacked:
		{
			int order[3] = { 2, 1, 0 };
			CalculateNoiseHistogram_8u_C3Packed( pIB, order );
		}
		break;
	case ibpfRGBx888Packed:
	case ibpfRGB888Packed:
	case ibpfYUV444Packed:
		{
			int order[3] = { 0, 1, 2 };
			CalculateNoiseHistogram_8u_C3Packed( pIB, order );
		}
		break;
	case ibpfBGR101010Packed_V2:
		{
			unsigned short red0, green0, blue0;
			unsigned short red1, green1, blue1;
			unsigned short difference = 0;
			for( int line=0; line<m_AOIh; line++ )
			{
				unsigned int* pPixel =  reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(pIB->vpData) + ( ( m_AOIy + line ) * pIB->pChannels[0].iLinePitch )) + m_AOIx;
				for( int pixel=0; pixel<m_AOIw; pixel++ )
				{
					GetBGR101010Packed_V2Pixel( *pPixel, red0, green0, blue0 );
					if( pixel < m_AOIw - 1 )
					{
						GetBGR101010Packed_V2Pixel( *(pPixel + 1), red1, green1, blue1 );
						difference = abs( red0 - red1 );
						m_pHistogramAverage[pChannel0Hor] += difference;
						++m_ppHistogramBuffer[pChannel0Hor][difference];
						difference = abs( green0 - green1 );
						m_pHistogramAverage[pChannel1Hor] += difference;
						++m_ppHistogramBuffer[pChannel1Hor][difference];
						difference = abs( blue0 - blue1 );
						m_pHistogramAverage[pChannel2Hor] += difference;
						++m_ppHistogramBuffer[pChannel2Hor][difference];
					}
					if( line < m_AOIh - 1 )
					{
						GetBGR101010Packed_V2Pixel( *reinterpret_cast<unsigned int*>(reinterpret_cast<unsigned char*>(pPixel) + pIB->pChannels[0].iLinePitch), red1, green1, blue1 );
						difference = abs( red0 - red1 );
						m_pHistogramAverage[pChannel0Ver] += difference;
						++m_ppHistogramBuffer[pChannel0Ver][difference];
						difference = abs( green0 - green1 );
						m_pHistogramAverage[pChannel1Ver] += difference;
						++m_ppHistogramBuffer[pChannel1Ver][difference];
						difference = abs( blue0 - blue1 );
						m_pHistogramAverage[pChannel2Ver] += difference;
						++m_ppHistogramBuffer[pChannel2Ver][difference];
					}
					++pPixel;
				}
			}
		}
		break;
	case ibpfRGB101010Packed:
	case ibpfRGB121212Packed:
	case ibpfRGB141414Packed:
	case ibpfRGB161616Packed:
	case ibpfYUV444_UYV_10Packed:
	case ibpfYUV444_10Packed:
		{
			unsigned short* pData = 0;
			unsigned short difference = 0;
			for( int line=0; line<m_AOIh; line++ )
			{
				pData = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(pIB->vpData) + ( ( m_AOIy + line ) * pIB->pChannels[0].iLinePitch ) + ( m_AOIx * pIB->iBytesPerPixel ));
				for( int pixel=0; pixel<m_AOIw; pixel++ )
				{
					
					if( pixel < m_AOIw - 1 )
					{
						difference = abs( saveAssign( pData[0], static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) ) - saveAssign( pData[0 + pIB->iBytesPerPixel], static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) ) );
						m_pHistogramAverage[pChannel0Hor] += difference;
						++m_ppHistogramBuffer[pChannel0Hor][difference];
						difference = abs( saveAssign( pData[1], static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) ) - saveAssign( pData[1 + pIB->iBytesPerPixel], static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) ) );
						m_pHistogramAverage[pChannel1Hor] += difference;
						++m_ppHistogramBuffer[pChannel1Hor][difference];
						difference = abs( saveAssign( pData[2], static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) ) - saveAssign( pData[2 + pIB->iBytesPerPixel], static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) ) );
						m_pHistogramAverage[pChannel2Hor] += difference;
						++m_ppHistogramBuffer[pChannel2Hor][difference];
					}
					if( line < m_AOIh - 1 )
					{
						difference = abs( saveAssign( pData[0], static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) ) - saveAssign( pData[0 + pIB->pChannels[0].iLinePitch], static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) ) );
						m_pHistogramAverage[pChannel0Ver] += difference;
						++m_ppHistogramBuffer[pChannel0Ver][difference];
						difference = abs( saveAssign( pData[1], static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) ) - saveAssign( pData[1 + pIB->pChannels[0].iLinePitch], static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) ) );
						m_pHistogramAverage[pChannel1Ver] += difference;
						++m_ppHistogramBuffer[pChannel1Ver][difference];
						difference = abs( saveAssign( pData[2], static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) ) - saveAssign( pData[2 + pIB->pChannels[0].iLinePitch], static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) ) );
						m_pHistogramAverage[pChannel2Ver] += difference;
						++m_ppHistogramBuffer[pChannel2Ver][difference];
					}
					pData += pIB->iChannelCount;
				}
			}
		}
		break;
	case ibpfRGBx888Planar:
		{
			unsigned char* pr = 0;
			unsigned char* pg = 0;
			unsigned char* pb = 0;
			unsigned char difference = 0;
			for( int line=0; line<m_AOIh; line++ )
			{
				pr = static_cast<unsigned char*>(pIB->vpData) + pIB->pChannels[0].iChannelOffset + ( ( m_AOIy + line ) * pIB->pChannels[0].iLinePitch ) + m_AOIx;
				pg = static_cast<unsigned char*>(pIB->vpData) + pIB->pChannels[1].iChannelOffset + ( ( m_AOIy + line ) * pIB->pChannels[1].iLinePitch ) + m_AOIx;
				pb = static_cast<unsigned char*>(pIB->vpData) + pIB->pChannels[2].iChannelOffset + ( ( m_AOIy + line ) * pIB->pChannels[2].iLinePitch ) + m_AOIx;
				for( int pixel=0; pixel<m_AOIw; pixel++ )
				{
					if( pixel < m_AOIw - 1 )
					{
						difference = abs( pr[0] - pr[1] );
						m_pHistogramAverage[pChannel0Hor] += difference;
						++m_ppHistogramBuffer[pChannel0Hor][difference];
						difference = abs( pg[0] - pg[1] );
						m_pHistogramAverage[pChannel1Hor] += difference;
						++m_ppHistogramBuffer[pChannel1Hor][difference];
						difference = abs( pb[0] - pb[1] );
						m_pHistogramAverage[pChannel2Hor] += difference;
						++m_ppHistogramBuffer[pChannel2Hor][difference];
					}
					if( line < m_AOIh - 1 )
					{
						difference = abs( pr[0] - pr[pIB->pChannels[0].iLinePitch] );
						m_pHistogramAverage[pChannel0Ver] += difference;
						++m_ppHistogramBuffer[pChannel0Ver][difference];
						difference = abs( pg[0] - pg[pIB->pChannels[1].iLinePitch] );
						m_pHistogramAverage[pChannel1Ver] += difference;
						++m_ppHistogramBuffer[pChannel1Ver][difference];
						difference = abs( pb[0] - pb[pIB->pChannels[2].iLinePitch] );
						m_pHistogramAverage[pChannel2Ver] += difference;
						++m_ppHistogramBuffer[pChannel2Ver][difference];
					}
					++pr;
					++pg;
					++pb;
				}
			}
		}
		break;
	case ibpfYUV422Packed:
		CalculateNoiseHistogramYUV<unsigned char>( pIB );
		break;
	case ibpfYUV422_10Packed:
		CalculateNoiseHistogramYUV<unsigned short>( pIB );
		break;
	case ibpfYUV422_UYVYPacked:
		CalculateNoiseHistogramUYV<unsigned char>( pIB );
		break;
	case ibpfYUV422_UYVY_10Packed:
		CalculateNoiseHistogramUYV<unsigned short>( pIB );
		break;
	case ibpfYUV422Planar:
		for( int line=0; line<m_AOIh; line++ )
		{
			unsigned char* py = static_cast<unsigned char*>(pIB->vpData) + pIB->pChannels[pY].iChannelOffset + ( ( m_AOIy + line ) * pIB->pChannels[pY].iLinePitch ) + m_AOIx;
			unsigned char* pu = static_cast<unsigned char*>(pIB->vpData) + pIB->pChannels[pU].iChannelOffset + ( ( m_AOIy + line ) * pIB->pChannels[pU].iLinePitch ) + m_AOIx;
			unsigned char* pv = static_cast<unsigned char*>(pIB->vpData) + pIB->pChannels[pV].iChannelOffset + ( ( m_AOIy + line ) * pIB->pChannels[pV].iLinePitch ) + m_AOIx;
			unsigned char difference = 0;
			for( int pixel=0; pixel<m_AOIw; pixel++ )
			{
				if( pixel < m_AOIw - 1 )
				{
					difference = abs( py[0] - py[1] );
					m_pHistogramAverage[pChannel0Hor] += difference;
					++m_ppHistogramBuffer[pChannel0Hor][difference];
					difference = abs( pu[0] - pu[1] );
					m_pHistogramAverage[pChannel1Hor] += difference;
					++m_ppHistogramBuffer[pChannel1Hor][difference];
					difference = abs( pv[0] - pv[1] );
					m_pHistogramAverage[pChannel2Hor] += difference;
					++m_ppHistogramBuffer[pChannel2Hor][difference];
				}
				if( line < m_AOIh - 1 )
				{
					difference = abs( py[0] - py[pIB->pChannels[0].iLinePitch] );
					m_pHistogramAverage[pChannel0Ver] += difference;
					++m_ppHistogramBuffer[pChannel0Ver][difference];
					difference = abs( pu[0] - pu[pIB->pChannels[1].iLinePitch] );
					m_pHistogramAverage[pChannel1Ver] += difference;
					++m_ppHistogramBuffer[pChannel1Ver][difference];
					difference = abs( pv[0] - pv[pIB->pChannels[2].iLinePitch] );
					m_pHistogramAverage[pChannel2Ver] += difference;
					++m_ppHistogramBuffer[pChannel2Ver][difference];
				}
				++py;
				if( pixel & 1 )
				{
					++pu;
					++pv;
				}
			}
		}
		break;
	default:
		// unsupported colour mode
		m_ChannelCount = 0;
		m_boUnsupportedPixelFormat = true;
		break;
	}
}

//-----------------------------------------------------------------------------
void HistogramCanvas::CalculateNoiseHistogram_8u_C3Packed( const ImageBuffer* pIB, int order[3] )
//-----------------------------------------------------------------------------
{
	unsigned char* pData = 0;
	unsigned char difference = 0;
	for( int line=0; line<m_AOIh; line++ )
	{
		pData = static_cast<unsigned char*>(pIB->vpData) + ( ( m_AOIy + line ) * pIB->pChannels[0].iLinePitch ) + ( m_AOIx * pIB->iBytesPerPixel );
		for( int pixel=0; pixel<m_AOIw; pixel++ )
		{
			if( pixel < m_AOIw - 1 )
			{
				difference = abs( pData[order[0]] - pData[order[0] + pIB->iBytesPerPixel] );
				m_pHistogramAverage[pChannel0Hor] += difference;
				++m_ppHistogramBuffer[pChannel0Hor][difference];
				difference = abs( pData[order[1]] - pData[order[1] + pIB->iBytesPerPixel] );
				m_pHistogramAverage[pChannel1Hor] += difference;
				++m_ppHistogramBuffer[pChannel1Hor][difference];
				difference = abs( pData[order[2]] - pData[order[2] + pIB->iBytesPerPixel] );
				m_pHistogramAverage[pChannel2Hor] += difference;
				++m_ppHistogramBuffer[pChannel2Hor][difference];
			}
			if( line < m_AOIh - 1 )
			{
				difference = abs( pData[order[0]] - pData[order[0] + pIB->pChannels[0].iLinePitch] );
				m_pHistogramAverage[pChannel0Ver] += difference;
				++m_ppHistogramBuffer[pChannel0Ver][difference];
				difference = abs( pData[order[1]] - pData[order[1] + pIB->pChannels[0].iLinePitch] );
				m_pHistogramAverage[pChannel1Ver] += difference;
				++m_ppHistogramBuffer[pChannel1Ver][difference];
				difference = abs( pData[order[2]] - pData[order[2] + pIB->pChannels[0].iLinePitch] );
				m_pHistogramAverage[pChannel2Ver] += difference;
				++m_ppHistogramBuffer[pChannel2Ver][difference];
			}
			pData += pIB->iBytesPerPixel;
		}
	}
}

//-----------------------------------------------------------------------------
template<typename _Ty>
void HistogramCanvas::CalculateNoiseHistogramUYV( const ImageBuffer* pIB )
//-----------------------------------------------------------------------------
{
	for( int line=0; line<m_AOIh; line++ )
	{
		_Ty* pData = reinterpret_cast<_Ty*>(static_cast<unsigned char*>(pIB->vpData) + ( ( m_AOIy + line ) * pIB->pChannels[pY].iLinePitch ) + ( m_AOIx * pIB->iBytesPerPixel ));
		_Ty difference = 0;
		for( int pixel=0; pixel<m_AOIw/2; pixel++ )
		{
			bool boIsVY = ( m_AOIx + pixel ) & 1;
			if( pixel < ( m_AOIw - 3 ) / 2 )
			{
				difference = abs( pData[1] - pData[3] );
				m_pHistogramAverage[pChannel0Hor] += difference;
				++m_ppHistogramBuffer[pChannel0Hor][difference];
				difference = abs( pData[3] - pData[5] );
				m_pHistogramAverage[pChannel0Hor] += difference;
				++m_ppHistogramBuffer[pChannel0Hor][difference];
				difference = abs( pData[0] - pData[4] );
				m_pHistogramAverage[boIsVY ? pChannel2Hor : pChannel1Hor] += 2*difference;
				m_ppHistogramBuffer[boIsVY ? pChannel2Hor : pChannel1Hor][difference] += 2;
				difference = abs( pData[2] - pData[6] );
				m_pHistogramAverage[boIsVY ? pChannel1Hor : pChannel2Hor] += 2*difference;
				m_ppHistogramBuffer[boIsVY ? pChannel1Hor : pChannel2Hor][difference] += 2;
			}
			if( line < m_AOIh - 1 )
			{
				difference = abs( pData[1] - pData[1 + pIB->pChannels[0].iLinePitch] );
				m_pHistogramAverage[pChannel0Ver] += difference;
				++m_ppHistogramBuffer[pChannel0Ver][difference];
				difference = abs( pData[0] - pData[pIB->pChannels[0].iLinePitch] );
				m_pHistogramAverage[boIsVY ? pChannel2Ver : pChannel1Ver] += difference;
				++m_ppHistogramBuffer[boIsVY ? pChannel2Ver : pChannel1Ver][difference];
				difference = abs( pData[3] - pData[3 + pIB->pChannels[0].iLinePitch] );
				m_pHistogramAverage[pChannel0Ver] += difference;
				++m_ppHistogramBuffer[pChannel0Ver][difference];
				difference = abs( pData[2] - pData[2 + pIB->pChannels[0].iLinePitch] );
				m_pHistogramAverage[boIsVY ? pChannel1Ver : pChannel2Ver] += difference;
				++m_ppHistogramBuffer[boIsVY ? pChannel1Ver : pChannel2Ver][difference];
			}
			pData += 4;
		}
	}
}

//-----------------------------------------------------------------------------
template<typename _Ty>
void HistogramCanvas::CalculateNoiseHistogramYUV( const ImageBuffer* pIB )
//-----------------------------------------------------------------------------
{
	for( int line=0; line<m_AOIh; line++ )
	{
		_Ty* pData = reinterpret_cast<_Ty*>(static_cast<unsigned char*>(pIB->vpData) + ( ( m_AOIy + line ) * pIB->pChannels[pY].iLinePitch ) + ( m_AOIx * pIB->iBytesPerPixel ));
		_Ty difference = 0;
		for( int pixel=0; pixel<m_AOIw/2; pixel++ )
		{
			bool boIsYV = ( m_AOIx + pixel ) & 1;
			if( pixel < ( m_AOIw - 3 ) / 2 )
			{
				difference = abs( pData[0] - pData[2] );
				m_pHistogramAverage[pChannel0Hor] += difference;
				++m_ppHistogramBuffer[pChannel0Hor][difference];
				difference = abs( pData[2] - pData[4] );
				m_pHistogramAverage[pChannel0Hor] += difference;
				++m_ppHistogramBuffer[pChannel0Hor][difference];
				difference = abs( pData[1] - pData[5] );
				m_pHistogramAverage[boIsYV ? pChannel2Hor : pChannel1Hor] += 2*difference;
				m_ppHistogramBuffer[boIsYV ? pChannel2Hor : pChannel1Hor][difference] += 2;
				difference = abs( pData[3] - pData[7] );
				m_pHistogramAverage[boIsYV ? pChannel1Hor : pChannel2Hor] += 2*difference;
				m_ppHistogramBuffer[boIsYV ? pChannel1Hor : pChannel2Hor][difference] += 2;
			}
			if( line < m_AOIh - 1 )
			{
				difference = abs( pData[0] - pData[pIB->pChannels[0].iLinePitch] );
				m_pHistogramAverage[pChannel0Ver] += difference;
				++m_ppHistogramBuffer[pChannel0Ver][difference];
				difference = abs( pData[1] - pData[1 + pIB->pChannels[0].iLinePitch] );
				m_pHistogramAverage[boIsYV ? pChannel2Ver : pChannel1Ver] += difference;
				++m_ppHistogramBuffer[boIsYV ? pChannel2Ver : pChannel1Ver][difference];
				difference = abs( pData[2] - pData[2 + pIB->pChannels[0].iLinePitch] );
				m_pHistogramAverage[pChannel0Ver] += difference;
				++m_ppHistogramBuffer[pChannel0Ver][difference];
				difference = abs( pData[3] - pData[3 + pIB->pChannels[0].iLinePitch] );
				m_pHistogramAverage[boIsYV ? pChannel1Ver : pChannel2Ver] += difference;
				++m_ppHistogramBuffer[boIsYV ? pChannel1Ver : pChannel2Ver][difference];
			}
			pData += 4;
		}
	}
}

//-----------------------------------------------------------------------------
void HistogramCanvas::CalculatePixelHistogram( const RequestData& data )
//-----------------------------------------------------------------------------
{
	const ImageBuffer* pIB = data.image_.getBuffer();
	switch( pIB->pixelFormat )
	{
	case ibpfMono8:
		if( m_bayerParity == bmpUndefined )
		{
			for( int line=0; line<m_AOIh; line++ )
			{
				unsigned char* pData = static_cast<unsigned char*>(pIB->vpData) + ( ( m_AOIy + line ) * pIB->pChannels[pRed].iLinePitch ) + ( m_AOIx * pIB->iBytesPerPixel );
				for( int pixel=0; pixel<m_AOIw; pixel++ )
				{
					m_pHistogramAverage[pRed] += *pData;
					++m_ppHistogramBuffer[pRed][*pData++];
				}
			}
		}
		else
		{
			for( int line=0; line<m_AOIh; line++ )
			{
				unsigned char* pData = static_cast<unsigned char*>(pIB->vpData) + ( ( m_AOIy + line ) * pIB->pChannels[pRed].iLinePitch ) + ( m_AOIx * pIB->iBytesPerPixel );
				for( int pixel=0; pixel<m_AOIw; pixel++ )
				{
					int index = ( ( ( line + m_AOIy ) & 1 ) ? ( ( ( pixel + m_AOIx ) & 1 ) ? pOddOdd : pOddEven ) : ( ( ( pixel + m_AOIx ) & 1 ) ? pEvenOdd : pEvenEven ) );
					m_pHistogramAverage[index] += *pData;
					++m_ppHistogramBuffer[index][*pData++];
				}
			}
		}
		break;
	case ibpfMono10:
	case ibpfMono12:
	case ibpfMono14:
	case ibpfMono16:
		if( m_bayerParity == bmpUndefined )
		{
			for( int line=0; line<m_AOIh; line++ )
			{
				unsigned short* pData = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(pIB->vpData) + ( ( m_AOIy + line ) * pIB->pChannels[pRed].iLinePitch ) + ( m_AOIx * pIB->iBytesPerPixel ));
				for( int pixel=0; pixel<m_AOIw; pixel++ )
				{
					unsigned short value = saveAssign( *pData, static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) );
					m_pHistogramAverage[pRed] += value;
					++m_ppHistogramBuffer[pRed][value];
					++pData;
				}
			}
		}
		else
		{
			for( int line=0; line<m_AOIh; line++ )
			{
				unsigned short* pData = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(pIB->vpData) + ( ( m_AOIy + line ) * pIB->pChannels[pRed].iLinePitch ) + ( m_AOIx * pIB->iBytesPerPixel ));
				for( int pixel=0; pixel<m_AOIw; pixel++ )
				{
					unsigned short value = saveAssign( *pData, static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) );
					int index = ( ( ( line + m_AOIy ) & 1 ) ? ( ( ( pixel + m_AOIx ) & 1 ) ? pOddOdd : pOddEven ) : ( ( ( pixel + m_AOIx ) & 1 ) ? pEvenOdd : pEvenEven ) );
					m_pHistogramAverage[index] += value;
					++m_ppHistogramBuffer[index][value];
					++pData;
				}
			}
		}
		break;
	case ibpfMono12Packed_V2:
		if( m_bayerParity == bmpUndefined )
		{
			for( int line=0; line<m_AOIh; line++ )
			{
				const int pixOffset = ( m_AOIy + line ) * pIB->iWidth;
				for( int pixel=0; pixel<m_AOIw; pixel++ )
				{
					unsigned short value = GetMonoPacked_V2Pixel( static_cast<unsigned char*>(pIB->vpData), pixOffset + m_AOIx + pixel, 4 );
					m_pHistogramAverage[pRed] += value;
					++m_ppHistogramBuffer[pRed][value];
				}
			}
		}
		else
		{
			for( int line=0; line<m_AOIh; line++ )
			{
				const int pixOffset = ( m_AOIy + line ) * pIB->iWidth;
				for( int pixel=0; pixel<m_AOIw; pixel++ )
				{
					unsigned short value = GetMonoPacked_V2Pixel( static_cast<unsigned char*>(pIB->vpData), pixOffset + m_AOIx + pixel, 4 );
					int index = ( ( ( line + m_AOIy ) & 1 ) ? ( ( ( pixel + m_AOIx ) & 1 ) ? pOddOdd : pOddEven ) : ( ( ( pixel + m_AOIx ) & 1 ) ? pEvenOdd : pEvenEven ) );
					m_pHistogramAverage[index] += value;
					++m_ppHistogramBuffer[index][value];
				}
			}
		}
		break;
	case ibpfBGR888Packed:
		{
			int order[3] = { 2, 1, 0 };
			CalculatePixelHistogram_8u_RGBPacked( pIB, order );
		}
		break;
	case ibpfRGBx888Packed:
	case ibpfRGB888Packed:
		{
			int order[3] = { 0, 1, 2 };
			CalculatePixelHistogram_8u_RGBPacked( pIB, order );
		}
		break;
	case ibpfBGR101010Packed_V2:
		for( int line=0; line<m_AOIh; line++ )
		{
			unsigned short red, green, blue;
			unsigned int* p =  reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(pIB->vpData) + ( ( m_AOIy + line ) * pIB->pChannels[0].iLinePitch )) + m_AOIx;
			for( int pixel=0; pixel<m_AOIw; pixel++ )
			{
				GetBGR101010Packed_V2Pixel( *p++, red, green, blue );
				m_pHistogramAverage[pBlue] += blue;
				++m_ppHistogramBuffer[pBlue][blue];
				m_pHistogramAverage[pGreen] += green;
				++m_ppHistogramBuffer[pGreen][green];
				m_pHistogramAverage[pRed] += red;
				++m_ppHistogramBuffer[pRed][red];
			}
		}
		break;
	case ibpfRGB101010Packed:
	case ibpfRGB121212Packed:
	case ibpfRGB141414Packed:
	case ibpfRGB161616Packed:
		for( int line=0; line<m_AOIh; line++ )
		{
			unsigned short* pData = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(pIB->vpData) + ( ( m_AOIy + line ) * pIB->pChannels[pRed].iLinePitch ) + ( m_AOIx * pIB->iBytesPerPixel ));
			for( int pixel=0; pixel<m_AOIw; pixel++ )
			{
				unsigned short value = saveAssign( *pData, static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) );
				m_pHistogramAverage[pBlue] += value;
				++m_ppHistogramBuffer[pBlue][value];
				++pData;
				value = saveAssign( *pData, static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) );
				m_pHistogramAverage[pGreen] += value;
				++m_ppHistogramBuffer[pGreen][value];
				++pData;
				value = saveAssign( *pData, static_cast<unsigned short>(0), static_cast<unsigned short>(m_valCount-1) );
				m_pHistogramAverage[pRed] += value;
				++m_ppHistogramBuffer[pRed][value];
				++pData;
			}
		}
		break;
	case ibpfRGBx888Planar:
		for( int line=0; line<m_AOIh; line++ )
		{
			unsigned char* pr = static_cast<unsigned char*>(pIB->vpData) + pIB->pChannels[pRed].iChannelOffset + ( ( m_AOIy + line ) * pIB->pChannels[pRed].iLinePitch ) + m_AOIx;
			unsigned char* pg = static_cast<unsigned char*>(pIB->vpData) + pIB->pChannels[pGreen].iChannelOffset + ( ( m_AOIy + line ) * pIB->pChannels[pGreen].iLinePitch ) + m_AOIx;
			unsigned char* pb = static_cast<unsigned char*>(pIB->vpData) + pIB->pChannels[pBlue].iChannelOffset + ( ( m_AOIy + line ) * pIB->pChannels[pBlue].iLinePitch ) + m_AOIx;
			for( int pixel=0; pixel<m_AOIw; pixel++ )
			{
				m_pHistogramAverage[pRed] += *pr;
				++m_ppHistogramBuffer[pRed][*pr++];
				m_pHistogramAverage[pGreen] += *pg;
				++m_ppHistogramBuffer[pGreen][*pg++];
				m_pHistogramAverage[pBlue] += *pb;
				++m_ppHistogramBuffer[pBlue][*pb++];
			}
		}
		break;
	case ibpfYUV422Packed:
		CalculatePixelHistogramYUV<unsigned char>( pIB );
		break;
	case ibpfYUV422_10Packed:
		CalculatePixelHistogramYUV<unsigned short>( pIB );
		break;
	case ibpfYUV422_UYVYPacked:
		CalculatePixelHistogramUYV<unsigned char>( pIB );
		break;
	case ibpfYUV422_UYVY_10Packed:
		CalculatePixelHistogramUYV<unsigned short>( pIB );
		break;
	case ibpfYUV444_UYVPacked:
		CalculatePixelHistogramYUV444<unsigned char>( pIB );
		break;
	case ibpfYUV444_UYV_10Packed:
		CalculatePixelHistogramYUV444<unsigned short>( pIB );
		break;
	case ibpfYUV444Packed:
		CalculatePixelHistogramYUV444<unsigned char>( pIB );
		break;
	case ibpfYUV444_10Packed:
		CalculatePixelHistogramYUV444<unsigned short>( pIB );
		break;
	case ibpfYUV422Planar:
		for( int line=0; line<m_AOIh; line++ )
		{
			unsigned char* py = static_cast<unsigned char*>(pIB->vpData) + pIB->pChannels[pY].iChannelOffset + ( ( m_AOIy + line ) * pIB->pChannels[pY].iLinePitch ) + m_AOIx;
			unsigned char* pu = static_cast<unsigned char*>(pIB->vpData) + pIB->pChannels[pU].iChannelOffset + ( ( m_AOIy + line ) * pIB->pChannels[pU].iLinePitch ) + m_AOIx;
			unsigned char* pv = static_cast<unsigned char*>(pIB->vpData) + pIB->pChannels[pV].iChannelOffset + ( ( m_AOIy + line ) * pIB->pChannels[pV].iLinePitch ) + m_AOIx;
			for( int pixel=0; pixel<m_AOIw; pixel++ )
			{
				m_pHistogramAverage[pY] += *py;
				++m_ppHistogramBuffer[pY][*py++];
				m_pHistogramAverage[pU] += *pu;
				++m_ppHistogramBuffer[pU][*pu];
				m_pHistogramAverage[pV] += *pv;
				++m_ppHistogramBuffer[pV][*pv];
				if( pixel & 1 )
				{
					++pu;
					++pv;
				}
			}
		}
		break;
	default:
		// unsupported colour mode
		m_ChannelCount = 0;
		m_boUnsupportedPixelFormat = true;
		break;
	}
}

//-----------------------------------------------------------------------------
void HistogramCanvas::CalculatePixelHistogram_8u_RGBPacked( const ImageBuffer* pIB, int order[3] )
//-----------------------------------------------------------------------------
{
	for( int line=0; line<m_AOIh; line++ )
	{
		unsigned char* pData = static_cast<unsigned char*>(pIB->vpData) + ( ( m_AOIy + line ) * pIB->pChannels[pRed].iLinePitch ) + ( m_AOIx * pIB->iBytesPerPixel );
		for( int pixel=0; pixel<m_AOIw; pixel++ )
		{
			m_pHistogramAverage[pBlue] += pData[order[0]];
			++m_ppHistogramBuffer[pBlue][pData[order[0]]];
			m_pHistogramAverage[pGreen] += pData[order[1]];
			++m_ppHistogramBuffer[pGreen][pData[order[1]]];
			m_pHistogramAverage[pRed] += pData[order[2]];
			++m_ppHistogramBuffer[pRed][pData[order[2]]];
			pData += pIB->iBytesPerPixel;
		}
	}
}

//-----------------------------------------------------------------------------
template<typename _Ty>
void HistogramCanvas::CalculatePixelHistogramUYV( const ImageBuffer* pIB )
//-----------------------------------------------------------------------------
{
	for( int line=0; line<m_AOIh; line++ )
	{
		_Ty* pData = reinterpret_cast<_Ty*>(static_cast<unsigned char*>(pIB->vpData) + ( ( m_AOIy + line ) * pIB->pChannels[pY].iLinePitch ) + ( m_AOIx * pIB->iBytesPerPixel ));
		const int LOOP_END = m_AOIx + m_AOIw;
		for( int pixel=m_AOIx; pixel<LOOP_END; pixel++ )
		{
			if( pixel % 2 )
			{
				m_pHistogramAverage[pChannel2] += *pData;
				++m_ppHistogramBuffer[pChannel2][*pData];
				m_pHistogramAverage[pChannel2] += *pData;
				++m_ppHistogramBuffer[pChannel2][*pData++];
			}
			else
			{
				m_pHistogramAverage[pChannel0] += *pData;
				++m_ppHistogramBuffer[pChannel0][*pData];
				m_pHistogramAverage[pChannel0] += *pData;
				++m_ppHistogramBuffer[pChannel0][*pData++];
			}
			m_pHistogramAverage[pChannel1] += *pData;
			++m_ppHistogramBuffer[pChannel1][*pData++];
		}
	}
}

//-----------------------------------------------------------------------------
template<typename _Ty>
void HistogramCanvas::CalculatePixelHistogramYUV( const ImageBuffer* pIB )
//-----------------------------------------------------------------------------
{
	for( int line=0; line<m_AOIh; line++ )
	{
		_Ty* pData = reinterpret_cast<_Ty*>(static_cast<unsigned char*>(pIB->vpData) + ( ( m_AOIy + line ) * pIB->pChannels[pY].iLinePitch ) + ( m_AOIx * pIB->iBytesPerPixel ));
		const int LOOP_END = m_AOIx + m_AOIw;
		for( int pixel=m_AOIx; pixel<LOOP_END; pixel++ )
		{
			m_pHistogramAverage[pY] += *pData;
			++m_ppHistogramBuffer[pY][*pData++];
			if( pixel % 2 )
			{
				m_pHistogramAverage[pV] += *pData;
				++m_ppHistogramBuffer[pV][*pData];
				m_pHistogramAverage[pV] += *pData;
				++m_ppHistogramBuffer[pV][*pData++];
			}
			else
			{
				m_pHistogramAverage[pU] += *pData;
				++m_ppHistogramBuffer[pU][*pData];
				m_pHistogramAverage[pU] += *pData;
				++m_ppHistogramBuffer[pU][*pData++];
			}
		}
	}
}

//-----------------------------------------------------------------------------
template<typename _Ty>
void HistogramCanvas::CalculatePixelHistogramYUV444( const ImageBuffer* pIB )
//-----------------------------------------------------------------------------
{
	for( int line=0; line<m_AOIh; line++ )
	{
		_Ty* pData = reinterpret_cast<_Ty*>(static_cast<unsigned char*>(pIB->vpData) + ( ( m_AOIy + line ) * pIB->pChannels[pY].iLinePitch ) + ( m_AOIx * pIB->iBytesPerPixel ));
		const int LOOP_END = m_AOIx + m_AOIw;
		for( int pixel=m_AOIx; pixel<LOOP_END; pixel++ )
		{
			m_pHistogramAverage[0] += pData[0];
			++m_ppHistogramBuffer[0][pData[0]];
			m_pHistogramAverage[1] += pData[1];
			++m_ppHistogramBuffer[1][pData[1]];
			m_pHistogramAverage[2] += pData[2];
			++m_ppHistogramBuffer[2][pData[2]];
			pData += 3;
		}
	}
}

//-----------------------------------------------------------------------------
void HistogramCanvas::DeallocateHistogramBuffer( void )
//-----------------------------------------------------------------------------
{
	if( m_ppHistogramBuffer )
	{
		for( int channel=0; channel<m_ChannelCount; channel++ )
		{
			delete [] m_ppHistogramBuffer[channel];
		}
		delete [] m_ppHistogramBuffer;
		m_ppHistogramBuffer = 0;
	}
	delete [] m_pHistogramAverage;
	m_pHistogramAverage = 0;
	delete [] m_pStandardDeviation;
	m_pStandardDeviation = 0;
	delete [] m_pHistogramMax;
	m_pHistogramMax = 0;
	CustomDealloc();
}

//-----------------------------------------------------------------------------
void HistogramCanvas::DrawHistogramLine( wxPaintDC& dc, int h, double scaleX, double scaleY, TPlane plane )
//-----------------------------------------------------------------------------
{
	if( !m_ppHistogramBuffer )
	{
		return;
	}

	int lowerStart = h - GetBorderWidth();
	dc.SetPen( *m_Pens[plane].pColour_ );
	unsigned int stepWidth = m_DrawStepWidth;
	if( stepWidth == 0 )
	{
		// '0' is auto mode, which results in no more then 256 different values will be displayed no matter which pixel format is used.
		stepWidth = static_cast<unsigned int>( static_cast<double>((m_valCount / 256)) * (static_cast<double>(GetPercentageToDraw()) / 100.));
	}
	if( stepWidth < 1 )
	{
		stepWidth = 1;
	}
	unsigned int from, to;
	GetDrawRange( &from, &to );
	for( unsigned int i=from; ( i<to-1 ) && ( i+stepWidth<m_valCount ); i+=stepWidth )
	{
		dc.DrawLine( static_cast<int>( GetBorderWidth() + ( ( i - from ) * scaleX ) + 1 ),
					 static_cast<int>( lowerStart - ( m_ppHistogramBuffer[plane][i] * scaleY ) ),
					 static_cast<int>( GetBorderWidth() + ( ( i - from + stepWidth ) * scaleX ) + 1 ),
					 static_cast<int>( lowerStart - ( m_ppHistogramBuffer[plane][i+stepWidth] * scaleY ) ) );
	}
	dc.SetPen( wxNullPen );
}

//-----------------------------------------------------------------------------
wxString HistogramCanvas::GetGridValue( int row, int col ) const
//-----------------------------------------------------------------------------
{
	if( m_ppHistogramBuffer && ( col >= 0 ) && ( row >= 0 ) && ( col < m_ChannelCount ) && ( static_cast<unsigned int>(row) <= m_valCount ) )
	{
		return ( row == 0 ) ? m_Pens[col].description_ : wxString::Format( GetGridValueFormatString().c_str(), m_ppHistogramBuffer[col][row-1] );
	}
	return wxEmptyString;
}

//-----------------------------------------------------------------------------
void HistogramCanvas::PrepareHistogramBuffer( bool boFormatChanged, int channelCount, mvIMPACT::acquire::TImageBufferPixelFormat pixelFormat )
//-----------------------------------------------------------------------------
{
	if( boFormatChanged || !m_ppHistogramBuffer || !m_pHistogramAverage || !m_pStandardDeviation || !m_pHistogramMax )
	{
		DeallocateHistogramBuffer();
		m_ChannelCount = channelCount;
		m_ppHistogramBuffer = new int*[channelCount];
		m_pHistogramAverage = new double[channelCount];
		m_pStandardDeviation = new double[channelCount];
		m_pHistogramMax = new PlotPoint[channelCount];
		assert( ( channelCount <= PLANE_CNT ) && wxT("Somebody has defined more channels then this tool can handle") );
		for( int channel=0; channel<channelCount; channel++ )
		{
			switch( pixelFormat )
			{
			case ibpfMono10:
			case ibpfBGR101010Packed_V2:
			case ibpfRGB101010Packed:
			case ibpfYUV422_10Packed:
			case ibpfYUV422_UYVY_10Packed:
			case ibpfYUV444_UYV_10Packed:
			case ibpfYUV444_10Packed:
				m_ppHistogramBuffer[channel] = new int[VAL_COUNT_10_BIT];
				m_valCount = VAL_COUNT_10_BIT;
				break;
			case ibpfMono12:
			case ibpfMono12Packed_V2:
			case ibpfRGB121212Packed:
				m_ppHistogramBuffer[channel] = new int[VAL_COUNT_12_BIT];
				m_valCount = VAL_COUNT_12_BIT;
				break;
			case ibpfMono14:
			case ibpfRGB141414Packed:
				m_ppHistogramBuffer[channel] = new int[VAL_COUNT_14_BIT];
				m_valCount = VAL_COUNT_14_BIT;
				break;
			case ibpfMono16:
			case ibpfRGB161616Packed:
				m_ppHistogramBuffer[channel] = new int[VAL_COUNT_16_BIT];
				m_valCount = VAL_COUNT_16_BIT;
				break;
			default:
				m_ppHistogramBuffer[channel] = new int[VAL_COUNT_8_BIT];
				m_valCount = VAL_COUNT_8_BIT;
				break;
			}
		}
		CustomAlloc( channelCount );
		SetupNumericalDisplay( m_ChannelCount, GetRowCountNeededForNumericalDisplay() );
	}

	for( int channel=0; channel<channelCount; channel++ )
	{
		memset( m_ppHistogramBuffer[channel], 0, m_valCount*sizeof(int) );
		m_pHistogramAverage[channel] = 0;
		m_pStandardDeviation[channel] = 0;
		m_pHistogramMax[channel] = PlotPoint();
	}
}

//-----------------------------------------------------------------------------
void HistogramCanvas::OnPaint( wxPaintEvent & )
//-----------------------------------------------------------------------------
{
	wxCriticalSectionLocker locker(m_critSect);
	wxPaintDC dc( this );

	if( !IsActive() )
	{
		return;
	}

	wxCoord w, h;
	dc.GetSize(&w, &h);
	int borderWidth = GetBorderWidth();
	double scaleY = static_cast<double>(h-2*borderWidth)/m_CurrentMax.cnt_;
	double scaleX = static_cast<double>(w-2*borderWidth)/(static_cast<double>(m_valCount) * (static_cast<double>(GetPercentageToDraw()) / 100.));

	dc.SetPen( *wxBLACK );
	dc.SetBrush( *wxWHITE_BRUSH );
	dc.DrawRectangle( 0, 0, w, h );
	dc.SetBrush( wxNullBrush );
	// lower line
	dc.DrawLine( borderWidth, h-borderWidth, w-borderWidth, h-borderWidth );
	// line on left side
	dc.DrawLine( borderWidth, h-borderWidth, borderWidth, borderWidth );

	// markers for X-axis
	int markerStartHeight = h - borderWidth - 3;
	int markerEndHeight = h - borderWidth + 4;
	unsigned int from, to;
	GetDrawRange( &from, &to );
	int XMarkerStepWidth = ( ( to - from ) < 6 ) ? ( to - from ) : ( to - from ) / 6;
	for( unsigned int i=from; i<to; i+=XMarkerStepWidth )
	{
		int xVal = i - from;
		dc.DrawLine( static_cast<int>( borderWidth + ( xVal * scaleX )), markerStartHeight, static_cast<int>( borderWidth + ( xVal * scaleX )), markerEndHeight );
		dc.DrawText( wxString::Format( wxT("%d"), i ), static_cast<int>( borderWidth + ( xVal * scaleX )), h - borderWidth + 3 );
	}

	// markers for y-axis
	int markerStart = borderWidth - 3;
	int markerEnd = borderWidth + 4;
	dc.DrawLine( markerStart, borderWidth, markerEnd, borderWidth );
	wxCoord textWidth, textHeight;
	wxCoord xOffset(1);
	const wxCoord rectSize(10);
	if( m_pHistogramAverage && m_pHistogramMax )
	{
		if( m_boUnsupportedPixelFormat )
		{
			dc.SetTextForeground( *wxRED );
			dc.DrawText( wxString(wxT("Unsupported pixel format")), xOffset, 1 );
		}
		else
		{
			for( int channel=0; channel<m_ChannelCount; channel++ )
			{
				DrawHistogramLine( dc, h, scaleX, scaleY, static_cast<TPlane>(channel) );
				wxString completeDescString = wxString::Format( wxT("%s(%.2f, %5d/%5d"), m_Pens[channel].description_.c_str(), m_pHistogramAverage[channel], m_pHistogramMax[channel].cnt_, m_pHistogramMax[channel].val_ );
				if( m_pStandardDeviation && m_boHandleStandardDeviation )
				{
					completeDescString.Append( wxString::Format( wxT(", %.2f"), m_pStandardDeviation[channel] ) );
				}
				completeDescString.Append( wxT("): ") );
				if( channel != 0 )
				{
					completeDescString.insert( 0, wxString(wxT(", ")) );
				}
				dc.DrawText( completeDescString, xOffset, 1 );
				dc.GetTextExtent( completeDescString, &textWidth, &textHeight );
				wxCoord yOffsetRect(((textHeight-rectSize)/2)+1);
				xOffset += textWidth;
				dc.SetPen( wxPen(*wxBLACK, 1, wxSOLID ) );
				dc.SetBrush( wxBrush(*(m_Pens[channel].pColour_)) );
				dc.DrawRectangle( xOffset, yOffsetRect, rectSize, rectSize );
				dc.SetBrush( wxNullBrush );
				dc.SetPen( wxNullPen );
				xOffset += rectSize + 2;
			}
		}
	}
	dc.SetBrush( wxNullBrush );
	dc.SetPen( wxNullPen );
}

//-----------------------------------------------------------------------------
void HistogramCanvas::SetDrawStepWidth( int value )
//-----------------------------------------------------------------------------
{
	if( ( value < 0 ) || ( value > GetDrawStepWidthMax() ) )
	{
		return;
	}
	AssignDisplayParameter( m_DrawStepWidth, value );
}

//-----------------------------------------------------------------------------
void HistogramCanvas::SetupNumericalDisplay( int channelCount, int rowCountNeeded )
//-----------------------------------------------------------------------------
{
	if( m_pNumericalDisplay )
	{
		int columnCount = m_pNumericalDisplay->GetTable()->GetNumberCols();
		if( columnCount < channelCount )
		{
			m_pNumericalDisplay->AppendCols( channelCount - columnCount );
		}
		else if( columnCount > channelCount )
		{
			m_pNumericalDisplay->DeleteCols( columnCount - 1, columnCount - channelCount );
		}
		for( int i=0; i<channelCount; i++ )
		{
			m_pNumericalDisplay->SetCellBackgroundColour( 0, i, *m_Pens[i].pColour_ );
			m_pNumericalDisplay->SetCellTextColour( 0, i, *wxWHITE );
			m_pNumericalDisplay->SetCellValue( 0, i, m_Pens[i].description_ );
		}

		int rowCount = m_pNumericalDisplay->GetTable()->GetNumberRows();
		if( rowCount < rowCountNeeded )
		{
			m_pNumericalDisplay->AppendRows( rowCountNeeded - rowCount );
		}
		else if( rowCount > rowCountNeeded )
		{
			m_pNumericalDisplay->DeleteRows( rowCount - 1, rowCount - rowCountNeeded );
		}
	}
}

//=============================================================================
//================= Implementation PixelHistogramCanvas =======================
//=============================================================================

IMPLEMENT_DYNAMIC_CLASS(PixelHistogramCanvas, HistogramCanvas)

//-----------------------------------------------------------------------------
PixelHistogramCanvas::PixelHistogramCanvas( wxWindow* parent, wxWindowID id /* = -1 */, const wxPoint& pos /* = wxDefaultPosition */,
	const wxSize& size /* = wxDefaultSize */, long style /* = wxSUNKEN_BORDER */, const wxString& name /* = "pixelhistogram" */, bool boActive /* = true */ )
	: HistogramCanvas(parent, wxT("Histogram"), id, pos, size, style, name, boActive) {}
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
void PixelHistogramCanvas::RefreshData( const RequestData& data, int x /* = -1 */, int y /* = -1 */, int w /* = -1 */, int h /* = -1 */, bool boForceRefresh /* = false */ )
//-----------------------------------------------------------------------------
{
	wxCriticalSectionLocker locker(m_critSect);

	bool boImageFormatChanged = false;
	const ImageBuffer* pIB = data.image_.getBuffer();
	const TBayerMosaicParity bayerParity = GetProcessBayerParity() ? data.bayerParity_ : bmpUndefined;
	const int channelCount = ( ( bayerParity != bmpUndefined ) ? 4 : pIB->iChannelCount );
	if( !MustUpdate( pIB, channelCount, x, y, w, h, boForceRefresh, 0, &boImageFormatChanged ) )
	{
		return;
	}

	if( boImageFormatChanged || !m_ppHistogramBuffer || !m_pHistogramAverage || !m_pHistogramMax || ( m_bayerParity != bayerParity ) )
	{
		SetupGDIData( pIB, channelCount, bayerParity );
		m_bayerParity = bayerParity;
	}

	PrepareHistogramBuffer( boImageFormatChanged, channelCount, pIB->pixelFormat );
	CalculatePixelHistogram( data );
	CalculateMaxValue();
	boImageFormatChanged |= CustomRefreshData( data, x, y, w, h );
	UpdateAnalysisOutput( boImageFormatChanged );
}

//=============================================================================
//================= Implementation IntensityPlotCanvas ========================
//=============================================================================

IMPLEMENT_DYNAMIC_CLASS(IntensityPlotCanvas, PixelHistogramCanvas)

//-----------------------------------------------------------------------------
IntensityPlotCanvas::IntensityPlotCanvas( wxWindow* parent, wxWindowID id /* = -1 */, const wxPoint& pos /* = wxDefaultPosition */,
	const wxSize& size /* = wxDefaultSize */, long style /* = wxSUNKEN_BORDER */, const wxString& name /* = "Intensity Plot" */, bool boActive /* = true */ )
	: PixelHistogramCanvas(parent, id, pos, size, style, name, boActive), m_SelectedPlot(psAverageIntensity),
	m_ppPlotValues(0), m_CurrentMaxPlotValues(), m_CurrentMinPlotValues(), m_CurrentPlotValues(),
	m_CurrentMaxPlotValue(std::numeric_limits<plot_datatype>::min()), m_CurrentMinPlotValue(std::numeric_limits<plot_datatype>::max())
//-----------------------------------------------------------------------------
{
	m_plotFeatures.insert( pfHistoryDepth );
	m_plotFeatures.erase( pfStepWidth );
	CustomAlloc( 1 );
	m_PlotNames.resize( psLAST );
	m_PlotNames[psAverageIntensity] = wxString(wxT("Average Intensity"));
	m_PlotNames[psMostFrequentValue] = wxString(wxT("Most Frequent Value"));
}

//-----------------------------------------------------------------------------
IntensityPlotCanvas::~IntensityPlotCanvas()
//-----------------------------------------------------------------------------
{
	CustomDealloc();
}

//-----------------------------------------------------------------------------
void IntensityPlotCanvas::CustomAlloc( int channelCount )
//-----------------------------------------------------------------------------
{
	m_PlotCount = channelCount;
	m_ppPlotValues = new std::deque<plot_datatype>*[m_PlotCount];
	m_CurrentMaxPlotValues.resize( m_PlotCount );
	m_CurrentMinPlotValues.resize( m_PlotCount );
	m_CurrentPlotValues.resize( m_PlotCount );
	for( unsigned int i=0; i<m_PlotCount; i++ )
	{
		m_ppPlotValues[i] = new std::deque<plot_datatype>();
		m_CurrentMaxPlotValues[i] = std::numeric_limits<plot_datatype>::min();
		m_CurrentMinPlotValues[i] = std::numeric_limits<plot_datatype>::max();
		m_CurrentPlotValues[i] = 0;
	}
}

//-----------------------------------------------------------------------------
void IntensityPlotCanvas::CustomDealloc( void )
//-----------------------------------------------------------------------------
{
	if( m_ppPlotValues )
	{
		for( unsigned int i=0; i<m_PlotCount; i++ )
		{
			delete m_ppPlotValues[i];
		}
		delete [] m_ppPlotValues;
		m_ppPlotValues = 0;
		m_CurrentMaxPlotValues.clear();
		m_CurrentMinPlotValues.clear();
		m_CurrentPlotValues.clear();
		m_PlotCount = 0;
	}
}

//-----------------------------------------------------------------------------
bool IntensityPlotCanvas::CustomRefreshData( const RequestData& /*data*/, int /*x = -1*/, int /*y = -1*/, int /*w = -1*/, int /*h = -1*/ )
//-----------------------------------------------------------------------------
{
	switch( m_SelectedPlot )
	{
	case psAverageIntensity:
		for( size_t channel=0; channel<m_PlotCount; channel++ )
		{
			m_CurrentPlotValues[channel] = m_pHistogramAverage[channel];
			m_ppPlotValues[channel]->push_back( m_pHistogramAverage[channel] );
		}
		break;
	case psMostFrequentValue:
		for( size_t channel=0; channel<m_PlotCount; channel++ )
		{
			m_CurrentPlotValues[channel] = m_pHistogramMax[channel].val_;
			m_ppPlotValues[channel]->push_back( m_pHistogramMax[channel].val_ );
		}
		break;
	case psLAST:
		return false;
	// don't add a default here. If an enum is not handled here the compiler can tell us then
	}

	bool boFullUpdate = RefreshPlotData();
	return boFullUpdate;
}

//-----------------------------------------------------------------------------
wxString IntensityPlotCanvas::GetGridValue( int row, int col ) const
//-----------------------------------------------------------------------------
{
	if( m_ppPlotValues && ( col >= 0 ) && ( row >= 0 ) && ( col < m_ChannelCount ) && ( static_cast<std::deque<plot_datatype>::size_type>(row) <= m_ppPlotValues[col]->size() ) )
	{
		return ( row == 0 ) ? m_Pens[col].description_ : wxString::Format( GetGridValueFormatString().c_str(), (*m_ppPlotValues[col])[row-1] );
	}
	return wxEmptyString;
}

//-----------------------------------------------------------------------------
int IntensityPlotCanvas::GetRowCountNeededForNumericalDisplay( void ) const
//-----------------------------------------------------------------------------
{
	return m_HistoryDepth + 1;
}

//-----------------------------------------------------------------------------
void IntensityPlotCanvas::OnPaint( wxPaintEvent & )
//-----------------------------------------------------------------------------
{
	wxCriticalSectionLocker locker(m_critSect);
	wxPaintDC dc( this );

	if( !IsActive() )
	{
		return;
	}

	wxCoord w, h;
	dc.GetSize(&w, &h);
	int borderWidth = GetBorderWidth();
	const int diagramHeight = h-2*borderWidth;
	double scaleY = static_cast<double>(diagramHeight) / ( static_cast<double>(m_valCount) * static_cast<double>(GetPercentageToDraw()) / 100. );
	double scaleX = static_cast<double>(w-2*borderWidth)/static_cast<double>(m_HistoryDepth);

	// white rectangle for the background
	dc.SetPen( *wxBLACK );
	dc.SetBrush( *wxWHITE_BRUSH );
	dc.DrawRectangle( 0, 0, w, h );
	dc.SetBrush( wxNullBrush );
	// lower line
	dc.DrawLine( borderWidth, h-borderWidth, w-borderWidth, h-borderWidth );
	// line on left side
	dc.DrawLine( borderWidth, h-borderWidth, borderWidth, borderWidth );

	// markers for X-axis
	int markerStartHeight = h - borderWidth - 3;
	int markerEndHeight = h - borderWidth + 4;
	const int XMarkerStepWidth = m_HistoryDepth / 5;
	for( unsigned int i=0; i<m_HistoryDepth; i += XMarkerStepWidth )
	{
		dc.DrawLine( static_cast<int>( borderWidth + ( i * scaleX )), markerStartHeight, static_cast<int>( borderWidth + ( i * scaleX )), markerEndHeight );
		dc.DrawText( wxString::Format( wxT("%d"), i ), static_cast<int>( borderWidth + ( i * scaleX )), h - borderWidth + 3 );
	}

	// markers for y-axis
	int markerStart = borderWidth - 3;
	int markerEnd = borderWidth + 4;
	dc.DrawLine( markerStart, borderWidth, markerEnd, borderWidth );

	wxCoord textOffset = 1;

	unsigned int from, to;
	GetDrawRange( &from, &to );
	for( unsigned int i=0; i<m_PlotCount; i++ )
	{
		const unsigned int valCount = static_cast<unsigned int>(m_ppPlotValues[i]->size());
		if( valCount > 1 )
		{
			int lowerStart = h - GetBorderWidth();
			dc.SetPen( *m_Pens[i].pColour_ );
			for( unsigned int j=0; j<valCount-1; j++ )
			{
				dc.DrawLine( static_cast<wxCoord>( GetBorderWidth() + ( j*scaleX ) ),
					 static_cast<wxCoord>( lowerStart - ( saveAssign( static_cast<wxCoord>((*m_ppPlotValues[i])[j] - from), 0, static_cast<wxCoord>(to - from) ) * scaleY ) ),
					 static_cast<wxCoord>( GetBorderWidth() + ( ( j+1 ) * scaleX ) ),
					 static_cast<wxCoord>( lowerStart - ( saveAssign( static_cast<wxCoord>((*m_ppPlotValues[i])[j+1] - from), 0, static_cast<wxCoord>(to - from) ) * scaleY ) ) );
			}

			dc.SetPen( wxNullPen );
		}

		// info in the top left corner
		wxString descriptionText(wxString::Format( wxT("%s: max: %.2f, min: %.2f : "), m_Pens[i].description_.c_str(), m_CurrentMaxPlotValues[i], ( m_CurrentMinPlotValues[i] == std::numeric_limits<plot_datatype>::max() ) ? 0. : m_CurrentMinPlotValues[i] ));
		dc.DrawText( descriptionText, textOffset, 1 );
		wxCoord textWidth, textHeight;
		dc.GetTextExtent( descriptionText, &textWidth, &textHeight );
		dc.SetPen( wxPen(*wxBLACK, 1, wxSOLID ) );
		dc.SetBrush( wxBrush(*m_Pens[i].pColour_) );
		dc.DrawRectangle( textOffset + textWidth, (((textHeight-10)/2)+1), 10, 10 );
		textOffset += textWidth + 15;
		dc.SetBrush( wxNullBrush );
		dc.SetPen( wxNullPen );
	}
	dc.SetBrush( wxNullBrush );
	dc.SetPen( wxNullPen );
}

//-----------------------------------------------------------------------------
bool IntensityPlotCanvas::RefreshPlotData( void )
//-----------------------------------------------------------------------------
{
	bool boFullUpdate = false;

	for( unsigned int i=0; i<m_PlotCount; i++ )
	{
		bool boMaxRemovedFromQueue = false;
		bool boMinRemovedFromQueue = false;
		while( m_ppPlotValues[i]->size() > m_HistoryDepth )
		{
			if( m_ppPlotValues[i]->front() == m_CurrentMaxPlotValues[i] )
			{
				boMaxRemovedFromQueue = true;
			}
			if( m_ppPlotValues[i]->front() == m_CurrentMinPlotValues[i] )
			{
				boMinRemovedFromQueue = true;
			}
			m_ppPlotValues[i]->pop_front();
		}

		if( boMaxRemovedFromQueue )
		{
			m_CurrentMaxPlotValues[i] = *(std::max_element( m_ppPlotValues[i]->begin(), m_ppPlotValues[i]->end() ));
		}
		else if( !m_ppPlotValues[i]->empty() && ( m_ppPlotValues[i]->back() > m_CurrentMaxPlotValues[i] ) )
		{
			m_CurrentMaxPlotValues[i] = m_ppPlotValues[i]->back();
		}

		if( boMinRemovedFromQueue )
		{
			m_CurrentMinPlotValues[i] = *(std::min_element( m_ppPlotValues[i]->begin(), m_ppPlotValues[i]->end() ));
		}
		else if( !m_ppPlotValues[i]->empty() && ( m_ppPlotValues[i]->back() < m_CurrentMinPlotValues[i] ) )
		{
			m_CurrentMinPlotValues[i] = m_ppPlotValues[i]->back();
		}
	}

	plot_datatype maxVal = *(std::max_element( m_CurrentMaxPlotValues.begin(), m_CurrentMaxPlotValues.end() ));
	if( m_CurrentMaxPlotValue != maxVal )
	{
		m_CurrentMaxPlotValue = maxVal;
		boFullUpdate = true;
	}

	plot_datatype minVal = *(std::min_element( m_CurrentMinPlotValues.begin(), m_CurrentMinPlotValues.end() ));
	if( m_CurrentMinPlotValue != minVal )
	{
		m_CurrentMinPlotValue = minVal;
		boFullUpdate = true;
	}

	return boFullUpdate;
}

//-----------------------------------------------------------------------------
void IntensityPlotCanvas::SetPlotSelection( const wxString& plotName )
//-----------------------------------------------------------------------------
{
	wxCriticalSectionLocker locker(m_critSect);

	TPlotSelection plotSelection = psLAST;
	for( std::vector<wxString>::size_type i=0; i<psLAST; i++ )
	{
		if( m_PlotNames[i] == plotName )
		{
			plotSelection = static_cast<TPlotSelection>(i);
			break;
		}
	}

	if( m_SelectedPlot == plotSelection )
	{
		return;
	}

	// ignore invalid values
	if( ( plotSelection >= psLAST ) || ( plotSelection < psFIRST ) )
	{
		return;
	}

	m_SelectedPlot = plotSelection;
	for( unsigned int i=0; i<m_PlotCount; i++ )
	{
		m_ppPlotValues[i]->clear();
		m_CurrentMaxPlotValues[i] = std::numeric_limits<plot_datatype>::min();
		m_CurrentMinPlotValues[i] = std::numeric_limits<plot_datatype>::max();
	}
	m_CurrentMaxPlotValue = std::numeric_limits<plot_datatype>::min();
	m_CurrentMinPlotValue = std::numeric_limits<plot_datatype>::max();
	UpdateAnalysisOutput( true );
}

//-----------------------------------------------------------------------------
void IntensityPlotCanvas::UpdateInternalData( void )
//-----------------------------------------------------------------------------
{
	RefreshPlotData();
	SetupNumericalDisplay( m_ChannelCount, GetRowCountNeededForNumericalDisplay() );
}

//=============================================================================
//================= Implementation NoiseHistogramCanvas =======================
//=============================================================================

IMPLEMENT_DYNAMIC_CLASS(NoiseHistogramCanvas, HistogramCanvas)

//-----------------------------------------------------------------------------
NoiseHistogramCanvas::NoiseHistogramCanvas( wxWindow* parent, wxWindowID id /* = -1 */, const wxPoint& pos /* = wxDefaultPosition */,
	const wxSize& size /* = wxDefaultSize */, long style /* = wxSUNKEN_BORDER */, const wxString& name /* = "noisehistogram" */, bool boActive /* = true */ )
	: HistogramCanvas(parent, wxT("NoiseHistogram"), id, pos, size, style, name, boActive, true)
//-----------------------------------------------------------------------------
{
	for( int i=0; i<PLANE_CNT; i++ )
	{
		m_Pens[i].description_ = wxString::Format( wxT("C%d%s"), i/2, ( i%2 ? wxT("Ver") : wxT("Hor") ) );
	}
}

//-----------------------------------------------------------------------------
void NoiseHistogramCanvas::RefreshData( const RequestData& data, int x /* = -1 */, int y /* = -1 */, int w /* = -1 */, int h /* = -1 */, bool boForceRefresh /* = false */ )
//-----------------------------------------------------------------------------
{
	wxCriticalSectionLocker locker(m_critSect);

	bool boImageFormatChanged = false;
	const ImageBuffer* pIB = data.image_.getBuffer();
	const TBayerMosaicParity bayerParity = GetProcessBayerParity() ? data.bayerParity_ : bmpUndefined;
	const int channelCount = ( bayerParity != bmpUndefined ) ? 4 : pIB->iChannelCount;
	if( !MustUpdate( pIB, 2*channelCount, x, y, w, h, boForceRefresh, 0, &boImageFormatChanged ) )
	{
		return;
	}

	if( boImageFormatChanged || ( m_bayerParity != bayerParity ) )
	{
		SetDefaultPens( pIB->pixelFormat );
		m_bayerParity = bayerParity;
	}

	PrepareHistogramBuffer( boImageFormatChanged, 2*channelCount, pIB->pixelFormat );
	CalculateNoiseHistogram( data );
	CalculateMaxValue();
	UpdateAnalysisOutput( boImageFormatChanged );
}
