cleardusk / 3DDFA_V2

The official PyTorch implementation of Towards Fast, Accurate and Stable 3D Dense Face Alignment, ECCV 2020.
MIT License
2.89k stars 511 forks source link

Negative dimensions problem #164

Open Devilben4 opened 7 hours ago

Devilben4 commented 7 hours ago

Hi,

with this code :

import sys
import os
import cv2
import torch
import numpy as np
sys.path.append('C:/Users/benkl/OneDrive/Documents/face recognition/3DDFA_V2')
from TDDFA import TDDFA
from utils.render import render
from utils.functions import crop_img
from Sim3DR import RenderPipeline

# Configuration
CONFIG_FP = 'configs/mb1_120x120.yml'  # Assurez-vous que ce chemin est correct
CHECKPOINT_FP = 'C:/Users/benkl/OneDrive/Documents/face recognition/3DDFA_V2/weights/mb1_120x120.pth'

# Initialisation de TDDFA
tddfa = TDDFA(gpu_mode=torch.cuda.is_available(), checkpoint_fp=CHECKPOINT_FP)
renderer = RenderPipeline()

# Capture vidéo
cap = cv2.VideoCapture(0)  # Changez l'index si nécessaire

def detect_faces(frame):
    """Détecter les visages dans le cadre en utilisant Haar Cascades."""
    face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
    return [face for face in faces]  # Retourne une liste de (x, y, w, h)

def clamp_roi_box(roi_box, frame_width, frame_height):
    """Limiter la boîte ROI aux limites du cadre."""
    if len(roi_box) != 4:
        raise ValueError(f"Expected ROI box with 4 elements, got {len(roi_box)} elements.")

    x, y, w, h = roi_box
    x = max(0, x)
    y = max(0, y)
    w = max(1, min(w, frame_width - x))
    h = max(1, min(h, frame_height - y))
    return (x, y, w, h)

def check_valid_dimensions(roi_box, frame_width, frame_height):
    """Valider les dimensions de la boîte ROI."""
    if len(roi_box) != 4:
        raise ValueError(f"Expected ROI box with 4 elements, got {len(roi_box)} elements.")

    x, y, w, h = roi_box
    if w <= 0 or h <= 0:
        raise ValueError("Invalid ROI box dimensions: width or height cannot be negative or zero.")
    if x < 0 or y < 0 or x + w > frame_width or y + h > frame_height:
        raise ValueError("ROI box is out of frame boundaries.")

def crop_img_safe(img, box):
    """Recadrer l'image en toute sécurité en fonction des coordonnées de la boîte."""
    if len(box) != 4:
        raise ValueError(f"Expected box with 4 elements, got {len(box)} elements.")

    x, y, w, h = box
    x = int(x)
    y = int(y)
    w = int(w)
    h = int(h)

    # S'assurer que les coordonnées sont dans les limites de l'image
    x_end = min(x + w, img.shape[1])
    y_end = min(y + h, img.shape[0])

    # Validation supplémentaire pour éviter les dimensions négatives
    if x < 0 or y < 0 or x_end <= x or y_end <= y:
        raise ValueError("Invalid crop coordinates resulting in negative or zero dimensions.")

    return img[y:y_end, x:x_end]

try:
    while True:
        ret, frame = cap.read()
        if not ret:
            print("Failed to capture video")
            break

        frame_height, frame_width = frame.shape[:2]
        print(f"Frame dimensions: width={frame_width}, height={frame_height}")

        # Détecter les visages dans le cadre
        boxes = detect_faces(frame)

        if boxes:
            box = boxes[0]  # Traiter seulement le premier visage détecté
            try:
                # Limiter et valider la boîte ROI de la détection
                clamped_box = clamp_roi_box(box, frame_width, frame_height)
                print(f"Clamped detected box: {clamped_box}")
                check_valid_dimensions(clamped_box, frame_width, frame_height)

                # Recadrer la région du visage
                cropped_face = crop_img_safe(frame, clamped_box)
                print(f"Cropped face shape: {cropped_face.shape}")

                # Traitement avec 3DDFA
                param_lst, roi_box_lst = tddfa(frame, [clamped_box])
                print(f"ROI boxes from TDDFA: {roi_box_lst}")

                # Limiter les boîtes ROI de TDDFA
                clamped_roi_box_lst = []
                for roi_box in roi_box_lst:
                    clamped_box = clamp_roi_box(roi_box, frame_width, frame_height)
                    print(f"Clamped ROI box: {clamped_box}")
                    clamped_roi_box_lst.append(clamped_box)

                # Valider les boîtes ROI clamped
                for clamped_box in clamped_roi_box_lst:
                    check_valid_dimensions(clamped_box, frame_width, frame_height)

                # Reconstruction 3D
                vertices_lst = tddfa.recon_vers(param_lst, clamped_roi_box_lst)

                # Rendu du visage 3D
                img = render(frame, [vertices_lst[0]], tddfa.tri, show_flag=False)
                cv2.imshow('3DDFA Render', img)

            except Exception as e:
                print(f"An error occurred during 3DDFA processing: {e}")

        # Afficher les résultats avec des rectangles autour des visages détectés
        for (x, y, w, h) in boxes:
            cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)
        cv2.imshow('Face Detection', frame)

        # Quitter si 'q' est pressé
        if cv2.waitKey(1) & 0xFF == ord('q'):
            print("Exiting...")
            break

except KeyboardInterrupt:
    print("Interrupted by user")

finally:
    cap.release()
    cv2.destroyAllWindows()

i got : An error occurred during 3DDFA processing: negative dimensions are not allowed

can someone tell me why ?

Devilben4 commented 4 hours ago

Actually i dodge it, but now my main problem is :

with this code :

# test_3ddfa.py

import sys
import os
import cv2
import torch
import numpy as np
from datetime import datetime

# Append the 3DDFA_V2 path
# Assurez-vous que le chemin ci-dessous pointe vers le répertoire racine de 3DDFA_V2
sys.path.append('C:/Users/benkl/OneDrive/Documents/face recognition/3DDFA_V2')

from TDDFA import TDDFA
from utils.render import render
from utils.functions import crop_img
from Sim3DR import RenderPipeline

def clamp_roi_box(roi_box, frame_width, frame_height):
    """Clamp the ROI box within the frame boundaries."""
    if len(roi_box) != 4:
        raise ValueError(f"Expected ROI box with 4 elements, got {len(roi_box)} elements.")

    x, y, w, h = roi_box
    x = max(0, x)
    y = max(0, y)
    w = max(1, min(w, frame_width - x))  # Ensure width is at least 1
    h = max(1, min(h, frame_height - y))  # Ensure height is at least 1
    return (x, y, w, h)

def detect_faces(frame):
    """Detect faces in the frame using Haar Cascades."""
    face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
    print(f"Detected faces: {faces}")
    return [face for face in faces]  # Return list of (x, y, w, h)

def process_image(image_path, output_dir, tddfa, renderer):
    """Process a single image to generate and save the UV map."""
    # Charger l'image
    frame = cv2.imread(image_path)
    if frame is None:
        print(f"Error: Could not load image {image_path}")
        return

    frame_height, frame_width = frame.shape[:2]
    print(f"Processing image: {image_path}")
    print(f"Image dimensions: width={frame_width}, height={frame_height}")

    # Détecter les visages
    boxes = detect_faces(frame)
    if not boxes:
        print("No faces detected.")
        return

    # Traiter le premier visage détecté
    box = boxes[0]
    print(f"Detected face box: {box}")

    # Clamp et valider la ROI box
    clamped_box = clamp_roi_box(box, frame_width, frame_height)
    print(f"Clamped ROI box: {clamped_box}")

    # Générer les paramètres 3D
    param_lst, roi_box_lst = tddfa(frame, [clamped_box])
    print(f"3D parameters: {param_lst}")

    # Clamp les ROI boxes de TDDFA
    clamped_roi_box_lst = [clamp_roi_box(roi_box, frame_width, frame_height) for roi_box in roi_box_lst]
    print(f"Clamped ROI boxes from TDDFA: {clamped_roi_box_lst}")

    # Reconstruire les vertices 3D
    vertices_lst = tddfa.recon_vers(param_lst, clamped_roi_box_lst)
    print("3D vertices reconstructed.")

    # Rendre le visage 3D
    img = render(frame, [vertices_lst[0]], tddfa.tri, show_flag=False)
    print("3D face rendered.")

    # Générer la texture map en recadrant la région du visage
    texture_map = crop_img(frame, clamped_roi_box_lst[0])
    print(f"Cropped texture map shape: {texture_map.shape}")

    if texture_map.size == 0:
        print("Error: Cropped texture map is empty.")
        return

    # Sauvegarder la UV map
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    uv_map_filename = os.path.join(output_dir, f"uv_map_{timestamp}.png")
    cv2.imwrite(uv_map_filename, texture_map)
    print(f"UV map saved to {uv_map_filename}")

    # Afficher la UV map
    cv2.imshow("UV Map", texture_map)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

def main():
    # ============================
    # === Définir les Chemins ===
    # ============================

    # 1. Chemin vers le fichier de configuration
    # Assurez-vous que ce fichier existe dans le répertoire spécifié
    CONFIG_FP = 'C:/Users/benkl/OneDrive/Documents/face recognition/3DDFA_V2/configs/mb1_120x120.yml'  # Exemple : 'configs/mb1_120x120.yml'

    # 2. Chemin vers le checkpoint (poids du modèle)
    # Assurez-vous que ce fichier existe dans le répertoire spécifié
    CHECKPOINT_FP = 'C:/Users/benkl/OneDrive/Documents/face recognition/3DDFA_V2/weights/mb1_120x120.pth'  # Exemple : 'weights/mb1_120x120.pth'

    # 3. Chemin vers l'image d'entrée
    # Placez votre image dans le répertoire spécifié ou ajustez le chemin en conséquence
    IMAGE_PATH = 'C:/Users/benkl/OneDrive/Documents/face recognition/UV_Maps/visage.png'  # Exemple : 'images/trump_hillary.jpg'

    # 4. Répertoire pour sauvegarder les UV maps
    OUTPUT_DIR = 'C:/Users/benkl/OneDrive/Documents/face recognition/UV_Maps'  # Vous pouvez choisir un autre nom ou chemin

    # ===========================================
    # === Vérifier et Créer les Répertoires ===
    # ===========================================

    # Créer le répertoire de sortie si nécessaire
    os.makedirs(OUTPUT_DIR, exist_ok=True)

    # Vérifier l'existence du fichier de configuration
    if not os.path.isfile(CONFIG_FP):
        print(f"Error: Configuration file not found at {CONFIG_FP}")
        sys.exit(1)

    # Vérifier l'existence du checkpoint
    if not os.path.isfile(CHECKPOINT_FP):
        print(f"Error: Checkpoint file not found at {CHECKPOINT_FP}")
        sys.exit(1)

    # Vérifier l'existence de l'image d'entrée
    if not os.path.isfile(IMAGE_PATH):
        print(f"Error: Input image not found at {IMAGE_PATH}")
        sys.exit(1)

    # ===================================
    # === Configuration de l'Appareil ===
    # ===================================

    DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    print(f"Using device: {DEVICE}")

    # ===========================
    # === Initialiser TDDFA ===
    # ===========================

    print("Initializing TDDFA...")
    tddfa = TDDFA(
        gpu_mode=torch.cuda.is_available(),
        checkpoint_fp=CHECKPOINT_FP,
        arch='mobilenet',  # Assurez-vous que c'est l'architecture correcte
        size=120  # Taille correspondant au checkpoint
    )
    print("TDDFA initialized.")

    # =================================
    # === Initialiser RenderPipeline ===
    # =================================

    print("Initializing RenderPipeline...")
    renderer = RenderPipeline()
    print("RenderPipeline initialized.")

    # ================================
    # === Traiter l'Image d'Exemple ===
    # ================================

    process_image(IMAGE_PATH, OUTPUT_DIR, tddfa, renderer)

if __name__ == "__main__":
    main()

My python always crash

Devilben4 commented 4 hours ago

I just want to have the UV map ... :(