演示地址

https://king2088.github.io/simple-image-label/

演示图

开发背景:

最近公司要做一个AI在线标注零碎,须要对图片进行标注,本人在github找了一些,然而大部分都是很久没有更新或者是不太适宜自定义等。当然我也看过CVAT本人的标注,它是采纳canvas开发的,不过对于咱们目前的我的项目来说,并不需要canvas,也不须要较为简单的框选,只须要反对矩形框标注即可,于是本人开发了一个web版的。

简介:

simple-image-label是一个基于Web的用户敌对型组件,简化了指标检测和深度学习工作中的图片标注过程。该组件采纳HTML和JavaScript开发,使用户可能轻松地对图片进行标注并生成标注信息,实用于各种利用场景。

次要特点:

  1. 用户敌对的界面:simple-image-label提供直观易用的界面,使图片标注变得轻而易举。其简洁性确保用户无论程度如何,都能轻松地应用该工具。
  2. 高效标注:借助simple-image-label,用户能够高效地对图片进行标注,增加标签并生成指标检测工作所需的坐标。它简化了标注流程,节俭了贵重的工夫和精力。
  3. 多样兼容性:该组件反对多种标注格局,包含风行的YOLO和VOC等格局。这种兼容性确保了与现有工作流程和深度学习框架的无缝集成。
  4. 网页便捷性:simple-image-label作为一个基于Web的工具,无需简单的装置或设置。用户能够间接从Web浏览器中拜访和应用该组件,使其便捷且随时可用。

开发过程:

simple-image-label的开发过程能够分为以下几个步骤:

  1. 创立HTML构造:首先,咱们须要创立一个蕴含图像和标注区域的HTML构造。能够应用以下代码作为终点:

    <div class="__simple-image-label__"> <div class="s-image-content">     <img id="label-bg_img" src="">     <div id="labelsContainer" class="label-content"></div> </div></div>
  2. 初始化组件:在JavaScript中,咱们须要初始化simple-image-label组件,为其绑定相干的事件和性能。以下是一个根本的初始化代码示例:

首先先再创label时,指定其矩形的左上顶点x,y轴坐标,以及矩形的宽高,而后将其增加到labelsContainer中

this.labelItem = {    uuid: '', // 随机生成    x: 0, // 百分比 = 左上角x轴坐标 / 以后图片宽度    y: 0, // 百分比 = 左上角y轴坐标 / 以后图片高度    width: 0, // 矩形宽度百分比 = 矩形宽度 / 以后图片宽度    height: 0, // 矩形高度百分比 = 矩形高度 / 以后图片高度    name: '', // 矩形名称    color: '' // 矩形色彩};this.labelsContainer.appendChild(this.labelItem);

须要留神的是,初始化之前须要期待图片load实现后再执行,避免图片还未load实现,就曾经看到所有标签,另外则是为了获取到图片的宽高,不便

// 初始化this.$w = this.labelsContainer.clientWidth;this.$h = this.labelsContainer.clientHeight;this.startPoint = { x: 0, y: 0 };this.endPoint = { x: 0, y: 0 };this.labelItem = { uuid: '', x: 0, y: 0, width: 0, height: 0, name: '', color: '' };this.labelsContainer.onmousedown = (e) => this.mousedown(e);// 鼠标挪动事件this.labelsContainer.onmousemove = (e) => this.mousemove(e);// 鼠标抬起事件this.labelsContainer.onmouseup = (e) => this.mouseup(e);// 右键点击this.labelsContainer.oncontextmenu = (e) => {    e.preventDefault();    if (this.contextmenu && typeof this.contextmenu === 'function') {    this.contextmenu(e)    }};if (this.readOnly) {    window.removeEventListener('resize', this.resize.bind(this), false);    this.labelsContainer.style.cursor = 'default';    this.clearAllLabelActive();} else {    this.labelsContainer.style.cursor = 'crosshair';}// 监听浏览器缩放,扭转label的宽高window.addEventListener('resize', this.resize.bind(this), false);this.resizeDotDisplayStatus();

当鼠标左键按下时,咱们记录下鼠标的地位,并记录鼠标左键按下时的坐标,用于后续计算。

// 计算坐标const clientLeft = e.clientX - this.getLabelsContainerRelativePoints().x;const clientTop = e.clientY - this.getLabelsContainerRelativePoints().y;let x = clientLeft / this.$w; // 转换为百分比let y = clientTop / this.$h;this.startPoint = {    x,    y};

当鼠标左键抬起时,咱们计算出鼠标左键抬起时的坐标,并计算出鼠标左键按下和抬起时的坐标差,

const clientLeft = e.clientX - this.getLabelsContainerRelativePoints().x;const clientTop = e.clientY - this.getLabelsContainerRelativePoints().y;let x = clientLeft / this.$w;let y = clientTop / this.$h;this.endPoint = {    x,    y};

这样就能够利用startPoint与endPoint两点只差算出标签的宽高。

labelItem.width = endPoint.x - startPoint.x;labelItem.height = endPoint.y - startPoint.y;

YOLO坐标计算:
YOLO坐标计算形式,[center_x, center_y, width, height],即center_x, center_y为中心点坐标,widthheight为宽高(留神:全副按百分比进行示意,如center_x的地位为30%,则示意为center_x为0.3,其余内容雷同)。

convertToYoloCoordinate(label) {    const coordinate = this.getCoordinate(label);    const { height, width } = this.imageInfo;    const labelCenterX = (coordinate.x + coordinate.x1) / 2;    const labelCenterY = (coordinate.y + coordinate.y1) / 2;    return [labelCenterX / width, labelCenterY / height, label.width, label.height];}

VOC坐标计算:
VOC坐标计算形式,[xmin, ymin, xmax, ymax],即xmin, ymin为左上角坐标,xmax, ymax为右下角坐标。
对于VOC标注,能够通过simple-image-label组件的 endLabeling 办法来计算标注框的坐标。以下是一个示例代码:

getCoordinate(label) {    const { height, width } = this.imageInfo;    return {        x: label.x * width,        y: label.y * height,        x1: (label.x + label.width) * width,        y1: (label.y + label.height) * height    };}
  1. 在Vue和React中应用simple-image-label:
    如果你正在应用Vue或React,能够将simple-image-label组件包装成可复用的组件,以便在应用程序中应用。以下是一个Vue组件示例:
  2. 装置simple-image-label:

    npm install simple-image-label -S
  3. 在Vue组件中引入simple-image-label并应用:

    <template>    <div id="YourElementId"></div></template><script setup>import SimpleImageLabel from 'simple-image-label'import { ref, onMounted } from 'vue';const simpleImageLabel = ref(null);onMounted(() => {    simpleImageLabel.value = new SimpleImageLabel({        el: 'YourElementId'        imageUrl: props.imageUrl,        labels: props.labels,        contextmenu: (e) => {            emit('contextmenu', e)        },        labelClick: (label) => {            emit('labelClick', label)        },        error: (e) => {            emit('error', e)        }    });})</script>
  4. 在react组件中应用simple-image-label:

    import SimpleImageLabel from 'simple-image-label';import img from './x.png'import { useEffect } from 'react';const ImageLabelComponent = () => {    let simpleImageLabel = null    useEffect(() => {        initSimpleDom()    }, [])    function initSimpleDom() {        simpleImageLabel = new SimpleImageLabel({            el: 'YourElementId',            imageUrl: img,            labels: [],            contextmenu: (e) => {                console.log(e);            },            labelClick: (label) => {                console.log(label);            },            error: (e) => {                console.log(e);            }        })    }    function getAllLabels() {        const labels = simpleImageLabel.getLabels()        console.log('labels', labels);    }    return (        <div>            <div id="YourElementId"></div>            <button onClick={getAllLabels}>Get all labels</button>        </div>    );}export default ImageLabelComponent;

我的项目地址:https://github.com/king2088/simple-image-label

如果你喜爱本我的项目,记得在github上给我一个Star