# Annexe : Application - Caméra

## Rôle et utilité

`apps/camera/app.py` est une application utilitaire permettant de visualiser le flux vidéo d'une webcam branchée à l'ordinateur, et d'enregistrer des photos. C'est une démonstration brillante de la capacité de GrimOS à s'interfacer avec du matériel externe.

## Implémentation technique

- La bibliothèque `cv2` (OpenCV) : Cette application est l'une des rares à nécessiter une dépendance lourde externe. Elle utilise `cv2.VideoCapture(0)` pour capturer le flux matériel de la première caméra détectée par le système Linux (`/dev/video0`).
- Conversion d'image en temps réel : Tkinter ne sait pas afficher un flux vidéo brut. Le script doit donc, dans une boucle très rapide (`window.after(15)`), capturer l'image de la webcam, convertir ses couleurs de BGR (le format d'OpenCV) vers RGB, puis transformer cette matrice en une image compatible avec l'interface via `ImageTk.PhotoImage`.
- Nettoyage mémoire : Le flux vidéo consommant beaucoup de ressources, l'application veille à libérer l'accès à la caméra (`cap.release()`) lorsque l'utilisateur ferme la fenêtre, évitant ainsi un crash matériel persistant.

## Pistes de modification

- Mode Enregistrement Vidéo : L'application actuelle ne prend que des photos. En exploitant la classe `cv2.VideoWriter`, on pourrait ajouter un bouton rouge "REC" permettant d'enregistrer des vidéos au format MP4 directement sur le disque.
- Filtres en direct : Toujours grâce à OpenCV, on pourrait ajouter une barre d'outils offrant des effets amusants en temps réel (Noir et Blanc, effet miroir, détection de contours) avant l'affichage dans le cadre Tkinter.

## Code Source

    import tkinter as tk
    from tkinter import messagebox
    from PIL import Image, ImageTk
    import os
    import datetime

    def start(window, app_manager=None, **kwargs):
        # Essayons d'importer cv2. S'il n'est pas là, on affiche un message d'erreur clair.
        try:
            import cv2
        except ImportError:
            tk.Label(window, text="La librairie OpenCV n'est pas installée.\n\nVeuillez exécuter :\nsudo apt-get install python3-opencv\n\npuis relancez l'application.", fg="red", font=("Arial", 12)).pack(expand=True)
            return

        top_frame = tk.Frame(window, bg="lightgray", height=40)
        top_frame.pack(side="top", fill="x")

        icon_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "icons")
        window.icons = getattr(window, "icons", {})
        if 'btn_camera' not in window.icons:
            ipath = os.path.join(icon_dir, "btn_camera.png")
            if os.path.exists(ipath):
                window.icons['btn_camera'] = tk.PhotoImage(file=ipath)

        video_container = tk.Frame(window, bg="black")
        video_container.pack(fill="both", expand=True)

        video_lbl = tk.Label(video_container, bg="black")
        video_lbl.pack(expand=True)

        try:
            cap = cv2.VideoCapture(0)
        except Exception as e:
            messagebox.showerror("Erreur", f"Impossible d'accéder à la webcam : {e}")
            return

        if not cap.isOpened():
            messagebox.showerror("Erreur", "Aucune webcam détectée sur /dev/video0.")
            return

        def update_frame():
            if not window.winfo_exists():
                cap.release()
                return

            ret, frame = cap.read()
            if ret:
                # OpenCV utilise BGR, ImageTk nécessite RGB
                frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                img = Image.fromarray(frame_rgb)
                imgtk = ImageTk.PhotoImage(image=img)

                video_lbl.imgtk = imgtk # garder la référence
                video_lbl.configure(image=imgtk)

            window.after(30, update_frame)

        def take_photo():
            ret, frame = cap.read()
            if ret:
                img_dir = os.path.expanduser("~/Images")
                os.makedirs(img_dir, exist_ok=True)
                timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
                filename = f"photo_{timestamp}.jpg"
                filepath = os.path.join(img_dir, filename)

                cv2.imwrite(filepath, frame)

                if app_manager and hasattr(app_manager, 'desktop'):
                    app_manager.desktop.show_toast(f"Photo sauvegardée :\n{filepath}")

        btn_photo = tk.Button(top_frame, text=" Prendre une photo", image=window.icons.get('btn_camera'), compound="left", font=("Arial", 11, "bold"), bg="#4CAF50", fg="white", relief="flat", command=take_photo)
        btn_photo.pack(side="left", padx=10, pady=5)

        def on_destroy(event):
            if str(event.widget) == str(window):
                if cap.isOpened():
                    cap.release()

        window.bind("<Destroy>", on_destroy)
        update_frame()