Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
yatengLG committed Apr 19, 2023
1 parent cdc86e9 commit cd1e24a
Show file tree
Hide file tree
Showing 74 changed files with 18,145 additions and 14 deletions.
2 changes: 1 addition & 1 deletion .idea/ISAT_with_segment_anything.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

Copyright 2023 yatengLG

https://github.com/yatengLG/ISAT_with_segment_anything

Licensed 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.
47 changes: 46 additions & 1 deletion README-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,54 @@

segment anything只是协助生成目标掩码,最终标注以多边形呈现,通过拖拽多边形顶点,可快速修改标注区域。

## 安装
### 1. 源码运行
```shell
# 创建虚拟环境
conda create -n ISAT_with_segment_anything python==3.8
conda activate ISAT_with_segment_anything
```

```shell
# 安装Segment anything
git clone git@github.com:facebookresearch/segment-anything.git
cd segment-anything
pip install -e .
cd ..
```

```shell
# 安装ISAT_with_segment_anything
git clone https://github.com/yatengLG/ISAT_with_segment_anything.git
cd ISAT_with_segment_anything
pip install -r requirements.txt
```

```text
# 下载Segment anything预训练模型
下载任一模型,并将模型存放于ISAT_with_segment_anything/segment_any目录下
模型链接:
https://dl.fbaipublicfiles.com/segment_anything/sam_vit_h_4b8939.pth
https://dl.fbaipublicfiles.com/segment_anything/sam_vit_l_0b3195.pth
https://dl.fbaipublicfiles.com/segment_anything/sam_vit_b_01ec64.pth
h模型最大,效果也最好;
b模型最小,效果也最差;
请按照硬件下载合适的模型,h模型在示例样本上的显存需求约8G.
```

```shell
# 运行软件
python main.py
```


## 标注操作

1. 通过鼠标左键(或右键)提示感兴趣区域(或不感兴趣区域),自动形成目标分割掩码
2. 可通过多次左右键提示,提升掩码质量
3. 回车键确认掩码,选择类别,得到多边形标注区域
3. E键结束标注,选择类别,得到多边形标注区域
4. 拖拽多边形顶点,精细化调整标注

## 注意事项
1. 自动分割效果受segment anything模型分割效果限制,如需更为精确的分割效果,可通过手动绘制多边形实现。
2. 如只需要使用手动绘制多边形标注,推荐使用[ISAT](https://github.com/yatengLG/ISAT)
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# ISAT图像分割标注工具

![examples/demo/标注组合图.png](examples/demo/标注组合图.png)

基于多边形的图像分割标注工具,支持实例分割与语义分割。

## 特点
主要对语义标注过程中存在标注重复部分进行优化。
自己标注过分割样本,或者使用coco分割数据集的朋友,肯定遇到过标注多边形之间存在覆盖的问题。
本项目通过引入多边形图层高低的方式,让上层的多边形覆盖下层多边形,从而保证每一个像素的类别都是单一的,降低数据的干扰。

* 支持对多边形图层进行调整(图层置顶或置底)。
* 标注文件转png单通道图(支持实例与语义)。
* 支持滚轮缩放,左键拖动图片。
* 类别标签导入与导出,方便不同任务之间快速切换。
## 安装
### 1. 源码运行
```shell
git clone https://github.com/yatengLG/ISAT.git
cd ISAT
conda create -n ISAT python==3.8
conda activate ISAT
pip install -r requirements.txt
python main.py
```
### 2. 下载打包好的exe
- 2.1 点击[链接](https://github.com/yatengLG/ISAT/releases/download/v1.0.0/ISAT_windows.zip)下载ISAT_windows.zip
- 2.2 解压
- 2.3 双击ISAT/main.exe运行

## 标注结果

### 标注文件与标签图片
ISAT提供了**json格式标注文件**,可以方便的进行传输与二次修改;同时,软件也提供将标注文件转换为**png单通道标签图片**的功能。

#### 1. json格式标注文件
主要用于传输、备份以及二次修改。但不方便直接参与模型训练等过程。

存储信息包括:图片名、图片尺寸、图片额外说明、标注目标类别、标注目标实例id、标注目标多边形顶点等。

#### 2. png单通道标签图片
主要用于模型的训练、测试等过程。

转换后的单通道标签图片具有与原图一致的分辨率,**参与模型训练时,直接读取像素值作为标签即可(图片为单通道图,像素值为单一的值,不是rgb)。**

> 部分软件查看png单通道图片时,存在对颜色边界处进行调整的情况。具体表现为,如 (0, 5, 0)到(0, 255, 0)过渡时,边缘会出现(0, 125, 0)的情况。https://github.com/yatengLG/ISAT/issues/2#issue-1662058434
**最终的标签是图像的像素值,而非颜色值**
这种情况不会对标签图片造成影响,请放心使用。


### 导出png单通道标签图片
软件内置了,将json标注文件转换为png单通道标签图片的工具。

转换时,区分**语义分割****实例分割**
- 语义分割

转换后的语义分割png单通道标签图片中,每个像素值为对应的类别id,具体的类别含义与标注时类别设置相一致,同时在转换目录中也会留存一份classesition.txt,便于查看类别与id对应关系。
- 实例分割

转换后的实例分割png单通道标签图片中,每个像素值为对应的组id。

![examples/demo/将标注结果导出为png单通道图.png](examples/demo/将标注结果导出为png单通道图.png)
84 changes: 84 additions & 0 deletions annotation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
# @Author : LG

import os
import cv2
from json import load, dump
from typing import List


class Object:
def __init__(self, category:str, group:int, segmentation, area, layer, bbox, iscrowd=0, note=''):
self.category = category
self.group = group
self.segmentation = segmentation
self.area = area
self.layer = layer
self.bbox = bbox
self.iscrowd = iscrowd
self.note = note


class Annotation:
def __init__(self, image_path, label_path):
img_folder, img_name = os.path.split(image_path)
self.description = 'ISAT'
self.img_folder = img_folder
self.img_name = img_name
self.label_path = label_path
self.note = ''
image = cv2.imread(image_path)
self.height, self.width, self.depth = image.shape
del image

self.objects:List[Object,...] = []

def load_annotation(self):
if os.path.exists(self.label_path):
with open(self.label_path, 'r') as f:
dataset = load(f)
info = dataset.get('info', {})
objects = dataset.get('objects', [])

self.img_name = info.get('name', '')
self.width = info.get('width', 0)
self.height = info.get('height', 0)
self.depth = info.get('depth', 0)
self.note = info.get('note', '')
for obj in objects:
category = obj.get('category', 'unknow')
group = obj.get('group', '')
segmentation = obj.get('segmentation', [])
iscrowd = obj.get('iscrowd', 0)
note = obj.get('note', '')
area = obj.get('area', 0)
layer = obj.get('layer', 1)
bbox = obj.get('bbox', [])
obj = Object(category, group, segmentation, area, layer, bbox, iscrowd, note)
self.objects.append(obj)

def save_annotation(self):
dataset = {}
dataset['info'] = {}
dataset['info']['description'] = self.description
dataset['info']['folder'] = self.img_folder
dataset['info']['name'] = self.img_name
dataset['info']['width'] = self.width
dataset['info']['height'] = self.height
dataset['info']['depth'] = self.depth
dataset['info']['note'] = self.note
dataset['objects'] = []
for obj in self.objects:
object = {}
object['category'] = obj.category
object['group'] = obj.group
object['segmentation'] = obj.segmentation
object['area'] = obj.area
object['layer'] = obj.layer
object['bbox'] = obj.bbox
object['iscrowd'] = obj.iscrowd
object['note'] = obj.note
dataset['objects'].append(object)
with open(self.label_path, 'w') as f:
dump(dataset, f, indent=4)
return True
35 changes: 35 additions & 0 deletions configs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import yaml
from enum import Enum


DEFAULT_CONFIG_FILE = 'default.yaml'
CONFIG_FILE = 'isat.yaml'

def load_config(file):
with open(file, 'rb')as f:
cfg = yaml.load(f.read(), Loader=yaml.FullLoader)
return cfg

def save_config(cfg, file):
s = yaml.dump(cfg)
with open(file, 'w') as f:
f.write(s)
return True

class STATUSMode(Enum):
VIEW = 0
CREATE = 1
EDIT = 2

class DRAWMode(Enum):
POLYGON = 0
SEGMENTANYTHING = 1

class CLICKMode(Enum):
POSITIVE = 0
NEGATIVE = 1

class MAPMode(Enum):
LABEL = 0
SEMANTIC = 1
INSTANCE = 2
3 changes: 3 additions & 0 deletions default.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
label:
- color: '#000000'
name: __background__
Binary file added example/images/000000000113.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit cd1e24a

Please sign in to comment.