-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathremoveCamBg.py
116 lines (86 loc) · 4.13 KB
/
removeCamBg.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# see red_blue.py in the examples dir
import os
import pyfakewebcam
import numpy as np
import cv2
import argparse
import time
import logging
W = 640 # Picture width
H = 480 # Picture height
logging.basicConfig(level=logging.INFO)
def parseArgs():
parser = argparse.ArgumentParser(description="Read a webcam image and replace all background with pixels from a custom image.")
parser.add_argument('-b', '--background', help="Filename of the background image. By default, it's a noisy image", default=None)
parser.add_argument('-u', '--mask-update', help="Update the face mask every u frames", default=3, type=int)
parser.add_argument('-d', '--mask-decay', help="Upon losing the face, how fast shall the face fade away. Between 0 and 1. 0 Means to delete mask immediately, 1 means keep mask forever.", default=0.1, type=float)
parser.add_argument('-m', '--mask-max', help="Maximum blending factor of the detected face, between 0 and 1. 1 means the face is not transparent at all. 0 means face it not visible at all", type=float, default=1)
parser.add_argument('-c', '--camera-id', help="Id of the video capturing device to open. Will use 0 by default, that will open the default backend camera.", default=0, type=int)
parser.add_argument('-s', '--scale-mask', help="Scale the area of the detected face by this factor", default=1, type=float)
parser.add_argument("--debug", help="If set, show the resulting image in a debug window", action='store_true', default=False)
return parser.parse_args()
return None
class MaskBackground:
def __init__(self, args):
self.args = args
self.bgImg = self.loadBgImage(args.background)
self.face_cascade = cv2.CascadeClassifier(os.path.join(os.path.dirname(__file__), 'haarcascade_frontalface_default.xml'))
self.nr = 0
self.fgMask_float = 0
def createNoisyBg(self, W, H):
X = np.random.rand(H, W) * 256
return np.dstack([X]*3)
def loadBgImage(self, bgFile):
if bgFile is not None:
bg = cv2.imread(bgFile, cv2.IMREAD_COLOR)
else:
bg = self.createNoisyBg(W, H)
return cv2.resize(bg, (W, H))
def run(self, img):
if self.nr % self.args.mask_update == 0:
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Detect faces
faces = self.face_cascade.detectMultiScale(gray, 1.5, 4)
img2 = img / 256.0
fgMask = np.zeros((480, 640), dtype=np.uint8)
wMax = 0
biggest = None
# Code review: Extract rect extraction into extra function
for dim in faces:
if dim[2] > wMax:
wMax = dim[2]
biggest = dim
if biggest is not None:
(x, y, w, h) = biggest
cv2.ellipse(fgMask, (x+w//2, y+h//2), (int(w//1.5*self.args.scale_mask), int(h/1.2*self.args.scale_mask)), 0, 0, 360, 255, -1)
self.fgMask_float = cv2.GaussianBlur(fgMask / 256., (51, 51), 0) * self.args.mask_max
self.fgMask_float = np.dstack([self.fgMask_float]*3)
else:
self.fgMask_float *= self.args.mask_decay
result = (self.bgImg * (1-self.fgMask_float) + img * (self.fgMask_float)).astype(np.uint8)
self.nr = self.nr + 1
return result
def main():
args = parseArgs()
print (args)
camera = pyfakewebcam.FakeWebcam('/dev/video20', W, H)
cam = cv2.VideoCapture(args.camera_id)
masker = MaskBackground(args)
framesInLastSec = 0
start = time.time()
while True:
ret_val, img = cam.read()
result = masker.run(img)
# Code review: Extract debug stuff into extra function
if args.debug:
cv2.imshow("input", img)
cv2.imshow("result", result)
cv2.waitKey(1)
framesInLastSec = framesInLastSec + 1
if time.time() - start > 1:
logging.info(f"Processed {framesInLastSec} frames in 1 second")
framesInLastSec = 0
start = time.time()
camera.schedule_frame(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
if __name__ == '__main__':
main()