SoFunction
Updated on 2024-11-15

Motion detection ViBe algorithm python implementation code

Motion object detection is generally divided into two steps: background modeling and motion object analysis. That is, a background model without moving objects is constructed. Then new video frames are compared with the background model to find out the moving objects in them. There are two better background modeling algorithms: 1) Article (Zivkovic Z. (2004) Improved adaptive Gausianmixture model for backgroundsubtraction, Proceedings of ICPR 2004, August 23-26 , Cambridge, UK.) proposes a Gaussian mixture modeling method. In this algorithm, each pixel of the background is fitted to a Gaussian mixture model. For a new image, it is only necessary to determine whether each pixel obeys this Gaussian mixture model to determine whether the pixel is background or foreground. However, the disadvantages of the hybrid Gaussian algorithm are that it is relatively computationally intensive, slow and sensitive to light.2) The ViBe algorithm proposed in the article (ViBe: A universal backgroundsubtraction algorithm for video sequences.). The algorithm is very fast, the computation is relatively small, and it is robust to noise and has a good detection effect.

As I was doing some research on tracking checks recently, I used the ViBe algorithm, and wrote this python version of the algorithm based on the c++ version available on the web, which I'm sharing here.

class ViBe: 
 ''''' 
 classdocs 
 ''' 
 __defaultNbSamples = 20  # of samples per pixel point
 __defaultReqMatches = 2  #min index
 __defaultRadius = 20;   #Sqthere radius
 __defaultSubsamplingFactor = 16# Sub-sampling probability
 __BG = 0      # background pixels
 __FG = 255      # foreground pixels
 __c_xoff=[-1,0,1,-1,1,-1,0,1,0] Neighborhood points of #x len=9
 __c_yoff=[-1,0,1,-1,1,-1,0,1,0] Neighborhood points of #y len=9
  
 __samples=[]    # Save the sample value of each pixel point, len defaultNbSamples+1
 __Height = 0 
 __Width = 0 
 
 def __init__(self, grayFrame): 
  ''''' 
  Constructor 
  ''' 
  self.__Height = [0] 
  self.__Width = [1] 
   
 
  for i in range(self.__defaultNbSamples+1): 
   self.__samples.insert(i,(([0],[1]),dtype=)); 
    
  self.__init_params(grayFrame) 
  
 def __init_params(self,grayFrame): 
  # Record randomly generated rows (r) and columns (c)
  rand=0 
  r=0 
  c=0 
 
  # Initialize each pixel sample
  for y in range(self.__Height): 
   for x in range(self.__Width): 
    for k in range(self.__defaultNbSamples): 
     # Randomize pixel sample values
     rand=(0,8) 
     r=y+self.__c_yoff[rand] 
     if r<0: 
      r=0 
     if r>=self.__Height: 
      r=self.__Height-1 # rows
     c=x+self.__c_xoff[rand] 
     if c<0: 
      c=0 
     if c>=self.__Width: 
      c=self.__Width-1  # columns
     # Store pixel sample values
     self.__samples[k][y,x] = grayFrame[r,c] 
   self.__samples[self.__defaultNbSamples][y,x] = 0 
    
 def update(self,grayFrame,frameNo): 
  foreground = ((self.__Height,self.__Width),dtype=np.uint8) 
  for y in range(self.__Height): #Height 
   for x in range(self.__Width):  #Width 
    # Used to determine whether a point is a background point, index records the number of samples that have been compared, count indicates the number of matching samples.
    count=0;index=0; 
    dist=0.0; 
    while (count<self.__defaultReqMatches) and (index<self.__defaultNbSamples): 
     dist= float(grayFrame[y,x]) - float(self.__samples[index][y,x]); 
     if dist<0: dist=-dist 
     if dist<self.__defaultRadius: count = count+1 
     index = index+1 
 
    if count>=self.__defaultReqMatches: 
     # Judged as background pixels, only background points can be used to propagate and update stored sample values
     self.__samples[self.__defaultNbSamples][y,x]=0 
  
     foreground[y,x] = self.__BG 
  
     rand=(0,self.__defaultSubsamplingFactor) 
     if rand==0: 
      rand=(0,self.__defaultNbSamples) 
      self.__samples[rand][y,x]=grayFrame[y,x] 
     rand=(0,self.__defaultSubsamplingFactor) 
     if rand==0: 
      rand=(0,8) 
      yN=y+self.__c_yoff[rand] 
      if yN<0: yN=0 
      if yN>=self.__Height: yN=self.__Height-1 
      rand=(0,8) 
      xN=x+self.__c_xoff[rand] 
      if xN<0: xN=0 
      if xN>=self.__Width: xN=self.__Width-1 
      rand=(0,self.__defaultNbSamples) 
      self.__samples[rand][yN,xN]=grayFrame[y,x] 
    else: 
     # Judged as foreground pixels
     foreground[y,x] = self.__FG; 
     self.__samples[self.__defaultNbSamples][y,x] += 1 
     if self.__samples[self.__defaultNbSamples][y,x]>50: 
      rand=(0,self.__defaultNbSamples) 
      if rand==0: 
       rand=(0,self.__defaultNbSamples) 
       self.__samples[rand][y,x]=grayFrame[y,x] 
  return foreground 

A tracking effect of the fish I made

This is the whole content of this article.