// Dans un store Pinia (stores/annotationStore.js) import { defineStore } from 'pinia' import { v4 as uuidv4 } from 'uuid' export const useAnnotationStore = defineStore('annotations', { state: () => ({ // Session courante avec métadonnées vidéo currentSession: { id: 'session-1', name: 'Session d\'annotation', videoId: null, video: null, // Nom du fichier vidéo metadata: { duration: 0, width: 0, height: 0, fps: 30, date: new Date().toISOString() } }, // Dictionnaire des objets objects: { // Format: "1": { id: "1", name: "Objet 1", color: "#4f056f" } }, // Compteur pour les IDs d'objets objectIdCounter: 1, // Annotations par frame frameAnnotations: {}, // Format: { // "0": [ // { // id: "uuid", // objectId: "1", // type: "mask", // mask: "base64...", // maskScore: 0.91, // maskImageSize: { width: 1920, height: 1080 }, // points: [{ x: 1270, y: 405, type: "positive" }] // }, // { // id: "uuid", // objectId: "2", // type: "rectangle", // x: 100, // y: 100, // width: 200, // height: 150 // } // ] // } selectedObjectId: null, temporaryPoints: [] }), getters: { getTemporaryPointsForObject: (state) => (objectId) => { return state.temporaryPoints.filter(point => point.objectId === objectId) } }, actions: { // Sélectionner un objet selectObject(objectId) { this.selectedObjectId = objectId console.log(`Objet sélectionné: ${objectId}`) }, // Désélectionner l'objet actuel deselectObject() { this.selectedObjectId = null }, // Mettre à jour les métadonnées de la vidéo updateVideoMetadata(metadata) { this.currentSession.metadata = { ...this.currentSession.metadata, ...metadata } }, // Ajouter une annotation pour l'objet sélectionné à la frame actuelle addAnnotation(frameNumber, annotation) { const id = uuidv4() let newAnnotation if (annotation.type === 'mask') { newAnnotation = { id, objectId: this.selectedObjectId, type: 'mask', mask: annotation.mask || '', maskScore: annotation.maskScore || 0, maskImageSize: annotation.maskImageSize || { width: this.currentSession.metadata.width, height: this.currentSession.metadata.height }, points: annotation.points || [] } } else if (annotation.type === 'rectangle') { newAnnotation = { id, objectId: this.selectedObjectId, type: 'rectangle', x: annotation.x, y: annotation.y, width: annotation.width, height: annotation.height } } else if (annotation.type === 'point') { newAnnotation = { id, objectId: this.selectedObjectId, type: 'point', x: annotation.x, y: annotation.y, pointType: annotation.pointType // 'positive' ou 'negative' } } else { // Gestion par défaut pour les autres types newAnnotation = { id, objectId: this.selectedObjectId, ...annotation } } // Vérifier que newAnnotation a été créée if (!newAnnotation) { console.error('Erreur: impossible de créer l\'annotation', annotation) return null } if (!this.frameAnnotations[frameNumber]) { this.frameAnnotations[frameNumber] = [] } this.frameAnnotations[frameNumber].push(newAnnotation) console.log('Annotation ajoutée:', newAnnotation) return id }, updateAnnotation(frameNumber, annotationId, updates) { if (!this.frameAnnotations[frameNumber]) return const annotationIndex = this.frameAnnotations[frameNumber].findIndex( a => a.id === annotationId ) if (annotationIndex === -1) return // Mettre à jour l'annotation avec les nouvelles propriétés this.frameAnnotations[frameNumber][annotationIndex] = { ...this.frameAnnotations[frameNumber][annotationIndex], ...updates } }, // Ajouter un nouvel objet addObject(objectData = {}) { const objectId = `${this.objectIdCounter++}` this.objects[objectId] = { id: objectId, name: objectData.name || `Objet ${this.objectIdCounter - 1}`, color: objectData.color || this.getRandomColor(), // Autres propriétés selon vos besoins } // Sélectionner automatiquement le nouvel objet this.selectObject(objectId) return objectId }, // Récupérer les annotations pour une frame getAnnotationsForFrame(frameNumber) { return this.frameAnnotations[frameNumber.toString()] || [] }, // Supprimer une annotation removeAnnotation(frameNumber, annotationId) { const frameKey = frameNumber.toString() if (this.frameAnnotations[frameKey]) { this.frameAnnotations[frameKey] = this.frameAnnotations[frameKey] .filter(a => a.id !== annotationId) } }, // Nouvelle méthode pour supprimer tous les masques d'un objet sur une frame removeMasksForObject(frameNumber, objectId) { const frameKey = frameNumber.toString() if (this.frameAnnotations[frameKey]) { this.frameAnnotations[frameKey] = this.frameAnnotations[frameKey] .filter(a => !(a.objectId === objectId && a.type === 'mask')) } }, // Vérifier si un objet a encore des annotations sur une frame hasAnnotationsForObject(frameNumber, objectId) { const frameKey = frameNumber.toString() if (!this.frameAnnotations[frameKey]) return false return this.frameAnnotations[frameKey] .some(a => a.objectId === objectId) }, // Générer une couleur aléatoire getRandomColor() { return '#' + Math.floor(Math.random()*16777215).toString(16).padStart(6, '0') }, // Sauvegarder les annotations dans le format demandé saveAnnotations() { const data = { video: this.currentSession.video, metadata: this.currentSession.metadata, objects: this.objects, annotations: this.frameAnnotations } localStorage.setItem('annotations', JSON.stringify(data)) }, // Charger les annotations depuis le format demandé loadAnnotations() { const saved = localStorage.getItem('annotations') if (saved) { const data = JSON.parse(saved) this.currentSession.video = data.video this.currentSession.metadata = data.metadata this.objects = data.objects this.frameAnnotations = data.annotations } }, getAnnotation(frameNumber, annotationId) { if (!this.frameAnnotations[frameNumber]) return null return this.frameAnnotations[frameNumber].find(a => a.id === annotationId) || null }, addTemporaryPoint(point) { // Ajouter un ID unique au point const pointWithId = { ...point, id: uuidv4() } this.temporaryPoints.push(pointWithId) return pointWithId.id }, removeTemporaryPoint(pointId) { const index = this.temporaryPoints.findIndex(p => p.id === pointId) if (index !== -1) { this.temporaryPoints.splice(index, 1) } }, clearTemporaryPoints() { this.temporaryPoints = [] }, // Supprimer un objet et toutes ses annotations deleteObject(objectId) { // Supprimer l'objet du dictionnaire delete this.objects[objectId] // Supprimer toutes les annotations associées à cet objet Object.keys(this.frameAnnotations).forEach(frameKey => { this.frameAnnotations[frameKey] = this.frameAnnotations[frameKey] .filter(annotation => annotation.objectId !== objectId) }) // Si l'objet supprimé était sélectionné, désélectionner if (this.selectedObjectId === objectId) { this.selectedObjectId = null } // Supprimer les points temporaires associés à cet objet this.temporaryPoints = this.temporaryPoints.filter(point => point.objectId !== objectId) } } })