File size: 3,444 Bytes
e9d9f4a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from fastapi import FastAPI
from pydantic import BaseModel
import cv2
from deepface import DeepFace
import tempfile
import requests
import shutil
import logging
from typing import Optional

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = FastAPI()

# Define the request model
class FaceVerificationRequest(BaseModel):
    id_url: str
    ref_url: str

def download_image(url: str) -> Optional[str]:
    """Downloads an image from a URL and saves it to a temporary file."""
    try:
        response = requests.get(url, stream=True)
        response.raise_for_status()  
        temp_path = tempfile.NamedTemporaryFile(delete=False, suffix=".jpg").name
        with open(temp_path, "wb") as f:
            shutil.copyfileobj(response.raw, f)
        logger.info(f"Image downloaded successfully: {url}")
        return temp_path
    except requests.exceptions.RequestException as e:
        logger.error(f"Failed to download image from {url}: {e}")
        return None

def detect_and_crop_face(image_path, detector_backend="mtcnn") -> Optional[str]:
    """Detects and crops the face from an image."""
    try:
        faces = DeepFace.extract_faces(img_path=image_path, detector_backend=detector_backend, enforce_detection=False)
        if not faces:
            logger.warning("No faces detected.")
            return None
        
        face_info = faces[0]
        facial_area = face_info.get("facial_area", {})
        if not facial_area:
            logger.warning("No valid facial area found.")
            return None
        
        x, y, w, h = facial_area["x"], facial_area["y"], facial_area["w"], facial_area["h"]
        image = cv2.imread(image_path)
        if image is None or w <= 0 or h <= 0:
            logger.error("Invalid face cropping dimensions.")
            return None
        
        cropped_face = image[y:y+h, x:x+w]
        temp_path = tempfile.NamedTemporaryFile(delete=False, suffix=".jpg").name
        cv2.imwrite(temp_path, cropped_face)
        logger.info(f"Face successfully cropped and saved at {temp_path}")
        return temp_path  
    except Exception as e:
        logger.error(f"Error during face detection: {e}")
        return None

@app.post("/verify")
async def verify_face(request: FaceVerificationRequest):
    """Verifies whether two faces belong to the same person."""
    try:
        id_path = download_image(request.id_url)
        ref_path = download_image(request.ref_url)
        
        if not id_path or not ref_path:
            return {"error": "Failed to download images."}
        
        cropped_face_path = detect_and_crop_face(id_path)
        if cropped_face_path:
            result = DeepFace.verify(
                img1_path=cropped_face_path, 
                img2_path=ref_path, 
                model_name="Facenet", 
                detector_backend="mtcnn"
            )
            threshold = 0.6  
            distance = result.get("distance", 1.0)
            is_match = distance < threshold
            
            logger.info(f"Face verification result: {result}")
            return {"match": is_match}
        else:
            return {"error": "Face detection failed for ID card image."}
    except Exception as e:
        logger.error(f"Verification failed: {e}")
        return {"error": str(e)}