├── .gitignore ├── BACKGROUND SUBTRACTION.pdf ├── Background_Subtraction_GMM.py ├── Background_Subtraction_OpenCV.py ├── Documentation.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | -------------------------------------------------------------------------------- /BACKGROUND SUBTRACTION.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcauduro/Background-Substraction-using-GMM/624353da51c689c9c740276e33f099e70d8297df/BACKGROUND SUBTRACTION.pdf -------------------------------------------------------------------------------- /Background_Subtraction_GMM.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | class gaussian: 5 | def __init__(self): 6 | self.mean = np.zeros((1, 3)) 7 | self.covariance = 0 8 | self.weight = 0; 9 | self.Next = None 10 | self.Previous = None 11 | 12 | class Node: 13 | def __init__(self): 14 | self.pixel_s = None 15 | self.pixel_r = None 16 | self.no_of_components = 0 17 | self.Next = None 18 | 19 | class Node1: 20 | def __init__(self): 21 | self.gauss = None 22 | self.no_of_comp = 0 23 | self.Next = None 24 | 25 | covariance0 = 11.0 26 | def Create_gaussian(info1, info2, info3): 27 | ptr = gaussian() 28 | if (ptr is not None): 29 | ptr.mean[1, 1] = info1 30 | ptr.mean[1, 2] = info2 31 | ptr.mean[1, 3] = info3 32 | ptr.covariance = covariance0 33 | ptr.weight = 0.002 34 | ptr.Next = None 35 | ptr.Previous = None 36 | 37 | return ptr 38 | 39 | def Create_Node(info1, info2, info3): 40 | N_ptr = Node() 41 | if (N_ptr is not None): 42 | N_ptr.Next = None 43 | N_ptr.no_of_components = 1 44 | N_ptr.pixel_s = N_ptr.pixel_r = Create_gaussian(info1, info2, info3) 45 | 46 | return N_ptr 47 | 48 | List_node = [] 49 | def Insert_End_Node(n): 50 | List_node.append(n) 51 | 52 | List_gaussian = [] 53 | def Insert_End_gaussian(n): 54 | List_gaussian.append(n) 55 | 56 | def Delete_gaussian(n): 57 | List_gaussian.remove(n); 58 | 59 | class Process: 60 | def __init__(self, alpha, firstFrame): 61 | self.alpha = alpha 62 | self.background = firstFrame 63 | 64 | def get_value(self, frame): 65 | self.background = frame * self.alpha + self.background * (1 - self.alpha) 66 | return cv2.absdiff(self.background.astype(np.uint8), frame) 67 | 68 | def denoise(frame): 69 | frame = cv2.medianBlur(frame, 5) 70 | frame = cv2.GaussianBlur(frame, (5, 5), 0) 71 | 72 | return frame 73 | 74 | capture = cv2.VideoCapture(0) 75 | ret, orig_frame = capture.read( ) 76 | if ret is True: 77 | value1 = Process(0.1, denoise(orig_frame)) 78 | run = True 79 | else: 80 | run = False 81 | 82 | while (run): 83 | ret, frame = capture.read() 84 | value = False; 85 | if ret is True: 86 | cv2.imshow('input', denoise(frame)) 87 | grayscale = value1.get_value(denoise(frame)) 88 | ret, mask = cv2.threshold(grayscale, 15, 255, cv2.THRESH_BINARY) 89 | cv2.imshow('mask', mask) 90 | key = cv2.waitKey(10) & 0xFF 91 | else: 92 | break 93 | 94 | if key == 27: 95 | break 96 | 97 | if value == True: 98 | orig_frame = cv2.resize(orig_frame, (340, 260), interpolation=cv2.INTER_CUBIC) 99 | orig_frame = cv2.cvtColor(orig_frame, cv2.COLOR_BGR2GRAY) 100 | orig_image_row = len(orig_frame) 101 | orig_image_col = orig_frame[0] 102 | 103 | bin_frame = np.zeros((orig_image_row, orig_image_col)) 104 | value = [] 105 | 106 | for i in range(0, orig_image_row): 107 | for j in range(0, orig_image_col): 108 | N_ptr = Create_Node(orig_frame[i][0], orig_frame[i][1], orig_frame[i][2]) 109 | if N_ptr is not None: 110 | N_ptr.pixel_s.weight = 1.0 111 | Insert_End_Node(N_ptr) 112 | else: 113 | print("error") 114 | exit(0) 115 | 116 | nL = orig_image_row 117 | nC = orig_image_col 118 | 119 | dell = np.array((1, 3)); 120 | mal_dist = 0.0; 121 | temp_cov = 0.0; 122 | alpha = 0.002; 123 | cT = 0.05; 124 | cf = 0.1; 125 | cfbar = 1.0 - cf; 126 | alpha_bar = 1.0 - alpha; 127 | prune = -alpha * cT; 128 | cthr = 0.00001; 129 | var = 0.0 130 | muG = 0.0; 131 | muR = 0.0; 132 | muB = 0.0; 133 | dR = 0.0; 134 | dB = 0.0; 135 | dG = 0.0; 136 | rval = 0.0; 137 | gval = 0.0; 138 | bval = 0.0; 139 | 140 | while (1): 141 | duration3 = 0.0; 142 | count = 0; 143 | count1 = 0; 144 | List_node1 = List_node; 145 | counter = 0; 146 | duration = cv2.getTickCount( ); 147 | for i in range(0, nL): 148 | r_ptr = orig_frame[i] 149 | b_ptr = bin_frame[i] 150 | 151 | for j in range(0, nC): 152 | sum = 0.0; 153 | sum1 = 0.0; 154 | close = False; 155 | background = 0; 156 | 157 | rval = r_ptr[0][0]; 158 | gval = r_ptr[0][0]; 159 | bval = r_ptr[0][0]; 160 | 161 | start = List_node1[counter].pixel_s; 162 | rear = List_node1[counter].pixel_r; 163 | ptr = start; 164 | 165 | temp_ptr = None; 166 | if (List_node1[counter].no_of_component > 4): 167 | Delete_gaussian(rear); 168 | List_node1[counter].no_of_component = List_node1[counter].no_of_component - 1; 169 | 170 | for k in range(0, List_node1[counter].no_of_component): 171 | weight = List_node1[counter].weight; 172 | mult = alpha / weight; 173 | weight = weight * alpha_bar + prune; 174 | if (close == False): 175 | muR = ptr.mean[0]; 176 | muG = ptr.mean[1]; 177 | muB = ptr.mean[2]; 178 | 179 | dR = rval - muR; 180 | dG = gval - muG; 181 | dB = bval - muB; 182 | 183 | var = ptr.covariance; 184 | 185 | mal_dist = (dR * dR + dG * dG + dB * dB); 186 | 187 | if ((sum < cfbar) and (mal_dist < 16.0 * var * var)): 188 | background = 255; 189 | 190 | if (mal_dist < (9.0 * var * var)): 191 | weight = weight + alpha; 192 | if mult < 20.0 * alpha: 193 | mult = mult; 194 | else: 195 | mult = 20.0 * alpha; 196 | 197 | close = True; 198 | 199 | ptr.mean[0] = muR + mult * dR; 200 | ptr.mean[1] = muG + mult * dG; 201 | ptr.mean[2] = muB + mult * dB; 202 | temp_cov = var + mult * (mal_dist - var); 203 | if temp_cov < 5.0: 204 | ptr.covariance = 5.0 205 | else: 206 | if (temp_cov > 20.0): 207 | ptr.covariance = 20.0 208 | else: 209 | ptr.covariance = temp_cov; 210 | 211 | temp_ptr = ptr; 212 | 213 | if (weight < -prune): 214 | ptr = Delete_gaussian(ptr); 215 | weight = 0; 216 | List_node1[counter].no_of_component = List_node1[counter].no_of_component - 1; 217 | else: 218 | sum += weight; 219 | ptr.weight = weight; 220 | 221 | ptr = ptr.Next; 222 | 223 | if (close == False): 224 | ptr = gaussian( ); 225 | ptr.weight = alpha; 226 | ptr.mean[0] = rval; 227 | ptr.mean[1] = gval; 228 | ptr.mean[2] = bval; 229 | ptr.covariance = covariance0; 230 | ptr.Next = None; 231 | ptr.Previous = None; 232 | Insert_End_gaussian(ptr); 233 | List_gaussian.append(ptr); 234 | temp_ptr = ptr; 235 | List_node1[counter].no_of_components = List_node1[counter].no_of_components + 1; 236 | 237 | ptr = start; 238 | while (ptr != None): 239 | ptr.weight = ptr.weight / sum; 240 | ptr = ptr.Next; 241 | 242 | while (temp_ptr != None and temp_ptr.Previous != None): 243 | if (temp_ptr.weight <= temp_ptr.Previous.weight): 244 | break; 245 | else: 246 | next = temp_ptr.Next; 247 | previous = temp_ptr.Previous; 248 | if (start == previous): 249 | start = temp_ptr; 250 | previous.Next = next; 251 | temp_ptr.Previous = previous.Previous; 252 | temp_ptr.Next = previous; 253 | if (previous.Previous != None): 254 | previous.Previous.Next = temp_ptr; 255 | if (next != None): 256 | next.Previous = previous; 257 | else: 258 | rear = previous; 259 | previous.Previous = temp_ptr; 260 | 261 | temp_ptr = temp_ptr.Previous; 262 | 263 | List_node1[counter].pixel_s = start; 264 | List_node1[counter].pixel_r = rear; 265 | counter = counter + 1; 266 | 267 | capture.release() 268 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /Background_Subtraction_OpenCV.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | 4 | cap = cv2.VideoCapture(0) 5 | fgbg = cv2.createBackgroundSubtractorMOG2() 6 | 7 | while(1): 8 | ret, frame = cap.read() 9 | 10 | fgmask = fgbg.apply(frame) 11 | cv2.imshow('frame',fgmask) 12 | k = cv2.waitKey(30) & 0xff 13 | if k == 27: 14 | break 15 | 16 | cap.release() 17 | cv2.destroyAllWindows() 18 | -------------------------------------------------------------------------------- /Documentation.txt: -------------------------------------------------------------------------------- 1 | Language Used: Python 2 | 3 | Content: 4 | BACKGROUND SUBTRACTION PDF FILE: contains details anlysis, implementation, and observations. 5 | Background_Subtraction_GMM: implementation of Background subtraction using Gaussian Mixture Model. 6 | Background_Subtraction_OpenCV:implementation of Background subtraction using OpenCV libraries. 7 | 8 | Sources Help: 9 | Background Modeling using Mixture of Gaussians for Foreground 10 | Detection - A Survey 11 | T. Bouwmans, F. El Baf, B. Vachon -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Background-Substraction-using-GMM 2 | This include implementation of Background Substraction using Gaussian mixture model. For this, i followed the research paper of Thierry Bouwmans on Background Modelling. I have also implemented this using OpenCV library and then compared both of them. The algorithm of both method and comparison between them is shown in pdf attached with it. Both of the code is written in python. 3 | --------------------------------------------------------------------------------