2nzi commited on
Commit
636d817
·
verified ·
1 Parent(s): ae94c0d

_objects export file

Browse files
Files changed (1) hide show
  1. src/components/EmptyView.vue +276 -276
src/components/EmptyView.vue CHANGED
@@ -1,277 +1,277 @@
1
- <template>
2
- <div class="export-view">
3
- <div class="export-content">
4
- <div class="export-header">
5
- <h3>Export</h3>
6
- </div>
7
-
8
- <div class="export-info">
9
- <div class="info-row">
10
- <span>{{ objectCount }} objets, {{ annotationCount }} annotations</span>
11
- </div>
12
- <div class="info-row filename">
13
- <span>{{ fileName }}</span>
14
- </div>
15
- </div>
16
-
17
- <div class="export-actions">
18
- <button
19
- class="export-button"
20
- @click="exportAnnotations"
21
- :disabled="!hasAnnotations"
22
- >
23
- <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
24
- <path d="M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z"/>
25
- </svg>
26
- Télécharger
27
- </button>
28
-
29
- <p v-if="!hasAnnotations" class="no-data-message">
30
- Aucune donnée à exporter
31
- </p>
32
- </div>
33
- </div>
34
- </div>
35
- </template>
36
-
37
- <script>
38
- import { useAnnotationStore } from '@/stores/annotationStore'
39
- import { useVideoStore } from '@/stores/videoStore'
40
- import { computed } from 'vue'
41
-
42
- export default {
43
- name: 'EmptyView',
44
-
45
- setup() {
46
- const annotationStore = useAnnotationStore()
47
- const videoStore = useVideoStore()
48
-
49
- const videoName = computed(() => {
50
- if (videoStore.selectedVideo?.name) {
51
- return videoStore.selectedVideo.name.replace(/\.[^/.]+$/, '') // Enlever l'extension
52
- }
53
- return 'default_video'
54
- })
55
-
56
- const fileName = computed(() => {
57
- return `${videoName.value}_config.json`
58
- })
59
-
60
- const objectCount = computed(() => {
61
- return Object.keys(annotationStore.objects).length
62
- })
63
-
64
- const annotationCount = computed(() => {
65
- let count = 0
66
- Object.values(annotationStore.frameAnnotations).forEach(frameAnnotations => {
67
- count += frameAnnotations.length
68
- })
69
- return count
70
- })
71
-
72
- const hasAnnotations = computed(() => {
73
- return annotationCount.value > 0
74
- })
75
-
76
- const exportAnnotations = () => {
77
- // Créer la structure objects selon le format demandé
78
- const objects = Object.values(annotationStore.objects).map(obj => {
79
- const objData = {
80
- obj_id: parseInt(obj.id)
81
- }
82
-
83
- // Analyser le label pour extraire le type et l'équipe
84
- if (obj.label) {
85
- const label = obj.label.toLowerCase()
86
-
87
- if (label.includes('ball')) {
88
- objData.obj_type = 'ball'
89
- objData.team = null
90
- } else if (label.includes('player')) {
91
- objData.obj_type = 'player'
92
-
93
- // Extraire le numéro d'équipe
94
- if (label.includes('team 1') || label.includes('team1')) {
95
- objData.team = 1
96
- } else if (label.includes('team 2') || label.includes('team2')) {
97
- objData.team = 2
98
- } else {
99
- objData.team = null
100
- }
101
- } else {
102
- objData.obj_type = null
103
- objData.team = null
104
- }
105
- } else {
106
- objData.obj_type = null
107
- objData.team = null
108
- }
109
-
110
- return objData
111
- })
112
-
113
- // Créer la structure initial_annotations selon le format demandé
114
- const initial_annotations = []
115
-
116
- // Parcourir toutes les frames qui ont des annotations
117
- Object.keys(annotationStore.frameAnnotations).forEach(frameNumber => {
118
- const frameAnnotations = annotationStore.frameAnnotations[frameNumber]
119
- const frameData = {
120
- frame: parseInt(frameNumber),
121
- annotations: []
122
- }
123
-
124
- // Grouper les annotations par objet pour cette frame
125
- const annotationsByObject = {}
126
- frameAnnotations.forEach(annotation => {
127
- if (!annotationsByObject[annotation.objectId]) {
128
- annotationsByObject[annotation.objectId] = []
129
- }
130
-
131
- // Extraire les points selon le type d'annotation
132
- if (annotation.type === 'point') {
133
- annotationsByObject[annotation.objectId].push({
134
- x: Math.round(annotation.x),
135
- y: Math.round(annotation.y),
136
- label: annotation.pointType === 'positive' ? 1 : 0
137
- })
138
- } else if (annotation.type === 'mask' && annotation.points) {
139
- // Ajouter tous les points du masque
140
- annotation.points.forEach(point => {
141
- annotationsByObject[annotation.objectId].push({
142
- x: Math.round(point.x),
143
- y: Math.round(point.y),
144
- label: point.type === 'positive' ? 1 : 0
145
- })
146
- })
147
- }
148
- })
149
-
150
- // Créer les annotations pour cette frame
151
- Object.keys(annotationsByObject).forEach(objectId => {
152
- const points = annotationsByObject[objectId]
153
- if (points.length > 0) {
154
- frameData.annotations.push({
155
- obj_id: parseInt(objectId),
156
- points: points
157
- })
158
- }
159
- })
160
-
161
- // Ajouter la frame seulement si elle a des annotations
162
- if (frameData.annotations.length > 0) {
163
- initial_annotations.push(frameData)
164
- }
165
- })
166
-
167
- // Structure finale selon le format demandé
168
- const exportData = {
169
- objects: objects,
170
- initial_annotations: initial_annotations
171
- }
172
-
173
- // Créer le blob et le télécharger
174
- const jsonString = JSON.stringify(exportData, null, 2)
175
- const blob = new Blob([jsonString], { type: 'application/json' })
176
- const url = URL.createObjectURL(blob)
177
-
178
- const link = document.createElement('a')
179
- link.href = url
180
- link.download = fileName.value
181
- document.body.appendChild(link)
182
- link.click()
183
- document.body.removeChild(link)
184
- URL.revokeObjectURL(url)
185
-
186
- console.log('Annotations exportées:', fileName.value)
187
- }
188
-
189
- return {
190
- videoName,
191
- fileName,
192
- objectCount,
193
- annotationCount,
194
- hasAnnotations,
195
- exportAnnotations
196
- }
197
- }
198
- }
199
- </script>
200
-
201
- <style scoped>
202
- .export-view {
203
- height: 100%;
204
- display: flex;
205
- align-items: center;
206
- justify-content: center;
207
- color: white;
208
- padding: 20px;
209
- }
210
-
211
- .export-content {
212
- text-align: center;
213
- width: 100%;
214
- }
215
-
216
- .export-header {
217
- margin-bottom: 20px;
218
- }
219
-
220
- .export-header h3 {
221
- margin: 0;
222
- font-size: 1rem;
223
- color: #fff;
224
- font-weight: 500;
225
- }
226
-
227
- .export-info {
228
- margin-bottom: 20px;
229
- }
230
-
231
- .info-row {
232
- margin-bottom: 8px;
233
- color: #ccc;
234
- font-size: 0.9rem;
235
- }
236
-
237
- .info-row.filename {
238
- color: #fff;
239
- font-family: monospace;
240
- font-size: 0.8rem;
241
- }
242
-
243
- .export-actions {
244
- text-align: center;
245
- }
246
-
247
- .export-button {
248
- display: inline-flex;
249
- align-items: center;
250
- gap: 6px;
251
- padding: 8px 16px;
252
- background: #4a4a4a;
253
- color: white;
254
- border: none;
255
- border-radius: 4px;
256
- font-size: 0.8rem;
257
- cursor: pointer;
258
- transition: background 0.2s;
259
- }
260
-
261
- .export-button:hover:not(:disabled) {
262
- background: #5a5a5a;
263
- }
264
-
265
- .export-button:disabled {
266
- background: #3c3c3c;
267
- color: #666;
268
- cursor: not-allowed;
269
- }
270
-
271
- .no-data-message {
272
- margin: 12px 0 0 0;
273
- color: #666;
274
- font-size: 0.8rem;
275
- font-style: italic;
276
- }
277
  </style>
 
1
+ <template>
2
+ <div class="export-view">
3
+ <div class="export-content">
4
+ <div class="export-header">
5
+ <h3>Export</h3>
6
+ </div>
7
+
8
+ <div class="export-info">
9
+ <div class="info-row">
10
+ <span>{{ objectCount }} objets, {{ annotationCount }} annotations</span>
11
+ </div>
12
+ <div class="info-row filename">
13
+ <span>{{ fileName }}</span>
14
+ </div>
15
+ </div>
16
+
17
+ <div class="export-actions">
18
+ <button
19
+ class="export-button"
20
+ @click="exportAnnotations"
21
+ :disabled="!hasAnnotations"
22
+ >
23
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
24
+ <path d="M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z"/>
25
+ </svg>
26
+ Télécharger
27
+ </button>
28
+
29
+ <p v-if="!hasAnnotations" class="no-data-message">
30
+ Aucune donnée à exporter
31
+ </p>
32
+ </div>
33
+ </div>
34
+ </div>
35
+ </template>
36
+
37
+ <script>
38
+ import { useAnnotationStore } from '@/stores/annotationStore'
39
+ import { useVideoStore } from '@/stores/videoStore'
40
+ import { computed } from 'vue'
41
+
42
+ export default {
43
+ name: 'EmptyView',
44
+
45
+ setup() {
46
+ const annotationStore = useAnnotationStore()
47
+ const videoStore = useVideoStore()
48
+
49
+ const videoName = computed(() => {
50
+ if (videoStore.selectedVideo?.name) {
51
+ return videoStore.selectedVideo.name.replace(/\.[^/.]+$/, '') // Enlever l'extension
52
+ }
53
+ return 'default_video'
54
+ })
55
+
56
+ const fileName = computed(() => {
57
+ return `${videoName.value}_objects.json`
58
+ })
59
+
60
+ const objectCount = computed(() => {
61
+ return Object.keys(annotationStore.objects).length
62
+ })
63
+
64
+ const annotationCount = computed(() => {
65
+ let count = 0
66
+ Object.values(annotationStore.frameAnnotations).forEach(frameAnnotations => {
67
+ count += frameAnnotations.length
68
+ })
69
+ return count
70
+ })
71
+
72
+ const hasAnnotations = computed(() => {
73
+ return annotationCount.value > 0
74
+ })
75
+
76
+ const exportAnnotations = () => {
77
+ // Créer la structure objects selon le format demandé
78
+ const objects = Object.values(annotationStore.objects).map(obj => {
79
+ const objData = {
80
+ obj_id: parseInt(obj.id)
81
+ }
82
+
83
+ // Analyser le label pour extraire le type et l'équipe
84
+ if (obj.label) {
85
+ const label = obj.label.toLowerCase()
86
+
87
+ if (label.includes('ball')) {
88
+ objData.obj_type = 'ball'
89
+ objData.team = null
90
+ } else if (label.includes('player')) {
91
+ objData.obj_type = 'player'
92
+
93
+ // Extraire le numéro d'équipe
94
+ if (label.includes('team 1') || label.includes('team1')) {
95
+ objData.team = 1
96
+ } else if (label.includes('team 2') || label.includes('team2')) {
97
+ objData.team = 2
98
+ } else {
99
+ objData.team = null
100
+ }
101
+ } else {
102
+ objData.obj_type = null
103
+ objData.team = null
104
+ }
105
+ } else {
106
+ objData.obj_type = null
107
+ objData.team = null
108
+ }
109
+
110
+ return objData
111
+ })
112
+
113
+ // Créer la structure initial_annotations selon le format demandé
114
+ const initial_annotations = []
115
+
116
+ // Parcourir toutes les frames qui ont des annotations
117
+ Object.keys(annotationStore.frameAnnotations).forEach(frameNumber => {
118
+ const frameAnnotations = annotationStore.frameAnnotations[frameNumber]
119
+ const frameData = {
120
+ frame: parseInt(frameNumber),
121
+ annotations: []
122
+ }
123
+
124
+ // Grouper les annotations par objet pour cette frame
125
+ const annotationsByObject = {}
126
+ frameAnnotations.forEach(annotation => {
127
+ if (!annotationsByObject[annotation.objectId]) {
128
+ annotationsByObject[annotation.objectId] = []
129
+ }
130
+
131
+ // Extraire les points selon le type d'annotation
132
+ if (annotation.type === 'point') {
133
+ annotationsByObject[annotation.objectId].push({
134
+ x: Math.round(annotation.x),
135
+ y: Math.round(annotation.y),
136
+ label: annotation.pointType === 'positive' ? 1 : 0
137
+ })
138
+ } else if (annotation.type === 'mask' && annotation.points) {
139
+ // Ajouter tous les points du masque
140
+ annotation.points.forEach(point => {
141
+ annotationsByObject[annotation.objectId].push({
142
+ x: Math.round(point.x),
143
+ y: Math.round(point.y),
144
+ label: point.type === 'positive' ? 1 : 0
145
+ })
146
+ })
147
+ }
148
+ })
149
+
150
+ // Créer les annotations pour cette frame
151
+ Object.keys(annotationsByObject).forEach(objectId => {
152
+ const points = annotationsByObject[objectId]
153
+ if (points.length > 0) {
154
+ frameData.annotations.push({
155
+ obj_id: parseInt(objectId),
156
+ points: points
157
+ })
158
+ }
159
+ })
160
+
161
+ // Ajouter la frame seulement si elle a des annotations
162
+ if (frameData.annotations.length > 0) {
163
+ initial_annotations.push(frameData)
164
+ }
165
+ })
166
+
167
+ // Structure finale selon le format demandé
168
+ const exportData = {
169
+ objects: objects,
170
+ initial_annotations: initial_annotations
171
+ }
172
+
173
+ // Créer le blob et le télécharger
174
+ const jsonString = JSON.stringify(exportData, null, 2)
175
+ const blob = new Blob([jsonString], { type: 'application/json' })
176
+ const url = URL.createObjectURL(blob)
177
+
178
+ const link = document.createElement('a')
179
+ link.href = url
180
+ link.download = fileName.value
181
+ document.body.appendChild(link)
182
+ link.click()
183
+ document.body.removeChild(link)
184
+ URL.revokeObjectURL(url)
185
+
186
+ console.log('Annotations exportées:', fileName.value)
187
+ }
188
+
189
+ return {
190
+ videoName,
191
+ fileName,
192
+ objectCount,
193
+ annotationCount,
194
+ hasAnnotations,
195
+ exportAnnotations
196
+ }
197
+ }
198
+ }
199
+ </script>
200
+
201
+ <style scoped>
202
+ .export-view {
203
+ height: 100%;
204
+ display: flex;
205
+ align-items: center;
206
+ justify-content: center;
207
+ color: white;
208
+ padding: 20px;
209
+ }
210
+
211
+ .export-content {
212
+ text-align: center;
213
+ width: 100%;
214
+ }
215
+
216
+ .export-header {
217
+ margin-bottom: 20px;
218
+ }
219
+
220
+ .export-header h3 {
221
+ margin: 0;
222
+ font-size: 1rem;
223
+ color: #fff;
224
+ font-weight: 500;
225
+ }
226
+
227
+ .export-info {
228
+ margin-bottom: 20px;
229
+ }
230
+
231
+ .info-row {
232
+ margin-bottom: 8px;
233
+ color: #ccc;
234
+ font-size: 0.9rem;
235
+ }
236
+
237
+ .info-row.filename {
238
+ color: #fff;
239
+ font-family: monospace;
240
+ font-size: 0.8rem;
241
+ }
242
+
243
+ .export-actions {
244
+ text-align: center;
245
+ }
246
+
247
+ .export-button {
248
+ display: inline-flex;
249
+ align-items: center;
250
+ gap: 6px;
251
+ padding: 8px 16px;
252
+ background: #4a4a4a;
253
+ color: white;
254
+ border: none;
255
+ border-radius: 4px;
256
+ font-size: 0.8rem;
257
+ cursor: pointer;
258
+ transition: background 0.2s;
259
+ }
260
+
261
+ .export-button:hover:not(:disabled) {
262
+ background: #5a5a5a;
263
+ }
264
+
265
+ .export-button:disabled {
266
+ background: #3c3c3c;
267
+ color: #666;
268
+ cursor: not-allowed;
269
+ }
270
+
271
+ .no-data-message {
272
+ margin: 12px 0 0 0;
273
+ color: #666;
274
+ font-size: 0.8rem;
275
+ font-style: italic;
276
+ }
277
  </style>