You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by te...@apache.org on 2020/04/15 17:07:07 UTC
[incubator-streampipes] 02/02: [STREAMPIPES-79] connect image
labeling tool with datalake - reading image from datalake - store coco file
in datalake - refactor ui
This is an automated email from the ASF dual-hosted git repository.
tex pushed a commit to branch image-labeling
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git
commit 4e6c71bc5d1f6088e67a2b2d7fbf2b4df9076448
Author: tex <te...@fzi.de>
AuthorDate: Wed Apr 15 19:05:18 2020 +0200
[STREAMPIPES-79] connect image labeling tool with datalake
- reading image from datalake
- store coco file in datalake
- refactor ui
---
.../rest/impl/datalake/DataLakeManagementV3.java | 51 ++++++++++
.../rest/impl/datalake/DataLakeResourceV3.java | 25 ++++-
.../app/CustomMaterial/custom-material.module.ts | 2 +-
ui/src/app/core-model/coco/Annotation.ts | 12 ---
ui/src/app/core-model/coco/Coco.format.ts | 60 -----------
.../datalake/datalake-rest.service.ts | 10 ++
ui/src/app/core-ui/core-ui.module.ts | 14 ++-
.../image-labeling/image-labeling.component.html | 3 +-
.../image-labeling/image-labeling.component.ts | 110 ++++++++++++++++----
.../core-ui/image/services/CocoFormat.service.ts | 112 +++++++++++++++++++++
ui/src/app/core-ui/image/util/color.util.ts | 33 ++++++
11 files changed, 329 insertions(+), 103 deletions(-)
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeManagementV3.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeManagementV3.java
index edcc375..65786d2 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeManagementV3.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeManagementV3.java
@@ -20,6 +20,7 @@ package org.apache.streampipes.rest.impl.datalake;
import com.google.gson.Gson;
import okhttp3.OkHttpClient;
+import org.apache.commons.io.FileUtils;
import org.influxdb.InfluxDB;
import org.influxdb.InfluxDBFactory;
import org.influxdb.dto.Query;
@@ -31,6 +32,7 @@ import org.apache.streampipes.rest.impl.datalake.model.GroupedDataResult;
import org.apache.streampipes.rest.impl.datalake.model.PageResult;
import org.apache.streampipes.storage.management.StorageDispatcher;
+import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.text.ParseException;
@@ -521,4 +523,53 @@ public class DataLakeManagementV3 {
}
}
+
+ public byte[] getImage(String fileRoute) throws IOException {
+ fileRoute = getImageFileRoute(fileRoute);
+ File file = new File(fileRoute);
+ return FileUtils.readFileToByteArray(file);
+ }
+
+
+ public String getImageCoco(String fileRoute) throws IOException {
+ fileRoute = getImageFileRoute(fileRoute);
+ String cocoRoute = getCocoFileRoute(fileRoute);
+
+ File file = new File(cocoRoute);
+ if (!file.exists()) {
+ return "";
+ } else {
+ return FileUtils.readFileToString(file, "UTF-8");
+ }
+ }
+
+
+ public void saveImageCoco(String fileRoute, String data) throws IOException {
+ fileRoute = getImageFileRoute(fileRoute);
+ String cocoRoute = getCocoFileRoute(fileRoute);
+
+ File file = new File(cocoRoute);
+ file.getParentFile().mkdirs();
+ FileUtils.writeStringToFile(file, data, "UTF-8");
+
+ }
+
+ private String getImageFileRoute(String fileRoute) {
+ fileRoute = fileRoute.replace("_", "/");
+ fileRoute = fileRoute.replace("/png", ".png");
+ return fileRoute;
+ }
+
+ private String getCocoFileRoute(String imageRoute) {
+ String[] splitedRoute = imageRoute.split("/");
+ String route = "";
+ for (int i = 0; splitedRoute.length - 2 >= i; i++) {
+ route += "/" + splitedRoute[i];
+ }
+ route += "Coco";
+ route += "/" + splitedRoute[splitedRoute.length - 1];
+ route = route.replace(".png", ".json");
+ return route;
+ }
+
}
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeResourceV3.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeResourceV3.java
index 2eb79f9..abb0a69 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeResourceV3.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeResourceV3.java
@@ -31,11 +31,7 @@ import java.io.IOException;
import java.text.ParseException;
import java.util.List;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
+import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@@ -208,4 +204,23 @@ public class DataLakeResourceV3 extends AbstractRestInterface {
.build();
}
+ @GET
+ @Path("/data/image/{route}/file")
+ @Produces("image/png")
+ public Response getImage(@PathParam("route") String fileRoute) throws IOException {
+ return ok(dataLakeManagement.getImage(fileRoute));
+ }
+
+ @GET
+ @Path("/data/image/{route}/coco")
+ @Produces("application/json")
+ public Response getImageCoco(@PathParam("route") String fileRoute) throws IOException {
+ return ok(dataLakeManagement.getImageCoco(fileRoute));
+ }
+
+ @POST
+ @Path("/data/image/{route}/coco")
+ public void saveImageCoco(@PathParam("route") String fileRoute, String data) throws IOException {
+ dataLakeManagement.saveImageCoco(fileRoute, data);
+ }
}
diff --git a/ui/src/app/CustomMaterial/custom-material.module.ts b/ui/src/app/CustomMaterial/custom-material.module.ts
index 42b9a11..8c76b28 100644
--- a/ui/src/app/CustomMaterial/custom-material.module.ts
+++ b/ui/src/app/CustomMaterial/custom-material.module.ts
@@ -16,7 +16,7 @@
*
*/
-import {NgModule} from '@angular/core';
+import { NgModule } from '@angular/core';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
diff --git a/ui/src/app/core-model/coco/Annotation.ts b/ui/src/app/core-model/coco/Annotation.ts
index ce76d22..d92082b 100644
--- a/ui/src/app/core-model/coco/Annotation.ts
+++ b/ui/src/app/core-model/coco/Annotation.ts
@@ -20,16 +20,4 @@ export class Annotation {
this.brushSize = undefined;
}
- isBox() {
- return this.bbox !== undefined;
- }
-
- isPolygon() {
- return this.segmentation !== undefined && this.brushSize === undefined;
- }
-
- isBrush() {
- return this.brushSize !== undefined;
- }
-
}
diff --git a/ui/src/app/core-model/coco/Coco.format.ts b/ui/src/app/core-model/coco/Coco.format.ts
index 160c6b1..c18821f 100644
--- a/ui/src/app/core-model/coco/Coco.format.ts
+++ b/ui/src/app/core-model/coco/Coco.format.ts
@@ -19,64 +19,4 @@ export class CocoFormat {
constructor() { }
- addImage(fileName) {
- const image = new Image();
- image.file_name = fileName;
- image.id = this.images.length + 1;
- this.images.push(image);
- }
-
- getLabelById(id) {
- return this.categories.find(elem => elem.id === id).name;
- }
-
- getLabelId(supercategory, name): number {
- let category = this.categories.find(elem => elem.name === name && elem.supercategory === supercategory);
- if (category === undefined) {
- category = new Category(this.categories.length + 1, name, supercategory);
- this.categories.push(category);
- }
- return category.id;
- }
-
- addReactAnnotationToFirstImage(cords, size, supercategory, category): Annotation {
- const annotation = new Annotation();
- annotation.id = this.annotations.length + 1;
- annotation.iscrowd = 0;
- annotation.image_id = 1;
- annotation.bbox = [cords.x, cords.y, size.x, size.y];
- annotation.category_id = this.getLabelId(supercategory, category);
- annotation.category_name = category;
- this.annotations.push(annotation);
- return annotation;
- }
-
- addPolygonAnnotationFirstImage(points, supercategory, category): Annotation {
- const annotation = new Annotation();
- annotation.id = this.annotations.length + 1;
- annotation.iscrowd = 0;
- annotation.image_id = 1;
- annotation.segmentation = [points];
- annotation.category_id = this.getLabelId(supercategory, category);
- annotation.category_name = category; this.annotations.push(annotation);
- return annotation;
- }
-
- addBrushAnnotationFirstImage(points, brushSize, supercategory, category): Annotation {
- const annotation = new Annotation();
- annotation.id = this.annotations.length + 1;
- annotation.iscrowd = 0;
- annotation.image_id = 1;
- annotation.segmentation = [points];
- annotation.brushSize = brushSize;
- annotation.category_id = this.getLabelId(supercategory, category);
- annotation.category_name = category;
- this.annotations.push(annotation);
- return annotation;
- }
-
- removeAnnotation(id) {
- this.annotations = this.annotations.filter(anno => anno.id !== id);
- }
-
}
diff --git a/ui/src/app/core-services/datalake/datalake-rest.service.ts b/ui/src/app/core-services/datalake/datalake-rest.service.ts
index 5550dbf..f94cbb3 100644
--- a/ui/src/app/core-services/datalake/datalake-rest.service.ts
+++ b/ui/src/app/core-services/datalake/datalake-rest.service.ts
@@ -134,5 +134,15 @@ export class DatalakeRestService {
};
}
+ getImageUrl(imageRoute) {
+ return this.dataLakeUrlV3 + '/data/image/' + imageRoute + '/file';
+ }
+
+ getCocoFileForImage(imageRoute) {
+ return this.http.get(this.dataLakeUrlV3 + '/data/image/' + imageRoute + '/coco');
+ }
+ saveCocoFileForImage(imageRoute, data) {
+ return this.http.post(this.dataLakeUrlV3 + '/data/image/' + imageRoute + '/coco', data);
+ }
}
diff --git a/ui/src/app/core-ui/core-ui.module.ts b/ui/src/app/core-ui/core-ui.module.ts
index 961d6cb..b6d8546 100644
--- a/ui/src/app/core-ui/core-ui.module.ts
+++ b/ui/src/app/core-ui/core-ui.module.ts
@@ -16,9 +16,9 @@
*
*/
-import {NgModule} from '@angular/core';
-import {FlexLayoutModule} from '@angular/flex-layout';
-import {CommonModule} from '@angular/common';
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { FlexLayoutModule } from '@angular/flex-layout';
import { CdkTableModule } from '@angular/cdk/table';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@@ -31,6 +31,8 @@ import { LineChartComponent } from './linechart/lineChart.component';
import { TableComponent } from './table/table.component';
// import * as PlotlyJS from 'plotly.js/dist/plotly.js';
+import { MatChipsModule } from '@angular/material/chips';
+import { MatSliderModule } from '@angular/material/slider';
import { PlotlyViaWindowModule } from 'angular-plotly.js';
import { ImageAnnotationsComponent } from './image/components/image-annotations/image-annotations.component';
import { ImageBarComponent } from './image/components/image-bar/image-bar.component';
@@ -38,12 +40,13 @@ import { ImageContainerComponent } from './image/components/image-container/imag
import { ImageLabelsComponent } from './image/components/image-labels/image-labels.component';
import { ImageCategorizeComponent } from './image/image-categorize/image-categorize.component';
import { ImageLabelingComponent } from './image/image-labeling/image-labeling.component';
+import { ImageViewerComponent } from './image/image-viewer/image-viewer.component';
import { ImageComponent } from './image/image.component';
import { BrushLabelingService } from './image/services/BrushLabeling.service';
import { ColorService } from './image/services/color.service';
import { PolygonLabelingService } from './image/services/PolygonLabeling.service';
import { ReactLabelingService } from './image/services/ReactLabeling.service';
-import { ImageViewerComponent } from './image/image-viewer/image-viewer.component';
+import { CocoFormatService } from "./image/services/CocoFormat.service";
// PlotlyViaCDNModule.plotlyjs = PlotlyJS;
@NgModule({
@@ -59,6 +62,8 @@ import { ImageViewerComponent } from './image/image-viewer/image-viewer.componen
MatDatepickerModule,
MatNativeDateModule,
PlotlyViaWindowModule,
+ MatSliderModule,
+ MatChipsModule
],
declarations: [
TableComponent,
@@ -78,6 +83,7 @@ import { ImageViewerComponent } from './image/image-viewer/image-viewer.componen
ReactLabelingService,
PolygonLabelingService,
BrushLabelingService,
+ CocoFormatService,
],
entryComponents: [
],
diff --git a/ui/src/app/core-ui/image/image-labeling/image-labeling.component.html b/ui/src/app/core-ui/image/image-labeling/image-labeling.component.html
index 954c33a..08801cc 100644
--- a/ui/src/app/core-ui/image/image-labeling/image-labeling.component.html
+++ b/ui/src/app/core-ui/image/image-labeling/image-labeling.component.html
@@ -33,6 +33,7 @@
<button mat-button (click)="setPolygonMode()" [style.background-color]="isPolygonMode() ? 'lightgrey' : 'white'"> <mat-icon>details</mat-icon></button>
<button mat-button (click)="setBrushMode()" [style.background-color]="isBrushMode() ? 'lightgrey' : 'white'"> <mat-icon>blur_circular</mat-icon></button>
<mat-slider [min]="1" [max]="50" [step]="1" [thumbLabel]="true" [(ngModel)]="brushSize"></mat-slider>
+ <button mat-button (click)="save()"> <mat-icon>save</mat-icon></button>
</div>
<sp-image-container
@@ -48,7 +49,7 @@
</div>
<sp-image-annotations
- [annotations]="this.cocoFiles[this.imagesIndex].annotations"
+ [annotations]="this.cocoFiles[this.imagesIndex]?.annotations"
[labels]="labels"
(changeAnnotationLabel)="handleChangeAnnotationLabel($event)"
(deleteAnnotation)="handleDeleteAnnotation($event)">
diff --git a/ui/src/app/core-ui/image/image-labeling/image-labeling.component.ts b/ui/src/app/core-ui/image/image-labeling/image-labeling.component.ts
index 42fbd2d..f430817 100644
--- a/ui/src/app/core-ui/image/image-labeling/image-labeling.component.ts
+++ b/ui/src/app/core-ui/image/image-labeling/image-labeling.component.ts
@@ -25,10 +25,11 @@ import { CocoFormat } from '../../../core-model/coco/Coco.format';
import { DatalakeRestService } from '../../../core-services/datalake/datalake-rest.service';
import { ImageContainerComponent } from '../components/image-container/image-container.component';
import { ICoordinates } from '../model/coordinates';
+import { LabelingMode } from '../model/labeling-mode';
import { BrushLabelingService } from '../services/BrushLabeling.service';
import { PolygonLabelingService } from '../services/PolygonLabeling.service';
import { ReactLabelingService } from '../services/ReactLabeling.service';
-import { LabelingMode } from '../model/labeling-mode';
+import { CocoFormatService } from "../services/CocoFormat.service";
@Component({
selector: 'sp-image-labeling',
@@ -52,37 +53,103 @@ export class ImageLabelingComponent implements OnInit, AfterViewInit {
@ViewChild(ImageContainerComponent) imageView: ImageContainerComponent;
+ measureName = 'testsix'; // TODO: Remove hard coded Index, should be injected
+ eventSchema = undefined; // TODO: event schema should be also injected
+ imageField = undefined;
+ pageIndex = undefined;
+ pageSum = undefined;
+
public labelingMode: LabelingMode = LabelingMode.ReactLabeling;
constructor(private restService: DatalakeRestService, private reactLabelingService: ReactLabelingService,
private polygonLabelingService: PolygonLabelingService, private brushLabelingService: BrushLabelingService,
- private snackBar: MatSnackBar) { }
+ private snackBar: MatSnackBar, private cocoFormatService: CocoFormatService) { }
ngOnInit(): void {
+
+
this.isHoverComponent = false;
this.brushSize = 5;
+
+
+
// 1. get labels
this.labels = this.restService.getLabels();
// 2. get Images
- this.imagesSrcs = this.restService.getImageSrcs();
+ this.restService.getAllInfos().subscribe(
+ res => {
+ this.eventSchema = res.find(elem => elem.measureName = this.measureName).eventSchema;
+ const properties = this.eventSchema.eventProperties;
+ for (const prop of properties) {
+ if (prop.domainProperties.find(type => type === 'https://image.com')) {
+ this.imageField = prop;
+ break;
+ }
+ }
+ this.loadData();
+ }
+ );
+
this.imagesIndex = 0;
// 3. get Coco files
- this.cocoFiles = [];
- for (const src of this.imagesSrcs) {
- const coco = new CocoFormat();
- coco.addImage(src);
- this.cocoFiles.push(coco);
- }
+ // this.cocoFiles = [];
+ // for (const src of this.imagesSrcs) {
+ // const coco = new CocoFormat();
+ // this.cocoFormatService.addImage(coco, scr)
+ // coco.addImage(src);
+ // this.cocoFiles.push(coco);
+ // }
}
ngAfterViewInit(): void {
this.imagesIndex = 0;
}
+ loadData() {
+ if (this.pageIndex === undefined) {
+ this.restService.getDataPageWithoutPage(this.measureName, 10).subscribe(
+ res => this.processData(res)
+ );
+ } else {
+ this.restService.getDataPage(this.measureName, 10, this.pageIndex).subscribe(
+ res => this.processData(res)
+ );
+ }
+ }
+
+ processData(pageResult) {
+ this.pageIndex = pageResult.page;
+ this.pageSum = pageResult.pageSum;
+ const imageIndex = pageResult.headers.findIndex(name => name === this.imageField.runtimeName);
+ const tmp = [];
+ this.cocoFiles = [];
+ pageResult.rows.forEach(row => {
+ tmp.push(this.restService.getImageUrl(row[imageIndex]))
+ this.restService.getCocoFileForImage(row[imageIndex]).subscribe(
+ coco => {
+ console.log('------------------------------' +
+ '--------------------------------')
+ if (coco === null) {
+ const cocoFile = new CocoFormat();
+ this.cocoFormatService.addImage(cocoFile, (row[imageIndex]));
+ this.cocoFiles.push(cocoFile);
+ } else {
+ this.cocoFiles.push(coco as CocoFormat);
+ }
+ console.log(this.cocoFiles);
+
+
+ }
+ );
+
+ });
+ this.imagesSrcs = tmp;
+ }
+
/* sp-image-view handler */
handleMouseDownLeft(layer: Konva.Layer, shift: ICoordinates, position: ICoordinates) {
@@ -128,7 +195,7 @@ export class ImageLabelingComponent implements OnInit, AfterViewInit {
case LabelingMode.ReactLabeling: {
const result = this.reactLabelingService.endLabeling(position);
const coco = this.cocoFiles[this.imagesIndex];
- const annotation = coco.addReactAnnotationToFirstImage(result[0], result[1],
+ const annotation = this.cocoFormatService.addReactAnnotationToFirstImage(coco, result[0], result[1],
this.selectedLabel.category, this.selectedLabel.label);
this.reactLabelingService.draw(annotationLayer, shift, annotation, this.imageView);
}
@@ -140,7 +207,7 @@ export class ImageLabelingComponent implements OnInit, AfterViewInit {
case LabelingMode.BrushLabeling: {
const result = this.brushLabelingService.endLabeling(position);
const coco = this.cocoFiles[this.imagesIndex];
- const annotation = coco.addBrushAnnotationFirstImage(result[0], result[1],
+ const annotation = this.cocoFormatService.addBrushAnnotationFirstImage(coco, result[0], result[1],
this.selectedLabel.category, this.selectedLabel.label);
this.brushLabelingService.draw(annotationLayer, shift, annotation, this.imageView);
}
@@ -155,7 +222,7 @@ export class ImageLabelingComponent implements OnInit, AfterViewInit {
case LabelingMode.PolygonLabeling:
const points = this.polygonLabelingService.endLabeling(position);
const coco = this.cocoFiles[this.imagesIndex];
- const annotation = coco.addPolygonAnnotationFirstImage(points,
+ const annotation = this.cocoFormatService.addPolygonAnnotationFirstImage(coco, points,
this.selectedLabel.category, this.selectedLabel.label);
this.polygonLabelingService.draw(layer, shift, annotation, this.imageView);
}
@@ -167,11 +234,11 @@ export class ImageLabelingComponent implements OnInit, AfterViewInit {
for (const annotation of coco.annotations) {
annotation.isHovered = false;
annotation.isSelected = false;
- if (annotation.isBox()) {
+ if (this.cocoFormatService.isBoxAnnonation(annotation)) {
this.reactLabelingService.draw(layer, shift, annotation, this.imageView);
- } else if (annotation.isPolygon() && !annotation.isBrush()) {
+ } else if (this.cocoFormatService.isPolygonAnnonation(annotation) && !this.cocoFormatService.isBrushAnnonation(annotation)) {
this.polygonLabelingService.draw(layer, shift, annotation, this.imageView);
- } else if (annotation.isBrush()) {
+ } else if (this.cocoFormatService.isBrushAnnonation(annotation)) {
this.brushLabelingService.draw(layer, shift, annotation, this.imageView);
}
}
@@ -210,7 +277,7 @@ export class ImageLabelingComponent implements OnInit, AfterViewInit {
/* sp-image-annotations handlers */
handleChangeAnnotationLabel(change: [Annotation, string, string]) {
const coco = this.cocoFiles[this.imagesIndex];
- const categoryId = coco.getLabelId(change[1], change[2]);
+ const categoryId = this.cocoFormatService.getLabelId(coco, change[1], change[2]);
change[0].category_id = categoryId;
change[0].category_name = change[2];
this.imageView.redrawAll();
@@ -219,7 +286,7 @@ export class ImageLabelingComponent implements OnInit, AfterViewInit {
handleDeleteAnnotation(annotation) {
if (annotation !== undefined) {
const coco = this.cocoFiles[this.imagesIndex];
- coco.removeAnnotation(annotation.id);
+ this.cocoFormatService.removeAnnotation(coco, annotation.id);
this.imageView.redrawAll();
}
}
@@ -236,11 +303,14 @@ export class ImageLabelingComponent implements OnInit, AfterViewInit {
}
}
- private save() {
+ save() {
// TODO
const coco = this.cocoFiles[this.imagesIndex];
- console.log(coco);
- this.openSnackBar('TODO: Save coco file');
+ const imageSrcSplitted = this.imagesSrcs[this.imagesIndex].split('/');
+ const imageRoute = imageSrcSplitted[imageSrcSplitted.length - 2]
+ this.restService.saveCocoFileForImage(imageRoute, JSON.stringify(coco)).subscribe(
+ res => this.openSnackBar('Saved')
+ );
}
private openSnackBar(message: string) {
diff --git a/ui/src/app/core-ui/image/services/CocoFormat.service.ts b/ui/src/app/core-ui/image/services/CocoFormat.service.ts
new file mode 100644
index 0000000..8c20ca4
--- /dev/null
+++ b/ui/src/app/core-ui/image/services/CocoFormat.service.ts
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Injectable } from '@angular/core';
+import { Annotation } from '../../../core-model/coco/Annotation';
+import { Category } from '../../../core-model/coco/Category';
+import { CocoFormat } from '../../../core-model/coco/Coco.format';
+import { Image } from '../../../core-model/coco/Image';
+
+@Injectable()
+export class CocoFormatService {
+
+
+ addImage(coco: CocoFormat, fileName) {
+ const image = new Image();
+ image.file_name = fileName;
+ image.id = coco.images.length + 1;
+ coco.images.push(image);
+ }
+
+ getLabelById(coco: CocoFormat, id) {
+ return coco.categories.find(elem => elem.id === id).name;
+ }
+
+ getLabelId(coco: CocoFormat, supercategory, name): number {
+ let category = coco.categories.find(elem => elem.name === name && elem.supercategory === supercategory);
+ if (category === undefined) {
+ category = new Category(coco.categories.length + 1, name, supercategory);
+ coco.categories.push(category);
+ }
+ return category.id;
+ }
+
+ static getLabelId(coco: CocoFormat, supercategory, name): number {
+ // TODO: Find better solution instead of copy same code
+ let category = coco.categories.find(elem => elem.name === name && elem.supercategory === supercategory);
+ if (category === undefined) {
+ category = new Category(coco.categories.length + 1, name, supercategory);
+ coco.categories.push(category);
+ }
+ return category.id;
+ }
+
+ addReactAnnotationToFirstImage(coco: CocoFormat, cords, size, supercategory, category): Annotation {
+ const annotation = new Annotation();
+ annotation.id = coco.annotations.length + 1;
+ annotation.iscrowd = 0;
+ annotation.image_id = 1;
+ annotation.bbox = [cords.x, cords.y, size.x, size.y];
+ annotation.category_id = CocoFormatService.getLabelId(coco, supercategory, category);
+ annotation.category_name = category;
+ coco.annotations.push(annotation);
+ return annotation;
+ }
+
+ addPolygonAnnotationFirstImage(coco: CocoFormat, points, supercategory, category): Annotation {
+ const annotation = new Annotation();
+ annotation.id = coco.annotations.length + 1;
+ annotation.iscrowd = 0;
+ annotation.image_id = 1;
+ annotation.segmentation = [points];
+ annotation.category_id = CocoFormatService.getLabelId(coco, supercategory, category);
+ annotation.category_name = category;
+ coco.annotations.push(annotation);
+ return annotation;
+ }
+
+ addBrushAnnotationFirstImage(coco: CocoFormat, points, brushSize, supercategory, category): Annotation {
+ const annotation = new Annotation();
+ annotation.id = coco.annotations.length + 1;
+ annotation.iscrowd = 0;
+ annotation.image_id = 1;
+ annotation.segmentation = [points];
+ annotation.brushSize = brushSize;
+ annotation.category_id = coco.getLabelId(supercategory, category);
+ annotation.category_name = category;
+ coco.annotations.push(annotation);
+ return annotation;
+ }
+
+ removeAnnotation(coco: CocoFormat, id) {
+ coco.annotations = coco.annotations.filter(anno => anno.id !== id);
+ }
+
+ isBoxAnnonation(annotation: Annotation) {
+ return annotation.bbox !== undefined;
+ }
+
+ isPolygonAnnonation(annotation: Annotation) {
+ return annotation.segmentation !== undefined && annotation.brushSize === undefined;
+ }
+
+ isBrushAnnonation(annotation: Annotation) {
+ return annotation.brushSize !== undefined;
+ }
+
+
+}
diff --git a/ui/src/app/core-ui/image/util/color.util.ts b/ui/src/app/core-ui/image/util/color.util.ts
new file mode 100644
index 0000000..65c4526
--- /dev/null
+++ b/ui/src/app/core-ui/image/util/color.util.ts
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export class ColorUtil {
+
+ static getColor(label) {
+ var hash = 0;
+ for (var i = 0; i < label.length; i++) {
+ hash = label.charCodeAt(i) + ((hash << 5) - hash);
+ }
+ var colour = '#';
+ for (var i = 0; i < 3; i++) {
+ var value = (hash >> (i * 8)) & 0xFF;
+ colour += ('00' + value.toString(16)).substr(-2);
+ }
+ return colour;
+ }
+
+}
\ No newline at end of file