int TBackgroundVuMeter::UpdateBackground(IplImage *pSource, IplImage *pBackground, IplImage *pMotionMask)
{
  int nErr = 0;
  unsigned char *ptrs, *ptrb, *ptrm;
  float *ptr1, *ptr2;

  if(!isInitOk(pSource, pBackground, pMotionMask))
    nErr = Init(pSource);
  
  if(!nErr)
  {
    m_nCount++;
    int nbc = pSource->width;
    int nbl = pSource->height;
    unsigned char v = m_nBinSize;

    // multiplie tout par alpha
    for(int i = 0; i < m_nBinCount; ++i)
      cvConvertScale(m_pHist[i], m_pHist[i], m_fAlpha, 0.0);

    for(int l = 0; l < nbl; ++l)
    {
      ptrs = (unsigned char *)(pSource->imageData + pSource->widthStep * l);
      ptrm = (unsigned char *)(pMotionMask->imageData + pMotionMask->widthStep * l);
      ptrb = (unsigned char *)(pBackground->imageData + pBackground->widthStep * l);

      for(int c = 0; c < nbc; ++c, ptrs++, ptrb++, ptrm++)
      {
        // recherche le bin à augmenter
        int i = *ptrs / v;
        
        if(i < 0 || i >= m_nBinCount)
          i = 0;
        
        ptr1 = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * l);
        ptr1 += c;

        *ptr1 += (float)(1.0 - m_fAlpha);
        *ptrm = (*ptr1 < m_fThreshold) ? 255 : 0;

        // recherche le bin du fond actuel
        i = *ptrb / v;
        
        if(i < 0 || i >= m_nBinCount)
          i = 0;
        
        ptr2 = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * l);
        ptr2 += c;

        if(*ptr2 < *ptr1)
          *ptrb = *ptrs;
      }
    }

    if(m_nCount < 5)
      cvSetZero(pMotionMask);
  }

  return nErr;
}
int TBackground::UpdateTest(IplImage *pSource, IplImage *pBackground, IplImage *pTest, int nX, int nY, int nInd)
{
  int nErr = 0;
  CvScalar Color;
  unsigned char *ptr;
  int l, c;

  if(pTest == NULL || !isInitOk(pSource, pBackground, pSource))
    nErr = 1;

  if(!nErr)
  {
    if(pTest->width != 256 || pTest->height != 256 || pTest->nChannels != 3)
      nErr = 1;

    if(nX < 0 || nX > pSource->width || nY < 0 || nY > pSource->height)
      nErr = 1;

    switch(nInd)
    {
      case 0 : Color = cvScalar(128, 0, 0); break;
      case 1 : Color = cvScalar(0, 128, 0); break;
      case 2 : Color = cvScalar(0, 0, 128); break;
      default : nErr = 1;
    }
  }

  if(!nErr)
  {
    // recupere l'indice de la colonne
    ptr = (unsigned char *)(pTest->imageData);
    c = *ptr;
    
    // efface la colonne
    cvLine(pTest, cvPoint(c, 0), cvPoint(c, 255), cvScalar(0));
    *ptr += 1;

    //recupere la couleur du fond
    ptr = (unsigned char *)(pBackground->imageData + pBackground->widthStep * nY);
    ptr += nX;
    l = *ptr;

    // dessine la couleur
    cvLine(pTest, cvPoint(c, l - 5), cvPoint(c, l + 5), Color);

    //recupere la couleur du point
    ptr = (unsigned char *)(pSource->imageData + pSource->widthStep * nY);
    ptr += nX;
    l = *ptr;

    // dessine la couleur
    ptr = (unsigned char *)(pTest->imageData + pTest->widthStep * l);
    ptr += (c * 3) + nInd;
    *ptr = 255;
  }

  return nErr;
}
int TBackgroundVuMeter::UpdateTest(IplImage *pSource, IplImage *pBackground, IplImage *pTest, int nX, int nY, int nInd)
{
  int nErr = 0;
  int i, nbl, nbc;
  float *ptrf;

  if(pTest == NULL || !isInitOk(pSource, pBackground, pSource)) 
    nErr = 1;

  if(!nErr)
  {
    nbl = pTest->height;
    nbc = pTest->width;

    if(nbl != 100 || nbc != m_nBinCount) 
      nErr = 1;

    if(nX < 0 || nX >= pSource->width || nY < 0 || nY >= pSource->height)
      nErr = 1;
  }

  if(!nErr)
  {
    cvSetZero(pTest);

    for(i = 0; i < m_nBinCount; ++i)
    {
      ptrf = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * nY);
      ptrf += nX;

      if(*ptrf >= 0 || *ptrf <= 1.0) {
        cvLine(pTest, cvPoint(i, 100), cvPoint(i, (int)(100.0 * (1.0 - *ptrf))), cvScalar(0, 255, 0));
      }
    }

    cvLine(pTest, cvPoint(0, (int)(100.0 * (1.0 - m_fThreshold))), cvPoint(m_nBinCount, (int)(100.0 * (1.0 - m_fThreshold))), cvScalar(0, 128, 0));
  }

  return nErr;
}