Browse Source

refactor a fair bit

Dr-Swopt 6 days ago
parent
commit
1f1b5a7f78
5 changed files with 180 additions and 11 deletions
  1. 52 0
      face_recognition_logic.py
  2. 15 3
      grpc_client.py
  3. 5 8
      proto/face_recognition.proto
  4. BIN
      sample_aladdin.jpg
  5. 108 0
      server.py

+ 52 - 0
face_recognition_logic.py

@@ -0,0 +1,52 @@
+import os
+import tempfile
+from deepface import DeepFace
+
+EMPLOYEE_DB_PATH = "data/employees"
+DEFAULT_MODEL = "VGG-Face"
+DETECTOR_BACKEND = "opencv"
+
+def recognize_face(image_bytes, model_name=None):
+    model = model_name if model_name else DEFAULT_MODEL
+    temp_file = None
+    print("request image" + model_name)
+    try:
+        # Save incoming image to a temporary file
+        with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp:
+            temp_file = tmp.name
+            tmp.write(image_bytes)
+
+        # Run DeepFace search
+        result = DeepFace.find(
+            img_path=temp_file,
+            db_path=EMPLOYEE_DB_PATH,
+            detector_backend=DETECTOR_BACKEND,
+            model_name=model,
+            enforce_detection=False
+        )
+
+        if isinstance(result, list):
+            result = result[0]
+
+        if result is None or len(result) == 0:
+            return {"name": "Unknown", "confidence": 0.0, "image": b""}
+
+        # Best match
+        best_row = result.iloc[0]
+        matched_image_path = best_row["identity"]
+        name = os.path.splitext(os.path.basename(matched_image_path))[0]
+
+        # Distance metric key depends on model
+        key = f"{model}_cosine"
+        distance = best_row.get(key, 0.3)
+        confidence = float(max(0.0, 1.0 - distance))
+
+        # Read matched image bytes
+        with open(matched_image_path, "rb") as f:
+            matched_image_bytes = f.read()
+
+        return {"name": name, "confidence": confidence, "image": matched_image_bytes}
+
+    finally:
+        if temp_file and os.path.exists(temp_file):
+            os.remove(temp_file)

+ 15 - 3
grpc_client.py

@@ -1,14 +1,26 @@
 import grpc
-import face_recognition_pb2
-import face_recognition_pb2_grpc
+import sys
+import os
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), "proto"))
+from proto import face_recognition_pb2, face_recognition_pb2_grpc
 
+# Load the test image
 with open("sample_aladdin.jpg", "rb") as f:
     image_bytes = f.read()
 
+# Connect to gRPC server
 channel = grpc.insecure_channel("localhost:50051")
 stub = face_recognition_pb2_grpc.FaceRecognitionServiceStub(channel)
 
-response = stub.Recognize(face_recognition_pb2.FaceRequest(image=image_bytes))
+# Create request with model_name = "Facenet"
+request = face_recognition_pb2.FaceRequest(
+    image=image_bytes,
+    model_name="OpenFace"  # specify the model here
+)
 
+# Call the Recognize RPC
+response = stub.Recognize(request)
+
+# Print results
 print("Name:", response.name)
 print("Confidence:", response.confidence)

+ 5 - 8
proto/face_recognition.proto

@@ -5,16 +5,17 @@ package facerecognition;
 // The request message containing the image bytes
 message FaceRequest {
   bytes image = 1;
+  string model_name = 2; // optional: "VGG-Face", "FaceNet", "OpenFace"
 }
 
-// The response message containing recognition results, now includes image
+// The response message containing recognition results
 message FaceResponse {
   string name = 1;
   float confidence = 2;
-  bytes image = 3; // newly added: return matched employee image
+  bytes image = 3; // matched employee image
 }
 
-// New messages for enrollment
+// Enrollment messages
 message EnrollFaceRequest {
   bytes image = 1;
   string name = 2;
@@ -28,7 +29,7 @@ message EnrollFaceResponse {
 // Messages for getting all employees
 message Employee {
   string name = 1;
-  bytes image = 2; // enrolled photo
+  bytes image = 2;
 }
 
 message EmployeeListRequest {}
@@ -51,10 +52,6 @@ message DeleteEmployeeResponse {
 service FaceRecognitionService {
   rpc Recognize(FaceRequest) returns (FaceResponse);
   rpc EnrollFace(EnrollFaceRequest) returns (EnrollFaceResponse);
-
-  // Updated RPC to return employee name + photo
   rpc GetAllEmployees(EmployeeListRequest) returns (EmployeeListResponse);
-
-  // Fixed to match the message name
   rpc DeleteEmployee(DeleteRequest) returns (DeleteEmployeeResponse);
 }

BIN
sample_aladdin.jpg


+ 108 - 0
server.py

@@ -0,0 +1,108 @@
+from face_recognition_logic import recognize_face
+import os
+import sys
+import grpc
+from concurrent import futures
+
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), "proto"))
+from proto import face_recognition_pb2, face_recognition_pb2_grpc
+
+EMPLOYEE_DB_PATH = "data/employees"
+
+
+class FaceRecognitionServicer(face_recognition_pb2_grpc.FaceRecognitionServiceServicer):
+
+    def Recognize(self, request, context):
+        model_name = request.model_name if request.model_name else None
+        print("DEBUG request.ListFields() =")
+        print(f"[INFO] Received recognition request... {model_name}")
+        try:
+            result = recognize_face(request.image, model_name)
+            return face_recognition_pb2.FaceResponse(
+                name=result["name"],
+                confidence=result["confidence"],
+                image=result["image"]
+            )
+        except Exception as e:
+            print("[ERROR] Recognition failed:", e)
+            return face_recognition_pb2.FaceResponse(
+                name="Error",
+                confidence=0.0,
+                image=b""
+            )
+
+    def EnrollFace(self, request, context):
+        try:
+            name = request.name
+            image_bytes = request.image
+            if not name or not image_bytes:
+                return face_recognition_pb2.EnrollFaceResponse(
+                    success=False,
+                    message="Name or image missing"
+                )
+
+            os.makedirs(EMPLOYEE_DB_PATH, exist_ok=True)
+            file_path = os.path.join(EMPLOYEE_DB_PATH, f"{name}.jpg")
+            with open(file_path, "wb") as f:
+                f.write(image_bytes)
+
+            print(f"[INFO] Enrolled employee: {name}")
+            return face_recognition_pb2.EnrollFaceResponse(
+                success=True,
+                message="Enrollment successful"
+            )
+        except Exception as e:
+            print(f"[ERROR] Enrollment failed: {e}")
+            return face_recognition_pb2.EnrollFaceResponse(
+                success=False,
+                message=str(e)
+            )
+
+    def GetAllEmployees(self, request, context):
+        try:
+            employee_files = [
+                f for f in os.listdir(EMPLOYEE_DB_PATH)
+                if f.lower().endswith((".jpg", ".png", ".jpeg"))
+            ]
+            employees = []
+            for file in employee_files:
+                path = os.path.join(EMPLOYEE_DB_PATH, file)
+                name = os.path.splitext(file)[0]
+                with open(path, "rb") as f:
+                    image_bytes = f.read()
+                employees.append(face_recognition_pb2.Employee(
+                    name=name, image=image_bytes))
+
+            return face_recognition_pb2.EmployeeListResponse(employees=employees)
+        except Exception as e:
+            print("[ERROR] Failed to list employees:", e)
+            return face_recognition_pb2.EmployeeListResponse(employees=[])
+
+    def DeleteEmployee(self, request, context):
+        try:
+            found = False
+            for file in os.listdir(EMPLOYEE_DB_PATH):
+                if os.path.splitext(file)[0] == request.name:
+                    os.remove(os.path.join(EMPLOYEE_DB_PATH, file))
+                    found = True
+                    break
+            message = "Deleted successfully" if found else "Employee not found"
+            return face_recognition_pb2.DeleteEmployeeResponse(success=found, message=message)
+        except Exception as e:
+            print("[ERROR] Failed to delete employee:", e)
+            return face_recognition_pb2.DeleteEmployeeResponse(success=False, message=str(e))
+
+
+def serve():
+    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
+    face_recognition_pb2_grpc.add_FaceRecognitionServiceServicer_to_server(
+        FaceRecognitionServicer(), server)
+    server.add_insecure_port("[::]:50051")
+    server.start()
+    print("[INFO] gRPC Face Recognition server running on port 50051")
+    server.wait_for_termination()
+
+
+if __name__ == "__main__":
+    os.makedirs(EMPLOYEE_DB_PATH, exist_ok=True)
+    serve()