Background subtraction with presence persistence

Hi, everyone, and thanks in advance for any help.

I would like to get a background subtraction method capable of gradually adjust itself to soft light variations but with the capacity of revealing a presence even that is not in motion.

What I’m trying to achieve is a mixture between old background subtraction method (based in comparing the actual frame with one initial referential image of the background) and those more actual adaptive ones.

For what I’ve been checking, the adaptive methods I’ve tried in python (with opencv ) or processing are only capable of detect a moving presence, comparing one frame with continually updated previous frames. Using the results for extracting consistent blobs of a foreground element that is not always moving seems difficult, because with the lack of movement the foreground turns into background.

This approach is useful to me as allows me to update the background reference img but the old method seems more consistent to me in the blob matter.

In the aim of getting a background subtraction method that doesn’t turn the still foreground presence into background, but allows you to update the referential background image for gradual light changes situations, I’ve modified the Golan Levin’s background subtraction processing sketch.

My logic is the following: when the difference of pixel values is below a low threshold we consider it as not due to presence but to a gradual change of light circumstances. This little changed pixels are therefore substituted to the pixels in the same position in the background reference’s array of pixels.

This method is obviously not valid with dramatic changes of the background like the appearance of a car light or whatever. Even that, I think it could help me in the situation of needing a background subtraction method in a middle controlled outdoor location. The installation I need to detect presence for would be in time slot where natural light is still fading until it becomes complete night.

Does anybody has an idea for improving this method or any other that would not need machine learning? My 2010 mac doesn’t allow me to install CUDA but even that I thing a background subtraction method with adaptive capabilities could be done.

I post the code of my sketch. Just press the ’s’ key for starting the comparison with the background.

/**
 * Background Subtraction 
 * by Golan Levin. 
 *
 * Detect the presence of people and objects in the frame using a simple
 * background-subtraction technique. To initialize the background, press key 's'.
 */


import processing.video.*;

int numPixels;
int[] backgroundPixels, backImg, preBackImg;
Capture video;
int camSel=0;
int topDiff=763;
int unbralDif=120;
int mindDif=20;
boolean subtraction, lowSubtr, bw, showBackgr;
PGraphics _tempPG;

void setup() {
  size(640, 480); 
  //colorMode(HSB, width, height, 100); 

  //backImg=createGraphics(width, height);
  ///preBackImg=createGraphics(width, height);
  // This the default video input, see the GettingStartedCapture 
  // example if it creates an error
  //video = new Capture(this, 160, 120);
  _tempPG=createGraphics(width, height);
  if (camSel==0)video = new Capture(this, width, height);
  else video = new Capture(this, width, height, Capture.list()[1]);

  // Start capturing the images from the camera
  video.start();  

  numPixels = video.width * video.height;
  // Create array to store the background image
  backgroundPixels = new int[numPixels];
  backImg = new int[numPixels];
  preBackImg = new int[numPixels];
  // Make the pixels[] array available for direct manipulation
  loadPixels();
}

void draw() {
  if (video.available()) {
    video.read(); // Read a new video frame
    video.loadPixels(); // Make the pixels of video available
    // Difference between the current frame and the stored background

    int presenceSum = 0;
    int diferencia=0;

    for (int i = 0; i < numPixels; i++) { // For each pixel in the video frame...
      // Fetch the current color in that location, and also the color
      // of the background in that spot
      color currColor = video.pixels[i];
      //float colBright=brightness(currColor);
      //color currColor = backImg[i];
      color bkgdColor = backgroundPixels[i];

      // Extract the red, green, and blue components of the current pixel's color
      int currR = (currColor >> 16) & 0xFF;
      int currG = (currColor >> 8) & 0xFF;
      int currB = currColor & 0xFF;

      // Extract the red, green, and blue components of the background pixel's color
      int bkgdR = (bkgdColor >> 16) & 0xFF;
      int bkgdG = (bkgdColor >> 8) & 0xFF;
      int bkgdB = bkgdColor & 0xFF;

      // Compute the difference of the red, green, and blue values
      int diffR = abs(currR - bkgdR);
      int diffG = abs(currG - bkgdG);
      int diffB = abs(currB - bkgdB);

      // Add these differences to the running tally
      presenceSum += diffR + diffG + diffB;


      // Render the difference image to the screen
      //pixels[i] = int(color(diffR, diffG, diffB);
      //turn image into bw, for future IR webcam input
      int gris=(int(brightness(color(diffR, diffG, diffB))));
      if (!showBackgr) {
        if (bw)pixels[i] =color(gris, gris, gris);
        else  pixels[i] = 0xFF000000 | (diffR << 16) | (diffG << 8) | diffB;
      }
      // The following line does the same thing much faster, but is more technical
      // pixels[i] = 0xFF000000 | (diffR << 16) | (diffG << 8) | diffB;


      /* auto-updating background part*/
      diferencia = diffR+diffG+diffB;
      //detect pixels that have change below a threshold
      if (lowSubtr && diferencia<mindDif) {
        /* substitute with them the backgound img array */
        backgroundPixels[i]=video.pixels[i];
      }
      
      /* end auto-updating background part*/

    }//end for

    updatePixels(); // Notify that the pixels[] array has changed
    //println("presenceSum: "+presenceSum); // Print out the total amount of movement
  }

  if (showBackgr) {
    _tempPG.beginDraw();
    _tempPG.loadPixels();
    arrayCopy(backgroundPixels,_tempPG.pixels);
    image(_tempPG, 0, 0);
    _tempPG.updatePixels();
    _tempPG.endDraw();
  }
  
  //toma inicial de imagen de fondo
  if (subtraction)startSubtr();
  subtraction=false;
}//end draw


void keyPressed() {
  if (keyPressed) {
    if (key=='s') subtraction=!subtraction;
    if (key=='g')bw=!bw;
    if (key=='b') {
      showBackgr=!showBackgr;
    }
  }
}

void startSubtr() {
  arraycopy(video.pixels, backgroundPixels);
  lowSubtr=true;
}


void actualizacion(int[] _srcArr, int[] _inputArr, int _ind) {
  for (int i=0; i<_srcArr.length; i++) {
    _srcArr[_ind]=_inputArr[i];
  }
}

2 posts were merged into an existing topic: Adaptive background subtraction with motionless objects