def respond_to_server(self): while True: req = self.recv() if req is None: break elif req == "SCAN": camera.scan_face() elif req == "ALIVE": self.send("OK") info("[PING] Alive.")
def report(self): if len(self.reports) > 10: if self.is_connected: info("[Reporter] Reporting.") self.reports_col.insert_many(self.reports) self.reports = [] else: if not self.is_connecting: db_t = threading.Thread(target=self.connect_to_db) db_t.daemon = True db_t.start()
def update_recognizer(): global recognizer info("[Recognizer] Updating the recognizer instance.") faces: List[vision.Frame] = [] ids: List[str] = [] for student in database.students_info.all(): frame = vision.Frame.open_path( f"{data.KNOWN_FACES_PATH}/{student['face-path']}") faces.append(frame) ids.append(student['inserted-id']) recognizer = vision.FaceRecognizer(zip(faces, ids)) info("[Recognizer] Recognizer update finished.")
def scan_face(): info("[Scanner] Scanning.") success, db = get_mongo_client(database.mongo_remote_url) students_col = db.get_collection("students") while True: frame = current_frame.copy() faces = vision.FaceDetector.opencv(frame) if len(faces) == 0: connection.client.send("!") continue faces = vision.FaceDetector.ageitgey(frame) if len(faces) != 1: info("[Scanner] Detection failure.") connection.client.send("!") continue info("[Scanner] Successfully scanned a face.") connection.client.send("OK") break student_id = connection.client.recv() student_name = connection.client.recv() classroom = connection.client.recv() reload = connection.client.recv() == "RELOAD" face_bin = io.BytesIO() faces[0].write(face_bin, ".jpg") student = { "id": student_id, "name": student_name, "classroom": classroom, "face": face_bin.getvalue() } students_col.insert_one(student) if reload: database.sync_database() update_recognizer()
def sync_database(): success, db = get_mongo_client(mongo_remote_url) info("[Database] Syncing the local database.") if not success: info( "[Database] Cannot sync the local database, server is unavailable." ) return students_collection = db.get_collection("students") ids = [] for student in students_collection.find({}, {"face": 0}): inserted_id = str(student['_id']) res = students_info.search(tinydb.where('inserted-id') == inserted_id) ids.append(inserted_id) if len(res) == 1: continue info( f"[Database] Adding a new student to the database with id {student['id']}." ) face = students_collection.find_one({'_id': student['_id']}, {"face": 1})['face'] face = vision.Frame.open_bytes(face) relative_path = f"{inserted_id}.jpg" face.save(f"{data.KNOWN_FACES_PATH}/{relative_path}") students_info.insert({ 'inserted-id': inserted_id, 'id': student['id'], 'name': student['name'], 'classroom': student['classroom'], 'face-path': relative_path }) for student in students_info.all(): if student['inserted-id'] not in ids: students_info.remove( tinydb.where('inserted-id') == student['inserted-id']) info( f"[Database] Student with id {student['id']} is removed from the local database." ) info("[Database] Synchronization finished.")
def detect_students(self): frame = current_frame.copy() faces = vision.FaceDetector.opencv(frame) if len(faces) > 0: info(f"[Detector] Found {len(faces)} face(s).") for student_id, face in recognizer.recognize_threaded(faces): if isinstance(student_id, str): student_id = bson.ObjectId(student_id) timestamp = datetime.datetime.now(tz=data.tz) self.reports.append({ "pi-id": data.config["pi"]["pi-id"], "location": data.config["pi"]["location"], "student-id": student_id, "timestamp": timestamp }) info( f"[Detector] Detected a student with database-id {student_id}." ) if data.config["settings"]["save-images"]: path = f"{data.DETECTED_FACES_PATH}/{student_id}" if not os.path.isdir(path): os.mkdir(path) face.save(f"{path}/{timestamp}.jpg")
def connect_to_db(self): info("[Detector] Attempting to connect to the database.") self.is_connecting = True success, db = get_mongo_client(database.mongo_remote_url) if success: info("[Detector] Database connection is successful.") self.reports_col = db.get_collection("reports") self.is_connected = True else: info("[Detector] Database connection failed.") self.is_connected = False self.is_connecting = False
def recv_continuous_client(self): while True: req = self.recv() if req is None: break elif req == "UNBIND": self.selected_cam = None info(f"[Server] UNBIND request from {self.sock_name}") elif self.selected_cam is not None: self.selected_cam.send(req) if req == "SCAN": info( f"[Server] SCAN request from {self.sock_name} to {self.selected_cam.sock_name}" ) while True: res = self.selected_cam.recv() self.send(res) if res == "OK": break elif req == "CAMERAS": info(f"[Server] CAMERAS request from {self.sock_name}") self.server.check_alive(Role.Role_Camera) res = {"pi-id": [], "location": []} for cam in self.server.get_role(Role.Role_Camera): res["pi-id"].append(cam.pi_id) res["location"].append(cam.location) self.send(json.dumps(res)) elif req.startswith("BIND"): info(f"[Server] BIND request from {self.sock_name}") req = req.split("BIND ")[1] selected_cam = None for cam in self.server.get_role(Role.Role_Camera): if cam.pi_id == req: selected_cam = cam break if selected_cam is None: self.send("!") else: self.send("OK") self.selected_cam = selected_cam
def connect_to_server(): global is_connected_server global client info("[Client] Attempting to connect to the server.") client = Client(networking.create_tcp_socket()) status = client.connect(address[0], address[1]) if status == networking.ConnectionStatus.CONNECTION_FAILED: is_connected_server = False info("[Client] Server connection is failed. Connection failure.") return client.send(address[2]) client.send(address[3]) res = client.recv() if res != "OK": is_connected_server = False info("[Client] Server connection is failed. Unmet credentials.") return client.send("CAMERA") client.send(data.config['pi']['pi-id']) client.send(data.config['pi']['location']) is_connected_server = True info("[Client] Server connection is successful.")
def new_client(self, client: Client) -> bool: client.server = self client.sock_name = client.tcp_socket.getpeername() username = client.recv() password = client.recv() info( f"[Server] A new client attempted to connect: address: {client.sock_name}, username: {username}" ) res = database.users.search((tinydb.where("username") == username) & (tinydb.where("password") == password)) if len(res) != 1: client.send("!") info( f"[Server] Client connection failed. Wrong password or username. " f"address: {client.sock_name}") return False info( f"[Server] Client connection successful. address: {client.sock_name}" ) client.send("OK") pos = client.recv() if pos == "CAMERA": client.role = Role.Role_Camera client.pi_id = client.recv() client.location = client.recv() info( f"[Server] Client added as camera. address: {client.sock_name}" ) elif pos == "CLIENT": client.role = Role.Role_Client self.executor.submit(client.recv_continuous_client) info(f"[Server] Client added. address: {client.sock_name}") else: client.send("!") info(f"[Server] Client connection is refused. Didnt specify role. " f"address: {client.sock_name}") return False return True
def connection_broke(self): self.server.clients.remove(self) info(f"[Server] Client is no longer alive. address: {self.sock_name}")
def start(): info("[Server] Starting the server.") server = Server(Client) info("[Server] Listening for incoming connections.") server.listen(data.config["server"]["port"], data.config["server"]["host"])
def check_alive(self, role: Role): info("[Server] Pinging clients.") for cam in self.get_role(role): cam.is_alive()
def connection_broke(self): global is_connected_server info("[Client] Connection broken.") is_connected_server = False
def shutdown(): info("[RPi] Exiting.") detector.report()