Explorar o código

Resolve "resize bounding boxes"

Eric Tröbs %!s(int64=4) %!d(string=hai) anos
pai
achega
6d206f6bb6

+ 5 - 0
pycs/frontend/WebServer.py

@@ -221,6 +221,11 @@ class WebServer:
             if 'delete' in result.keys():
                 target_object.remove_result(result_identifier)
 
+            # update result
+            else:
+                target_object.update_result(result_identifier, result)
+
+            # return default success response
             return response()
 
         # finally start web server

+ 4 - 0
pycs/projects/MediaFile.py

@@ -29,6 +29,10 @@ class MediaFile(ObservableDict):
     def remove_result(self, identifier):
         del self['predictionResults'][identifier]
 
+    def update_result(self, identifier, value):
+        value['id'] = identifier
+        self['predictionResults'][identifier] = value
+
     def resize(self, maximum_width):
         # check if resized file already exists
         resized = MediaFile(self, self.parent)

+ 54 - 7
webui/src/components/media/annotated-image.vue

@@ -13,11 +13,13 @@
     <annotation-box v-for="(result, index) in predictions"
                     type="server"
                     :key="index"
+                    :id="result.id"
                     :image="image"
                     :position="result"
                     :socket="socket"
                     :immutable="false"
-                    :box-url="mediaUrl + '/' + result.id"/>
+                    :box-url="mediaUrl + '/' + result.id"
+                    @resize="resize"/>
   </div>
 </template>
 
@@ -55,7 +57,9 @@ export default {
         height: 0
       },
       start: false,
-      current: false
+      fixed: false,
+      current: false,
+      callback: false
     }
   },
   computed: {
@@ -110,10 +114,10 @@ export default {
       return (this.get(event).clientY - bcr.top) / bcr.height;
     },
     buildRectangle: function (x1, y1, x2, y2) {
-      const lx = Math.max(Math.min(x1, x2), 0);
-      const hx = Math.min(Math.max(x1, x2), 1);
-      const ly = Math.max(Math.min(y1, y2), 0);
-      const hy = Math.min(Math.max(y1, y2), 1);
+      const lx = this.fixed && 'lx' in this.fixed ? this.fixed.lx : Math.max(Math.min(x1, x2), 0);
+      const hx = this.fixed && 'hx' in this.fixed ? this.fixed.hx : Math.min(Math.max(x1, x2), 1);
+      const ly = this.fixed && 'ly' in this.fixed ? this.fixed.ly : Math.max(Math.min(y1, y2), 0);
+      const hy = this.fixed && 'hy' in this.fixed ? this.fixed.hy : Math.min(Math.max(y1, y2), 1);
 
       return {
         x: lx,
@@ -138,9 +142,52 @@ export default {
     },
     release: function () {
       if (this.start) {
-        this.socket.post(this.mediaUrl, this.current);
+        if (this.callback)
+          this.callback(this.current);
+        else
+          this.socket.post(this.mediaUrl, this.current);
+
         this.start = false;
+        this.fixed = false;
         this.current = false;
+        this.callback = false;
+      }
+    },
+    resize: function (position, mode, callback) {
+      this.callback = callback;
+      switch (mode) {
+        case 'nw':
+          this.start = {x: position.x + position.w, y: position.y + position.h};
+          this.fixed = false;
+          break;
+        case 'ne':
+          this.start = {x: position.x, y: position.y + position.h};
+          this.fixed = false;
+          break;
+        case 'sw':
+          this.start = {x: position.x + position.w, y: position.y};
+          this.fixed = false;
+          break;
+        case 'se':
+          this.start = {x: position.x, y: position.y};
+          this.fixed = false;
+          break;
+        case 'nn':
+          this.start = {x: position.x, y: position.y + position.h};
+          this.fixed = {lx: position.x, hx: position.x + position.w};
+          break;
+        case 'ww':
+          this.start = {x: position.x + position.w, y: position.y};
+          this.fixed = {ly: position.y, hy: position.y + position.h};
+          break;
+        case 'ee':
+          this.start = {x: position.x, y: position.y};
+          this.fixed = {ly: position.y, hy: position.y + position.h};
+          break;
+        case 'ss':
+          this.start = {x: position.x, y: position.y};
+          this.fixed = {lx: position.x, hx: position.x + position.w};
+          break;
       }
     }
   }

+ 44 - 5
webui/src/components/media/annotation-box.vue

@@ -1,8 +1,20 @@
 <template>
   <div class="annotation-box" :style="style" @mousedown.stop.prevent @touchstart.stop.prevent>
-    <template v-if="!immutable">
-      <img alt="delete" src="@/assets/icons/trash.svg" @click="deleteSelf">
-    </template>
+    <div class="nw" @mousedown="resizeSelf('nw')" @touchstart="resizeSelf('nw')"></div>
+    <div class="nn" @mousedown="resizeSelf('nn')" @touchstart="resizeSelf('nn')"></div>
+    <div class="ne" @mousedown="resizeSelf('ne')" @touchstart="resizeSelf('ne')"></div>
+    <div class="ww" @mousedown="resizeSelf('ww')" @touchstart="resizeSelf('ww')"></div>
+
+    <div class="buttons">
+      <template v-if="!immutable">
+        <img alt="delete" src="@/assets/icons/trash.svg" @click="deleteSelf">
+      </template>
+    </div>
+
+    <div class="ee" @mousedown="resizeSelf('ee')" @touchstart="resizeSelf('ee')"></div>
+    <div class="sw" @mousedown="resizeSelf('sw')" @touchstart="resizeSelf('sw')"></div>
+    <div class="ss" @mousedown="resizeSelf('ss')" @touchstart="resizeSelf('ss')"></div>
+    <div class="se" @mousedown="resizeSelf('se')" @touchstart="resizeSelf('se')"></div>
   </div>
 </template>
 
@@ -37,7 +49,13 @@ export default {
   },
   methods: {
     deleteSelf: function () {
-      this.socket.post(this.boxUrl, {delete: true});
+      this.socket.post(this.boxUrl, {delete: true, id: this.id});
+    },
+    resizeSelf: function (mode) {
+      this.$emit('resize', this.position, mode, this.updateSelf);
+    },
+    updateSelf: function (value) {
+      this.socket.post(this.boxUrl, value);
     }
   }
 }
@@ -47,6 +65,12 @@ export default {
 .annotation-box {
   position: absolute;
 
+  display: grid;
+  grid-template-rows: 10px auto 10px;
+  grid-template-columns: 10px auto 10px;
+}
+
+.buttons {
   display: flex;
   justify-content: center;
   align-items: center;
@@ -54,8 +78,23 @@ export default {
 
 img {
   width: 2rem;
-  max-width: 50%;
   filter: invert(1);
   opacity: 0.9;
 }
+
+.nn, .ss {
+  cursor: ns-resize;
+}
+
+.ww, .ee {
+  cursor: ew-resize;
+}
+
+.ne, .sw {
+  cursor: nesw-resize;
+}
+
+.nw, .se {
+  cursor: nwse-resize;
+}
 </style>