jebin2 commited on
Commit
770761f
·
1 Parent(s): 4e78057

manual box value fix

Browse files
comic_panel_extractor/static/annotator.html CHANGED
@@ -453,6 +453,46 @@
453
  height: calc(100vh - 372px);
454
  }
455
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
456
  </style>
457
  </head>
458
 
@@ -554,8 +594,74 @@
554
  <span class="info-value" id="selectedBoxInfo">None</span>
555
  </div>
556
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
557
  </div>
558
 
 
559
  <!-- Quick Actions -->
560
  <div class="sidebar-section">
561
  <div class="section-title">Actions</div>
@@ -720,6 +826,26 @@
720
  // Keyboard events
721
  document.addEventListener('keydown', (e) => this.onKeyDown(e));
722
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
723
  // Make canvas focusable for keyboard events
724
  this.canvas.tabIndex = 0;
725
  }
@@ -1835,6 +1961,11 @@
1835
  this.drawCanvas();
1836
  return;
1837
  }
 
 
 
 
 
1838
  if (!this.currentImage || this.selectedBoxIndex < 0) return;
1839
 
1840
  const resizeDistance = 5; // Fixed resize distance
@@ -1972,16 +2103,196 @@
1972
  }
1973
  }
1974
 
 
1975
  updateSelectedBoxInfo() {
1976
  const selectedBoxInfo = document.getElementById('selectedBoxInfo');
 
 
1977
  if (this.selectedBoxIndex >= 0) {
1978
- const box = this.annotations[this.selectedBoxIndex];
1979
- selectedBoxInfo.textContent = `#${this.selectedBoxIndex + 1} (${Math.round(box.left)}, ${Math.round(box.top)}, ${Math.round(box.width)}×${Math.round(box.height)})`;
 
 
 
 
 
 
 
 
 
 
 
1980
  } else {
1981
  selectedBoxInfo.textContent = 'None';
 
1982
  }
1983
  }
1984
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1985
  getMousePos(e) {
1986
  const rect = this.canvas.getBoundingClientRect();
1987
  const scaleX = this.canvas.width / rect.width;
 
453
  height: calc(100vh - 372px);
454
  }
455
  }
456
+
457
+ .form-input-sm {
458
+ padding: 4px 6px;
459
+ font-size: 11px;
460
+ height: auto;
461
+ }
462
+
463
+ .point-edit-row {
464
+ display: flex;
465
+ align-items: center;
466
+ gap: 4px;
467
+ margin-bottom: 4px;
468
+ padding: 4px;
469
+ background: #f8fafc;
470
+ border-radius: 4px;
471
+ }
472
+
473
+ .point-edit-input {
474
+ flex: 1;
475
+ padding: 2px 4px;
476
+ font-size: 10px;
477
+ border: 1px solid #d1d5db;
478
+ border-radius: 3px;
479
+ width: 50px;
480
+ }
481
+
482
+ .point-delete-btn {
483
+ background: #f56565;
484
+ color: white;
485
+ border: none;
486
+ border-radius: 3px;
487
+ padding: 2px 6px;
488
+ font-size: 10px;
489
+ cursor: pointer;
490
+ min-width: 20px;
491
+ }
492
+
493
+ .point-delete-btn:hover {
494
+ background: #e53e3e;
495
+ }
496
  </style>
497
  </head>
498
 
 
594
  <span class="info-value" id="selectedBoxInfo">None</span>
595
  </div>
596
  </div>
597
+
598
+ <!-- Enhanced Edit Panel for Selected Annotation -->
599
+ <div id="annotationEditPanel" style="display: none; margin-top: 16px;">
600
+ <div class="section-title">Edit Selected</div>
601
+ <div class="info-card">
602
+ <div class="form-field" style="margin-bottom: 12px;">
603
+ <label class="form-label">Type</label>
604
+ <span class="info-value" id="editType">-</span>
605
+ </div>
606
+
607
+ <div class="form-field" style="margin-bottom: 12px;">
608
+ <label class="form-label">Class ID</label>
609
+ <input type="number" class="form-input form-input-sm" id="editClassId" min="0" max="100"
610
+ style="padding: 6px 8px; font-size: 12px;">
611
+ </div>
612
+
613
+ <!-- Bbox-specific controls -->
614
+ <div id="bboxEditControls" style="display: none;">
615
+ <div class="form-field" style="margin-bottom: 8px;">
616
+ <label class="form-label">Position (X, Y)</label>
617
+ <div style="display: flex; gap: 8px;">
618
+ <input type="number" class="form-input form-input-sm" id="editLeft" min="0"
619
+ style="flex: 1; padding: 4px 6px; font-size: 11px;">
620
+ <input type="number" class="form-input form-input-sm" id="editTop" min="0"
621
+ style="flex: 1; padding: 4px 6px; font-size: 11px;">
622
+ </div>
623
+ </div>
624
+ <div class="form-field" style="margin-bottom: 12px;">
625
+ <label class="form-label">Size (W × H)</label>
626
+ <div style="display: flex; gap: 8px;">
627
+ <input type="number" class="form-input form-input-sm" id="editWidth" min="10"
628
+ style="flex: 1; padding: 4px 6px; font-size: 11px;">
629
+ <input type="number" class="form-input form-input-sm" id="editHeight" min="10"
630
+ style="flex: 1; padding: 4px 6px; font-size: 11px;">
631
+ </div>
632
+ </div>
633
+ </div>
634
+
635
+ <!-- Polygon-specific controls -->
636
+ <div id="polygonEditControls" style="display: none;">
637
+ <div class="form-field" style="margin-bottom: 8px;">
638
+ <label class="form-label">Points (<span id="pointCount">0</span>)</label>
639
+ <div id="pointsList" style="max-height: 120px; overflow-y: auto;
640
+ border: 1px solid #e2e8f0; border-radius: 4px; padding: 8px;">
641
+ <!-- Points will be populated here -->
642
+ </div>
643
+ </div>
644
+ </div>
645
+
646
+ <div style="display: flex; gap: 8px; margin-top: 12px;">
647
+ <button class="btn btn-success btn-sm" id="applyEditBtn"
648
+ style="flex: 1; padding: 6px 8px; font-size: 11px;">
649
+ ✓ Apply
650
+ </button>
651
+ <button class="btn btn-secondary btn-sm" id="cancelEditBtn"
652
+ style="flex: 1; padding: 6px 8px; font-size: 11px;">
653
+ ✗ Cancel
654
+ </button>
655
+ <button class="btn btn-danger btn-sm" id="deleteEditBtn"
656
+ style="padding: 6px 8px; font-size: 11px;">
657
+ 🗑️
658
+ </button>
659
+ </div>
660
+ </div>
661
+ </div>
662
  </div>
663
 
664
+
665
  <!-- Quick Actions -->
666
  <div class="sidebar-section">
667
  <div class="section-title">Actions</div>
 
826
  // Keyboard events
827
  document.addEventListener('keydown', (e) => this.onKeyDown(e));
828
 
829
+ // Edit panel buttons
830
+ document.getElementById('applyEditBtn').addEventListener('click', () => this.applyEdits());
831
+ document.getElementById('cancelEditBtn').addEventListener('click', () => this.cancelEdits());
832
+ document.getElementById('deleteEditBtn').addEventListener('click', () => this.deleteSelectedBox());
833
+
834
+ // Real-time bbox updates
835
+ document.getElementById('editLeft').addEventListener('input', () => this.updateBboxFromInputs());
836
+ document.getElementById('editTop').addEventListener('input', () => this.updateBboxFromInputs());
837
+ document.getElementById('editWidth').addEventListener('input', () => this.updateBboxFromInputs());
838
+ document.getElementById('editHeight').addEventListener('input', () => this.updateBboxFromInputs());
839
+
840
+ // Class ID real-time update
841
+ document.getElementById('editClassId').addEventListener('input', (e) => {
842
+ if (this.selectedBoxIndex >= 0) {
843
+ this.annotations[this.selectedBoxIndex].classId = parseInt(e.target.value) || 0;
844
+ this.annotations[this.selectedBoxIndex].saved = false;
845
+ }
846
+ });
847
+
848
+
849
  // Make canvas focusable for keyboard events
850
  this.canvas.tabIndex = 0;
851
  }
 
1961
  this.drawCanvas();
1962
  return;
1963
  }
1964
+ if (e.key === 'Enter') {
1965
+ e.preventDefault();
1966
+ this.onDoubleClick()
1967
+ return;
1968
+ }
1969
  if (!this.currentImage || this.selectedBoxIndex < 0) return;
1970
 
1971
  const resizeDistance = 5; // Fixed resize distance
 
2103
  }
2104
  }
2105
 
2106
+ // Enhanced updateSelectedBoxInfo method
2107
  updateSelectedBoxInfo() {
2108
  const selectedBoxInfo = document.getElementById('selectedBoxInfo');
2109
+ const editPanel = document.getElementById('annotationEditPanel');
2110
+
2111
  if (this.selectedBoxIndex >= 0) {
2112
+ const annotation = this.annotations[this.selectedBoxIndex];
2113
+
2114
+ if (annotation.type === 'segmentation') {
2115
+ const bounds = this.getPolygonBounds(annotation.points);
2116
+ const pointCount = annotation.points.length;
2117
+ selectedBoxInfo.textContent = `#${this.selectedBoxIndex + 1} Polygon (${pointCount} points, ${Math.round(bounds.left)}, ${Math.round(bounds.top)}, ${Math.round(bounds.width)}×${Math.round(bounds.height)})`;
2118
+ } else {
2119
+ selectedBoxInfo.textContent = `#${this.selectedBoxIndex + 1} BBox (${Math.round(annotation.left)}, ${Math.round(annotation.top)}, ${Math.round(annotation.width)}×${Math.round(annotation.height)})`;
2120
+ }
2121
+
2122
+ // Show and populate edit panel
2123
+ this.showEditPanel(annotation);
2124
+ editPanel.style.display = 'block';
2125
  } else {
2126
  selectedBoxInfo.textContent = 'None';
2127
+ editPanel.style.display = 'none';
2128
  }
2129
  }
2130
 
2131
+ // New method to show edit panel
2132
+ showEditPanel(annotation) {
2133
+ const editType = document.getElementById('editType');
2134
+ const editClassId = document.getElementById('editClassId');
2135
+ const bboxControls = document.getElementById('bboxEditControls');
2136
+ const polygonControls = document.getElementById('polygonEditControls');
2137
+
2138
+ // Set common fields
2139
+ editType.textContent = annotation.type === 'segmentation' ? 'Polygon' : 'Bounding Box';
2140
+ editClassId.value = annotation.classId || 0;
2141
+
2142
+ if (annotation.type === 'bbox') {
2143
+ // Show bbox controls
2144
+ bboxControls.style.display = 'block';
2145
+ polygonControls.style.display = 'none';
2146
+
2147
+ document.getElementById('editLeft').value = Math.round(annotation.left);
2148
+ document.getElementById('editTop').value = Math.round(annotation.top);
2149
+ document.getElementById('editWidth').value = Math.round(annotation.width);
2150
+ document.getElementById('editHeight').value = Math.round(annotation.height);
2151
+
2152
+ // Set max values based on current position
2153
+ document.getElementById('editLeft').max = this.originalWidth - annotation.width;
2154
+ document.getElementById('editTop').max = this.originalHeight - annotation.height;
2155
+ document.getElementById('editWidth').max = this.originalWidth - annotation.left;
2156
+ document.getElementById('editHeight').max = this.originalHeight - annotation.top;
2157
+ } else {
2158
+ // Show polygon controls
2159
+ bboxControls.style.display = 'none';
2160
+ polygonControls.style.display = 'block';
2161
+
2162
+ this.populatePolygonPointsList(annotation.points);
2163
+ }
2164
+ }
2165
+
2166
+ // New method to populate polygon points list
2167
+ populatePolygonPointsList(points) {
2168
+ const pointsList = document.getElementById('pointsList');
2169
+ const pointCount = document.getElementById('pointCount');
2170
+
2171
+ pointCount.textContent = points.length;
2172
+ pointsList.innerHTML = '';
2173
+
2174
+ points.forEach((point, index) => {
2175
+ const row = document.createElement('div');
2176
+ row.className = 'point-edit-row';
2177
+ row.innerHTML = `
2178
+ <span style="font-size: 10px; color: #4a5568; min-width: 15px;">${index + 1}:</span>
2179
+ <input type="number" class="point-edit-input" value="${Math.round(point.x)}"
2180
+ data-index="${index}" data-coord="x" min="0" max="${this.originalWidth}">
2181
+ <input type="number" class="point-edit-input" value="${Math.round(point.y)}"
2182
+ data-index="${index}" data-coord="y" min="0" max="${this.originalHeight}">
2183
+ <button class="point-delete-btn" data-index="${index}"
2184
+ ${points.length <= 3 ? 'disabled title="Cannot delete - minimum 3 points required"' : ''}>
2185
+ ×
2186
+ </button>
2187
+ `;
2188
+ pointsList.appendChild(row);
2189
+ });
2190
+
2191
+ // Add event listeners for point inputs
2192
+ pointsList.querySelectorAll('.point-edit-input').forEach(input => {
2193
+ input.addEventListener('change', (e) => this.updatePolygonPoint(e));
2194
+ });
2195
+
2196
+ // Add event listeners for delete buttons
2197
+ pointsList.querySelectorAll('.point-delete-btn').forEach(btn => {
2198
+ btn.addEventListener('click', (e) => this.deletePolygonPoint(e));
2199
+ });
2200
+ }
2201
+
2202
+ // New method to update polygon point
2203
+ updatePolygonPoint(e) {
2204
+ const index = parseInt(e.target.dataset.index);
2205
+ const coord = e.target.dataset.coord;
2206
+ const value = parseInt(e.target.value);
2207
+
2208
+ if (this.selectedBoxIndex >= 0) {
2209
+ const annotation = this.annotations[this.selectedBoxIndex];
2210
+ if (annotation.type === 'segmentation' && annotation.points[index]) {
2211
+ annotation.points[index][coord] = Math.max(0,
2212
+ Math.min(coord === 'x' ? this.originalWidth : this.originalHeight, value));
2213
+ annotation.saved = false;
2214
+ this.drawCanvas();
2215
+ }
2216
+ }
2217
+ }
2218
+
2219
+ // New method to delete polygon point
2220
+ deletePolygonPoint(e) {
2221
+ const index = parseInt(e.target.dataset.index);
2222
+
2223
+ if (this.selectedBoxIndex >= 0) {
2224
+ const annotation = this.annotations[this.selectedBoxIndex];
2225
+ if (annotation.type === 'segmentation' && annotation.points.length > 3) {
2226
+ annotation.points.splice(index, 1);
2227
+ annotation.saved = false;
2228
+ this.populatePolygonPointsList(annotation.points);
2229
+ this.updateSelectedBoxInfo();
2230
+ this.drawCanvas();
2231
+ }
2232
+ }
2233
+ }
2234
+
2235
+ // Method to apply edits
2236
+ applyEdits() {
2237
+ if (this.selectedBoxIndex >= 0) {
2238
+ const annotation = this.annotations[this.selectedBoxIndex];
2239
+ const newClassId = parseInt(document.getElementById('editClassId').value) || 0;
2240
+
2241
+ // Update class ID
2242
+ annotation.classId = newClassId;
2243
+
2244
+ if (annotation.type === 'bbox') {
2245
+ // Update bbox properties
2246
+ const newLeft = parseInt(document.getElementById('editLeft').value);
2247
+ const newTop = parseInt(document.getElementById('editTop').value);
2248
+ const newWidth = parseInt(document.getElementById('editWidth').value);
2249
+ const newHeight = parseInt(document.getElementById('editHeight').value);
2250
+
2251
+ // Apply boundary constraints
2252
+ annotation.left = Math.max(0, Math.min(this.originalWidth - newWidth, newLeft));
2253
+ annotation.top = Math.max(0, Math.min(this.originalHeight - newHeight, newTop));
2254
+ annotation.width = Math.max(10, Math.min(this.originalWidth - annotation.left, newWidth));
2255
+ annotation.height = Math.max(10, Math.min(this.originalHeight - annotation.top, newHeight));
2256
+ }
2257
+
2258
+ annotation.saved = false;
2259
+ this.updateSelectedBoxInfo();
2260
+ this.drawCanvas();
2261
+ this.showAlert('Annotation updated', 'success');
2262
+ }
2263
+ }
2264
+
2265
+ // Method to cancel edits
2266
+ cancelEdits() {
2267
+ // Just refresh the edit panel with current values
2268
+ if (this.selectedBoxIndex >= 0) {
2269
+ this.showEditPanel(this.annotations[this.selectedBoxIndex]);
2270
+ }
2271
+ }
2272
+ // Method for real-time bbox updates
2273
+ updateBboxFromInputs() {
2274
+ if (this.selectedBoxIndex >= 0) {
2275
+ const annotation = this.annotations[this.selectedBoxIndex];
2276
+ if (annotation.type === 'bbox') {
2277
+ const newLeft = parseInt(document.getElementById('editLeft').value) || 0;
2278
+ const newTop = parseInt(document.getElementById('editTop').value) || 0;
2279
+ const newWidth = parseInt(document.getElementById('editWidth').value) || 10;
2280
+ const newHeight = parseInt(document.getElementById('editHeight').value) || 10;
2281
+
2282
+ // Apply constraints and update
2283
+ annotation.left = Math.max(0, Math.min(this.originalWidth - newWidth, newLeft));
2284
+ annotation.top = Math.max(0, Math.min(this.originalHeight - newHeight, newTop));
2285
+ annotation.width = Math.max(10, Math.min(this.originalWidth - annotation.left, newWidth));
2286
+ annotation.height = Math.max(10, Math.min(this.originalHeight - annotation.top, newHeight));
2287
+
2288
+ annotation.saved = false;
2289
+ this.drawCanvas();
2290
+ }
2291
+ }
2292
+ }
2293
+
2294
+
2295
+
2296
  getMousePos(e) {
2297
  const rect = this.canvas.getBoundingClientRect();
2298
  const scaleX = this.canvas.width / rect.width;