From febf35fc4409732912e21f3d92e8504859684d3c Mon Sep 17 00:00:00 2001
From: yatenglg <767624851@qq.com>
Date: Fri, 28 Apr 2023 22:13:50 +0800
Subject: [PATCH] update
---
 .idea/misc.xml                 |   2 +-
 UpdateLog.md                   |   8 +-
 isat.yaml                      |   2 +-
 tools/toCOCO.py                | 294 +++++++++++++++++++++++++++++++++
 tools/toVOC.py                 |   2 +-
 tools/tococo.py                | 200 ----------------------
 ui/COCO_to_ISAT_dialog.py      | 109 ++++++++++++
 ui/COCO_to_ISAT_dialog.ui      | 211 +++++++++++++++++++++++
 ui/ISAT_to_COCO_dialog.py      |  98 +++++++++++
 ui/ISAT_to_COCO_dialog.ui      | 185 +++++++++++++++++++++
 ui/MainWindow.py               |  16 +-
 ui/MainWindow.ui               |  27 ++-
 widgets/COCO_to_ISAT_dialog.py |  69 ++++++++
 widgets/ISAT_to_COCO_dialog.py |  69 ++++++++
 widgets/ISAT_to_VOC_dialog.py  |   4 +-
 widgets/converter.py           |  86 ----------
 widgets/mainwindow.py          |  18 +-
 17 files changed, 1095 insertions(+), 305 deletions(-)
 create mode 100644 tools/toCOCO.py
 delete mode 100644 tools/tococo.py
 create mode 100644 ui/COCO_to_ISAT_dialog.py
 create mode 100644 ui/COCO_to_ISAT_dialog.ui
 create mode 100644 ui/ISAT_to_COCO_dialog.py
 create mode 100644 ui/ISAT_to_COCO_dialog.ui
 create mode 100644 widgets/COCO_to_ISAT_dialog.py
 create mode 100644 widgets/ISAT_to_COCO_dialog.py
 delete mode 100644 widgets/converter.py
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 3f589e5..b47cefa 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,4 +1,4 @@
 
 
-  
+  
 
\ No newline at end of file
diff --git a/UpdateLog.md b/UpdateLog.md
index 0881d32..123910e 100644
--- a/UpdateLog.md
+++ b/UpdateLog.md
@@ -1,4 +1,4 @@
-# 20240424
+# 
 
 - 添加了对labelme格式json的支持(只支持标注的多边形)
 
@@ -16,6 +16,6 @@
 - bug修复
 
 # 
-- 添加转换voc格式png图片的功能 finish
-- 添加转换coco格式json的功能 ing
-- 添加转换coco格式json转ISAT格式json的功能 ing
\ No newline at end of file
+- 添加转换voc格式png图片的功能(单通道png)
+- 添加转换coco格式json的功能(ISAT jsons to COCO json)
+- 添加转换coco格式json转ISAT格式json的功能(COCO json to ISAT jsons)
\ No newline at end of file
diff --git a/isat.yaml b/isat.yaml
index 9376fac..f5f0b9a 100644
--- a/isat.yaml
+++ b/isat.yaml
@@ -19,4 +19,4 @@ label:
   name: cake
 - color: '#5c3566'
   name: fence
-language: zh
+language: en
diff --git a/tools/toCOCO.py b/tools/toCOCO.py
new file mode 100644
index 0000000..cc2257d
--- /dev/null
+++ b/tools/toCOCO.py
@@ -0,0 +1,294 @@
+# -*- coding: utf-8 -*-
+# @Author  : LG
+
+from json import load, dump
+import os
+from pycocotools import mask as coco_mask
+import cv2
+import imgviz
+import yaml
+import numpy as np
+
+
+class COCOConverter:
+    def convert_to_coco(self, isat_json_root:str, to_path:str):
+        coco_anno = {}
+        # info
+        coco_anno['info'] = {}
+        coco_anno['info']['description'] = 'coco from ISAT'
+        coco_anno['info']['version'] = None
+        coco_anno['info']['year'] = None
+        coco_anno['info']['contributor'] = None
+        coco_anno['info']['date_created'] = None
+
+        # licenses
+        coco_anno['licenses'] = []
+        license1 = {}
+        license1['url'] = None
+        license1['id'] = 0
+        license1['name'] = None
+        coco_anno['licenses'].append(license1)
+
+        # images and annotations
+        coco_anno['images'] = []
+        coco_anno['annotations'] = []
+        coco_anno['categories'] = []
+
+        categories_dict = {}
+
+        jsons = [f for f in os.listdir(isat_json_root) if f.endswith('.json')]
+        for file_index, json in enumerate(jsons):
+            print('Load ISAT: {}'.format(json))
+            try:
+                with open(os.path.join(isat_json_root, json), 'r') as f:
+                    dataset = load(f)
+                    info = dataset.get('info', {})
+                    description = info.get('description', '')
+                    if not description.startswith('ISAT'):
+                        # 不是ISAT格式json
+                        continue
+
+                    img_name = info.get('name', '')
+                    width = info.get('width', None)
+                    height = info.get('height', None)
+                    depth = info.get('depth', None)
+                    note = info.get('note', '')
+                    objects = dataset.get('objects', [])
+
+                    # image
+                    coco_image_info = {}
+                    coco_image_info['license'] = None
+                    coco_image_info['url'] = None
+                    coco_image_info['file_name'] = img_name
+                    coco_image_info['height'] = height
+                    coco_image_info['width'] = width
+                    coco_image_info['date_captured'] = None
+                    coco_image_info['id'] = file_index
+                    coco_anno['images'].append(coco_image_info)
+
+                    objects_groups = [obj.get('group', 0) for obj in objects]
+                    objects_groups.sort()
+                    objects_groups = set(objects_groups)
+                    # 同group
+                    for group_index, group in enumerate(objects_groups):
+                        objs_with_group = [obj for obj in objects if obj.get('group', 0) == group]
+                        cats = [obj.get('category', 'unknow') for obj in objs_with_group]
+                        cats = set(cats)
+                        # 同category
+                        for cat in cats:
+                            if cat not in categories_dict:
+                                categories_dict[cat] = len(categories_dict)
+                            category_index = categories_dict.get(cat)
+
+                            objs_with_cat = [obj for obj in objs_with_group if obj.get('category', 0) == cat]
+                            crowds = [obj.get('iscrowd', 'unknow') for obj in objs_with_group]
+                            crowds = set(crowds)
+                            # 同iscrowd
+                            for crowd in crowds:
+                                objs_with_crowd = [obj for obj in objs_with_cat if obj.get('iscrowd', 0) == crowd]
+                                # anno
+                                coco_anno_info = {}
+                                coco_anno_info['iscrowd'] = crowd
+                                coco_anno_info['image_id'] = file_index
+                                coco_anno_info['image_name'] = img_name
+                                coco_anno_info['category_id'] = category_index
+                                coco_anno_info['id'] = len(coco_anno['annotations'])
+                                coco_anno_info['segmentation'] = []
+                                coco_anno_info['area'] = 0.
+                                coco_anno_info['bbox'] = []
+
+                                for obj in objs_with_crowd:
+
+                                    segmentation = obj.get('segmentation', [])
+                                    area = obj.get('area', 0)
+                                    bbox = obj.get('bbox', [])
+                                    if bbox is None:
+                                        segmentation_nd = np.array(segmentation)
+                                        bbox = [min(segmentation_nd[:, 0]), min(segmentation_nd[:, 1]),
+                                                max(segmentation_nd[:, 0]), max(segmentation_nd[:, 1])]
+                                        del segmentation_nd
+                                    segmentation = [e for p in segmentation for e in p]
+
+
+
+                                    if bbox != []:
+                                        if coco_anno_info['bbox'] == []:
+                                            coco_anno_info['bbox'] = bbox
+                                        else:
+                                            bbox_tmp = coco_anno_info['bbox']
+                                            bbox_tmp = [min(bbox_tmp[0], bbox[0]), min(bbox_tmp[1], bbox[1]),
+                                                        max(bbox_tmp[2], bbox[2]), max(bbox_tmp[3], bbox[3])]
+                                            coco_anno_info['bbox'] = bbox_tmp
+                                    coco_anno_info['segmentation'].append(segmentation)
+                                    if area is not None:
+                                        coco_anno_info['area'] += float(area)
+
+                                # (xmin, ymin, xmax, ymax) 2 (xmin, ymin, w, h)
+                                bbox_tmp = coco_anno_info['bbox']
+                                coco_anno_info['bbox'] = [bbox_tmp[0], bbox_tmp[1],
+                                                          bbox_tmp[2] - bbox_tmp[0], bbox_tmp[3] - bbox_tmp[1]]
+
+                                coco_anno['annotations'].append(coco_anno_info)
+            except Exception as e:
+                print('Load ISAT: {}, error: {}'.format(json, e))
+
+        categories_dict = sorted(categories_dict.items(), key=lambda x:x[1])
+        coco_anno['categories'] = [{'name': name, 'id': id, 'supercategory': None} for name, id in categories_dict]
+
+        with open(to_path, 'w') as f:
+            try:
+                dump(coco_anno, f)
+                print('Save coco json to {}'.format(to_path))
+            except Exception as e:
+                print('Save {} error :{}'.format(to_path, e))
+
+
+    def convert_from_coco(self, coco_json_path:str, to_root:str, keep_crowd:bool=False):
+        assert coco_json_path.endswith('.json')
+        annos = {}
+        if os.path.exists(coco_json_path):
+            with open(coco_json_path, 'r') as f:
+                dataset = load(f)
+                images = {image.get('id', None):{
+                    'file_name': image.get('file_name', ''),
+                    'height': image.get('height', ''),
+                    'width': image.get('width', ''),
+                } for image in dataset.get('images', [])}
+                annotations = dataset.get('annotations', [])
+                categories = {categorie.get('id', None): {'name': categorie.get('name', '')} for categorie in dataset.get('categories', [])}
+                for index, annotation in enumerate(annotations):
+
+                    annotation_index = annotation.get('id')
+                    annotation_image_id = annotation.get('image_id')
+                    annotation_category_id = annotation.get('category_id')
+
+                    file_name = images[annotation_image_id].get('file_name')
+                    height = images[annotation_image_id].get('height')
+                    width = images[annotation_image_id].get('width')
+                    iscrowd = annotation["iscrowd"]
+
+                    if file_name == '000000279278.jpg':
+                        continue
+                    if annotation_image_id not in annos:
+                        annos[annotation_image_id] = {}
+
+                    objects = annos[annotation_image_id].get('objects', [])
+
+                    if iscrowd == 0:
+                        # polygon
+                        segmentations = annotation.get('segmentation')
+                        for segmentation in segmentations:
+                            xs = segmentation[::2]
+                            ys = segmentation[1::2]
+                            points = [[x, y] for x ,y in zip(xs, ys)]
+                            obj = {
+                                'category': categories.get(annotation_category_id).get('name'),
+                                'group': annotation_index,
+                                'area': None,
+                                'segmentation': points,
+                                'layer': 1,
+                                'bbox': None,
+                                'iscrowd': iscrowd,
+                                'note': ''
+                            }
+                            objects.append(obj)
+                    elif iscrowd == 1 and keep_crowd:
+                        segmentations = annotation.get('segmentation', {})
+                        if isinstance(segmentations, dict) and 'counts' in segmentations:
+                            # RLE
+                            rles = coco_mask.frPyObjects(segmentations, height, width)
+                            masks = coco_mask.decode(rles)
+                            contours, _ = cv2.findContours(masks, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_KCOS)
+                            for contour in contours:
+                                points = []
+                                for point in contour:
+                                    x, y = point[0]
+                                    points.append([float(x), float(y)])
+                                obj = {
+                                    'category': categories.get(annotation_category_id).get('name'),
+                                    'group': annotation_index,
+                                    'area': None,
+                                    'segmentation': points,
+                                    'layer': 1,
+                                    'bbox': None,
+                                    'iscrowd': iscrowd,
+                                    'note': ''
+                                }
+                                objects.append(obj)
+                        else:
+                            # polygon
+                            for segmentation in segmentations:
+                                xs = segmentation[::2]
+                                ys = segmentation[1::2]
+                                points = [[x, y] for x, y in zip(xs, ys)]
+                                obj = {
+                                    'category': categories.get(annotation_category_id).get('name'),
+                                    'group': annotation_index,
+                                    'area': None,
+                                    'segmentation': points,
+                                    'layer': 1,
+                                    'bbox': None,
+                                    'iscrowd': iscrowd,
+                                    'note': ''
+                                }
+                                objects.append(obj)
+                    else:
+                        pass
+                    annos[annotation_image_id]['objects'] = objects
+
+
+                for image_id, values in annos.items():
+                    image_path = images[image_id].get('file_name')
+                    folder, name = os.path.split(image_path)
+                    height = images[image_id].get('height')
+                    width = images[image_id].get('width')
+                    objects = values.get('objects', [])
+
+                    isat_anno = {}
+                    isat_anno['info'] = {}
+                    isat_anno['info']['description'] = 'ISAT'
+                    isat_anno['info']['folder'] = folder
+                    isat_anno['info']['name'] = name
+                    isat_anno['info']['width'] = width
+                    isat_anno['info']['height'] = height
+                    isat_anno['info']['depth'] = None
+                    isat_anno['info']['note'] = ''
+                    isat_anno['objects'] = []
+                    # coco annotation的id 太大了,这里缩一下,每张图片重新开始计数
+                    groups_dict = {}
+                    for obj in objects:
+                        group = obj.get('group', 0)
+                        if group not in groups_dict:
+                            groups_dict[group] = len(groups_dict)+1
+                    for obj in objects:
+                        object = {}
+                        object['category'] = obj.get('category', '')
+                        object['group'] = groups_dict.get(obj.get('group', 0))
+                        object['segmentation'] = obj.get('segmentation', [])
+                        object['area'] = obj.get('area', None)
+                        object['layer'] = obj.get('layer', None)
+                        object['bbox'] = obj.get('bbox', None)
+                        object['iscrowd'] = obj.get('iscrowd', 0)
+                        object['note'] = obj.get('note', '')
+                        isat_anno['objects'].append(object)
+                    json_name = '.'.join(name.split('.')[:-1]) + '.json'
+                    save_json = os.path.join(to_root, json_name)
+                    with open(save_json, 'w') as f:
+                        try:
+                            dump(isat_anno, f)
+                            print('Converted coco to ISAT: {}'.format(json_name))
+
+                        except Exception as e:
+                            print('Convert coco to ISAT {} ,error: {}'.format(json_name, e))
+
+                ### 类别文件
+                cmap = imgviz.label_colormap()
+                sorted(categories)
+                for index, (k, categorie_dict) in enumerate(categories.items()):
+                    r, g, b = cmap[index+1]
+                    categorie_dict['color'] = "#{:02x}{:02x}{:02x}".format(r, g, b)
+                print(categories)
+
+                s = yaml.dump({'label': list(categories.values())})
+                with open(os.path.join(to_root, 'categorys.yaml'), 'w') as f:
+                    f.write(s)
diff --git a/tools/toVOC.py b/tools/toVOC.py
index e5dd5e3..3baa54e 100644
--- a/tools/toVOC.py
+++ b/tools/toVOC.py
@@ -8,7 +8,7 @@ import mahotas
 import imgviz
 
 
-class ToVOC:
+class VOCConverter:
     def __init__(self, cfg, is_segmentation):
         self.is_segmentation = is_segmentation
 
diff --git a/tools/tococo.py b/tools/tococo.py
deleted file mode 100644
index 99aa07d..0000000
--- a/tools/tococo.py
+++ /dev/null
@@ -1,200 +0,0 @@
-# -*- coding: utf-8 -*-
-# @Author  : LG
-
-from json import load, dump
-import os
-from pycocotools import mask as coco_mask
-import cv2
-import imgviz
-
-
-class COCOConverter:
-    def __init__(self, ):
-        pass
-        # labels = cfg.get('label', [])
-        # for index, label_dict in enumerate(labels):
-        #     category = label_dict.get('name', 'unknow')
-        #     color = label_dict.get('color', '#000000')
-
-    def convert_to_coco(self, isat_json_root:str, to_path:str):
-        coco_anno = {}
-        # info
-        coco_anno['info'] = {}
-        coco_anno['info']['description'] = 'coco from ISAT'
-        coco_anno['info']['version'] = None
-        coco_anno['info']['year'] = None
-        coco_anno['info']['contributor'] = None
-        coco_anno['info']['date_created'] = None
-
-        # licenses
-        coco_anno['licenses'] = []
-        coco_anno['licenses'][0] = {}
-        coco_anno['licenses'][0]['url'] = None
-        coco_anno['licenses'][0]['id'] = 0
-        coco_anno['licenses'][0]['name'] = None
-
-        # images and annotations
-        coco_anno['images'] = []
-        coco_anno['annotations'] = []
-
-        jsons = [f for f in os.listdir(isat_json_root) if f.endswith('.json')]
-        for json in jsons:
-            coco_image_info = {}
-
-            dataset = load(os.path.join(isat_json_root, json))
-            info = dataset.get('info', {})
-            description = info.get('description', '')
-            if not description.startswith('ISAT'):
-                # 不是ISAT格式json
-                continue
-            img_name = info.get('name', '')
-            width = info.get('width', None)
-            height = info.get('height', None)
-            depth = info.get('depth', None)
-            note = info.get('note', '')
-            objects = dataset.get('objects', [])
-            for obj in objects:
-                category = obj.get('category', 'unknow')
-                group = obj.get('group', 0)
-                if group is None: group = 0
-                segmentation = obj.get('segmentation', [])
-                iscrowd = obj.get('iscrowd', 0)
-                note = obj.get('note', '')
-                area = obj.get('area', 0)
-                layer = obj.get('layer', 2)
-                bbox = obj.get('bbox', [])
-
-
-
-    def convert_from_coco(self, coco_json:str, to_path:str, keep_crowd:bool=False):
-        assert coco_json.endswith('.json')
-        annos = {}
-        if os.path.exists(coco_json):
-            with open(coco_json, 'r') as f:
-                dataset = load(f)
-                images = {image.get('id', None):{
-                    'file_name': image.get('file_name', ''),
-                    'height': image.get('height', ''),
-                    'width': image.get('width', ''),
-                } for image in dataset.get('images', [])}
-                annotations = dataset.get('annotations', [])
-                categories = {categorie.get('id', None): {'name': categorie.get('name', '')} for categorie in dataset.get('categories', [])}
-                for index, annotation in enumerate(annotations):
-
-                    annotation_index = annotation.get('id')
-                    annotation_image_id = annotation.get('image_id')
-                    annotation_category_id = annotation.get('category_id')
-
-                    file_name = images[annotation_image_id].get('file_name')
-                    height = images[annotation_image_id].get('height')
-                    width = images[annotation_image_id].get('width')
-                    iscrowd = annotation["iscrowd"]
-
-                    if file_name == '000000279278.jpg':
-                        continue
-                    if annotation_image_id not in annos:
-                        annos[annotation_image_id] = {}
-
-                    objects = annos[annotation_image_id].get('objects', [])
-
-                    if iscrowd == 0:
-                        # polygon
-                        segmentations = annotation.get('segmentation')
-                        for segmentation in segmentations:
-                            xs = segmentation[::2]
-                            ys = segmentation[1::2]
-                            points = [[x, y] for x ,y in zip(xs, ys)]
-                            obj = {
-                                'category': categories.get(annotation_category_id).get('name'),
-                                'group': annotation_index,
-                                'area': None,
-                                'segmentation': points,
-                                'layer': 1,
-                                'bbox': None,
-                                'iscrowd': iscrowd,
-                                'note': ''
-                            }
-                            objects.append(obj)
-                    elif iscrowd == 1 and keep_crowd:
-                        # RLE
-                        segmentations = annotation.get('segmentation', {})
-                        rles = coco_mask.frPyObjects(segmentations, height, width)
-                        masks = coco_mask.decode(rles)
-                        contours, _ = cv2.findContours(masks, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_KCOS)
-                        for contour in contours:
-                            points = []
-                            for point in contour:
-                                x, y = point[0]
-                                points.append([float(x), float(y)])
-                            obj = {
-                                'category': categories.get(annotation_category_id).get('name'),
-                                'group': annotation_index,
-                                'area': None,
-                                'segmentation': points,
-                                'layer': 1,
-                                'bbox': None,
-                                'iscrowd': iscrowd,
-                                'note': ''
-                            }
-                            objects.append(obj)
-
-                    else:
-                        pass
-                    annos[annotation_image_id]['objects'] = objects
-
-
-                for image_id, values in annos.items():
-                    image_path = images[image_id].get('file_name')
-                    folder, name = os.path.split(image_path)
-                    height = images[image_id].get('height')
-                    width = images[image_id].get('width')
-                    objects = values.get('objects', [])
-
-                    isat_anno = {}
-                    isat_anno['info'] = {}
-                    isat_anno['info']['description'] = 'ISAT'
-                    isat_anno['info']['folder'] = folder
-                    isat_anno['info']['name'] = name
-                    isat_anno['info']['width'] = width
-                    isat_anno['info']['height'] = height
-                    isat_anno['info']['depth'] = None
-                    isat_anno['info']['note'] = ''
-                    isat_anno['objects'] = []
-                    # coco annotation的id 太大了,这里缩一下,每张图片重新开始计数
-                    groups_dict = {}
-                    for obj in objects:
-                        group = obj.get('group', 0)
-                        if group not in groups_dict:
-                            groups_dict[group] = len(groups_dict)+1
-                    for obj in objects:
-                        object = {}
-                        object['category'] = obj.get('category', '')
-                        object['group'] = groups_dict.get(obj.get('group', 0))
-                        object['segmentation'] = obj.get('segmentation', [])
-                        object['area'] = obj.get('area', None)
-                        object['layer'] = obj.get('layer', None)
-                        object['bbox'] = obj.get('bbox', None)
-                        object['iscrowd'] = obj.get('iscrowd', 0)
-                        object['note'] = obj.get('note', '')
-                        isat_anno['objects'].append(object)
-                    json_name = '.'.join(name.split('.')[:-1]) + '.json'
-                    save_json = os.path.join(to_path, json_name)
-                    with open(save_json, 'w') as f:
-                        try:
-                            dump(isat_anno, f)
-                            print('Converted coco to ISAT: {}'.format(json_name))
-
-                        except Exception as e:
-                            print('Convert coco to ISAT {} ,error: {}'.format(json_name, e))
-
-                    ### 类别文件
-                    cmap = imgviz.label_colormap()
-
-
-if __name__ == '__main__':
-    coco = COCOConverter()
-    coco.convert_from_coco(
-        '/mnt/disk/coco/annotations/instances_val2017.json',
-        '/mnt/disk/coco/isat_json',
-        True
-    )
\ No newline at end of file
diff --git a/ui/COCO_to_ISAT_dialog.py b/ui/COCO_to_ISAT_dialog.py
new file mode 100644
index 0000000..b574486
--- /dev/null
+++ b/ui/COCO_to_ISAT_dialog.py
@@ -0,0 +1,109 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'COCO_to_ISAT_dialog.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.7
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+class Ui_Dialog(object):
+    def setupUi(self, Dialog):
+        Dialog.setObjectName("Dialog")
+        Dialog.setWindowModality(QtCore.Qt.NonModal)
+        Dialog.resize(514, 202)
+        font = QtGui.QFont()
+        font.setFamily("Times New Roman")
+        font.setPointSize(12)
+        Dialog.setFont(font)
+        Dialog.setSizeGripEnabled(False)
+        Dialog.setModal(False)
+        self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
+        self.verticalLayout.setObjectName("verticalLayout")
+        self.widget = QtWidgets.QWidget(Dialog)
+        self.widget.setObjectName("widget")
+        self.gridLayout = QtWidgets.QGridLayout(self.widget)
+        self.gridLayout.setContentsMargins(0, 0, 0, 0)
+        self.gridLayout.setObjectName("gridLayout")
+        self.pushButton_save_root = QtWidgets.QPushButton(self.widget)
+        self.pushButton_save_root.setObjectName("pushButton_save_root")
+        self.gridLayout.addWidget(self.pushButton_save_root, 3, 1, 1, 1)
+        self.pushButton_label_path = QtWidgets.QPushButton(self.widget)
+        self.pushButton_label_path.setObjectName("pushButton_label_path")
+        self.gridLayout.addWidget(self.pushButton_label_path, 2, 1, 1, 1)
+        self.lineEdit_save_root = QtWidgets.QLineEdit(self.widget)
+        self.lineEdit_save_root.setEnabled(True)
+        self.lineEdit_save_root.setReadOnly(True)
+        self.lineEdit_save_root.setObjectName("lineEdit_save_root")
+        self.gridLayout.addWidget(self.lineEdit_save_root, 3, 0, 1, 1)
+        self.lineEdit_label_path = QtWidgets.QLineEdit(self.widget)
+        self.lineEdit_label_path.setEnabled(True)
+        self.lineEdit_label_path.setReadOnly(True)
+        self.lineEdit_label_path.setObjectName("lineEdit_label_path")
+        self.gridLayout.addWidget(self.lineEdit_label_path, 2, 0, 1, 1)
+        self.verticalLayout.addWidget(self.widget)
+        self.widget_3 = QtWidgets.QWidget(Dialog)
+        self.widget_3.setObjectName("widget_3")
+        self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.widget_3)
+        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
+        spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+        self.horizontalLayout_2.addItem(spacerItem)
+        self.checkBox_keepcrowd = QtWidgets.QCheckBox(self.widget_3)
+        self.checkBox_keepcrowd.setObjectName("checkBox_keepcrowd")
+        self.horizontalLayout_2.addWidget(self.checkBox_keepcrowd)
+        self.verticalLayout.addWidget(self.widget_3)
+        self.widget_4 = QtWidgets.QWidget(Dialog)
+        self.widget_4.setObjectName("widget_4")
+        self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.widget_4)
+        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
+        spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+        self.horizontalLayout_3.addItem(spacerItem1)
+        self.label_info = QtWidgets.QLabel(self.widget_4)
+        self.label_info.setText("")
+        self.label_info.setObjectName("label_info")
+        self.horizontalLayout_3.addWidget(self.label_info)
+        self.verticalLayout.addWidget(self.widget_4)
+        self.widget_2 = QtWidgets.QWidget(Dialog)
+        self.widget_2.setObjectName("widget_2")
+        self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget_2)
+        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
+        self.horizontalLayout.setObjectName("horizontalLayout")
+        self.label = QtWidgets.QLabel(self.widget_2)
+        self.label.setStyleSheet("color: rgb(255, 0, 0);")
+        self.label.setObjectName("label")
+        self.horizontalLayout.addWidget(self.label)
+        spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+        self.horizontalLayout.addItem(spacerItem2)
+        self.pushButton_cache = QtWidgets.QPushButton(self.widget_2)
+        icon = QtGui.QIcon()
+        icon.addPixmap(QtGui.QPixmap(":/icons/icons/关闭_close-one.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+        self.pushButton_cache.setIcon(icon)
+        self.pushButton_cache.setObjectName("pushButton_cache")
+        self.horizontalLayout.addWidget(self.pushButton_cache)
+        self.pushButton_apply = QtWidgets.QPushButton(self.widget_2)
+        icon1 = QtGui.QIcon()
+        icon1.addPixmap(QtGui.QPixmap(":/icons/icons/校验_check-one.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+        self.pushButton_apply.setIcon(icon1)
+        self.pushButton_apply.setObjectName("pushButton_apply")
+        self.horizontalLayout.addWidget(self.pushButton_apply)
+        self.verticalLayout.addWidget(self.widget_2)
+
+        self.retranslateUi(Dialog)
+        QtCore.QMetaObject.connectSlotsByName(Dialog)
+
+    def retranslateUi(self, Dialog):
+        _translate = QtCore.QCoreApplication.translate
+        Dialog.setWindowTitle(_translate("Dialog", "ISAT to VOC png"))
+        self.pushButton_save_root.setText(_translate("Dialog", "Save root"))
+        self.pushButton_label_path.setText(_translate("Dialog", "Json path"))
+        self.lineEdit_save_root.setPlaceholderText(_translate("Dialog", "ISAT jsons save root"))
+        self.lineEdit_label_path.setPlaceholderText(_translate("Dialog", "COCO json path"))
+        self.checkBox_keepcrowd.setText(_translate("Dialog", "Keep crowd"))
+        self.label.setText(_translate("Dialog", "Convert COCO json to ISAT jsons."))
+        self.pushButton_cache.setText(_translate("Dialog", "cache"))
+        self.pushButton_apply.setText(_translate("Dialog", "convert"))
+import icons_rc
diff --git a/ui/COCO_to_ISAT_dialog.ui b/ui/COCO_to_ISAT_dialog.ui
new file mode 100644
index 0000000..557a10b
--- /dev/null
+++ b/ui/COCO_to_ISAT_dialog.ui
@@ -0,0 +1,211 @@
+
+
+ Dialog
+ 
+  
+   Qt::NonModal
+  
+  
+   
+    0
+    0
+    514
+    202
+   
+  
+  
+   
+    Times New Roman
+    12
+   
+  
+  
+   ISAT to VOC png
+  
+  
+   false
+  
+  
+   false
+  
+  
+   - 
+    
+     
+      
+       0
+      
+      
+       0
+      
+      
+       0
+      
+      
+       0
+      
+      - 
+       
+        
+         Save root
+        
+       
+      +
- 
+       
+        
+         Json path
+        
+       
+      +
- 
+       
+        
+         true
+        
+        
+         true
+        
+        
+         ISAT jsons save root
+        
+       
+      +
- 
+       
+        
+         true
+        
+        
+         true
+        
+        
+         COCO json path
+        
+       
+      +     
+    
+
+- 
+    
+     
+      - 
+       
+        
+         Qt::Horizontal
+        
+        
+         
+          40
+          20
+         
+        
+       
+      +
- 
+       
+        
+         Keep crowd
+        
+       
+      +     
+    
+
+- 
+    
+     
+      - 
+       
+        
+         Qt::Horizontal
+        
+        
+         
+          40
+          20
+         
+        
+       
+      +
- 
+       
+        
+         
+        
+       
+      +     
+    
+
+- 
+    
+     
+      
+       0
+      
+      
+       0
+      
+      
+       0
+      
+      
+       0
+      
+      - 
+       
+        
+         color: rgb(255, 0, 0);
+        
+        
+         Convert COCO json to ISAT jsons.
+        
+       
+      +
- 
+       
+        
+         Qt::Horizontal
+        
+        
+         
+          40
+          20
+         
+        
+       
+      +
- 
+       
+        
+         cache
+        
+        
+         
+          :/icons/icons/关闭_close-one.svg:/icons/icons/关闭_close-one.svg
+        
+       
+      +
- 
+       
+        
+         convert
+        
+        
+         
+          :/icons/icons/校验_check-one.svg:/icons/icons/校验_check-one.svg
+        
+       
+      +     
+    
+
+  
+ 
+ 
+  
+ 
+ 
+
diff --git a/ui/ISAT_to_COCO_dialog.py b/ui/ISAT_to_COCO_dialog.py
new file mode 100644
index 0000000..a171bfc
--- /dev/null
+++ b/ui/ISAT_to_COCO_dialog.py
@@ -0,0 +1,98 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'ISAT_to_COCO_dialog.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.7
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+class Ui_Dialog(object):
+    def setupUi(self, Dialog):
+        Dialog.setObjectName("Dialog")
+        Dialog.setWindowModality(QtCore.Qt.NonModal)
+        Dialog.resize(508, 155)
+        font = QtGui.QFont()
+        font.setFamily("Times New Roman")
+        font.setPointSize(12)
+        Dialog.setFont(font)
+        Dialog.setSizeGripEnabled(False)
+        Dialog.setModal(False)
+        self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
+        self.verticalLayout.setObjectName("verticalLayout")
+        self.widget = QtWidgets.QWidget(Dialog)
+        self.widget.setObjectName("widget")
+        self.gridLayout = QtWidgets.QGridLayout(self.widget)
+        self.gridLayout.setContentsMargins(0, 0, 0, 0)
+        self.gridLayout.setObjectName("gridLayout")
+        self.pushButton_save_path = QtWidgets.QPushButton(self.widget)
+        self.pushButton_save_path.setObjectName("pushButton_save_path")
+        self.gridLayout.addWidget(self.pushButton_save_path, 3, 1, 1, 1)
+        self.pushButton_label_root = QtWidgets.QPushButton(self.widget)
+        self.pushButton_label_root.setObjectName("pushButton_label_root")
+        self.gridLayout.addWidget(self.pushButton_label_root, 2, 1, 1, 1)
+        self.lineEdit_save_path = QtWidgets.QLineEdit(self.widget)
+        self.lineEdit_save_path.setEnabled(True)
+        self.lineEdit_save_path.setReadOnly(True)
+        self.lineEdit_save_path.setObjectName("lineEdit_save_path")
+        self.gridLayout.addWidget(self.lineEdit_save_path, 3, 0, 1, 1)
+        self.lineEdit_label_root = QtWidgets.QLineEdit(self.widget)
+        self.lineEdit_label_root.setEnabled(True)
+        self.lineEdit_label_root.setReadOnly(True)
+        self.lineEdit_label_root.setObjectName("lineEdit_label_root")
+        self.gridLayout.addWidget(self.lineEdit_label_root, 2, 0, 1, 1)
+        self.verticalLayout.addWidget(self.widget)
+        self.widget_3 = QtWidgets.QWidget(Dialog)
+        self.widget_3.setObjectName("widget_3")
+        self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.widget_3)
+        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
+        spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+        self.horizontalLayout_2.addItem(spacerItem)
+        self.label_info = QtWidgets.QLabel(self.widget_3)
+        self.label_info.setText("")
+        self.label_info.setObjectName("label_info")
+        self.horizontalLayout_2.addWidget(self.label_info)
+        self.verticalLayout.addWidget(self.widget_3)
+        self.widget_2 = QtWidgets.QWidget(Dialog)
+        self.widget_2.setObjectName("widget_2")
+        self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget_2)
+        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
+        self.horizontalLayout.setObjectName("horizontalLayout")
+        self.label = QtWidgets.QLabel(self.widget_2)
+        self.label.setStyleSheet("color: rgb(255, 0, 0);")
+        self.label.setObjectName("label")
+        self.horizontalLayout.addWidget(self.label)
+        spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+        self.horizontalLayout.addItem(spacerItem1)
+        self.pushButton_cache = QtWidgets.QPushButton(self.widget_2)
+        icon = QtGui.QIcon()
+        icon.addPixmap(QtGui.QPixmap(":/icons/icons/关闭_close-one.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+        self.pushButton_cache.setIcon(icon)
+        self.pushButton_cache.setObjectName("pushButton_cache")
+        self.horizontalLayout.addWidget(self.pushButton_cache)
+        self.pushButton_apply = QtWidgets.QPushButton(self.widget_2)
+        icon1 = QtGui.QIcon()
+        icon1.addPixmap(QtGui.QPixmap(":/icons/icons/校验_check-one.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+        self.pushButton_apply.setIcon(icon1)
+        self.pushButton_apply.setObjectName("pushButton_apply")
+        self.horizontalLayout.addWidget(self.pushButton_apply)
+        self.verticalLayout.addWidget(self.widget_2)
+
+        self.retranslateUi(Dialog)
+        QtCore.QMetaObject.connectSlotsByName(Dialog)
+
+    def retranslateUi(self, Dialog):
+        _translate = QtCore.QCoreApplication.translate
+        Dialog.setWindowTitle(_translate("Dialog", "ISAT to VOC png"))
+        self.pushButton_save_path.setText(_translate("Dialog", "Save path"))
+        self.pushButton_label_root.setText(_translate("Dialog", "Jsons root"))
+        self.lineEdit_save_path.setPlaceholderText(_translate("Dialog", "COCO json save path"))
+        self.lineEdit_label_root.setPlaceholderText(_translate("Dialog", "ISAT jsons root"))
+        self.label.setText(_translate("Dialog", "Convert ISAT jsons to COCO json."))
+        self.pushButton_cache.setText(_translate("Dialog", "cache"))
+        self.pushButton_apply.setText(_translate("Dialog", "convert"))
+import icons_rc
diff --git a/ui/ISAT_to_COCO_dialog.ui b/ui/ISAT_to_COCO_dialog.ui
new file mode 100644
index 0000000..f1acc8c
--- /dev/null
+++ b/ui/ISAT_to_COCO_dialog.ui
@@ -0,0 +1,185 @@
+
+
+ Dialog
+ 
+  
+   Qt::NonModal
+  
+  
+   
+    0
+    0
+    508
+    155
+   
+  
+  
+   
+    Times New Roman
+    12
+   
+  
+  
+   ISAT to VOC png
+  
+  
+   false
+  
+  
+   false
+  
+  
+- 
+    
+     
+      
+       0
+      
+      
+       0
+      
+      
+       0
+      
+      
+       0
+      
+      - 
+       
+        
+         Save path
+        
+       
+      +
- 
+       
+        
+         Jsons root
+        
+       
+      +
- 
+       
+        
+         true
+        
+        
+         true
+        
+        
+         COCO json save path
+        
+       
+      +
- 
+       
+        
+         true
+        
+        
+         true
+        
+        
+         ISAT jsons root
+        
+       
+      +     
+    
+
+- 
+    
+     
+      - 
+       
+        
+         Qt::Horizontal
+        
+        
+         
+          40
+          20
+         
+        
+       
+      +
- 
+       
+        
+         
+        
+       
+      +     
+    
+
+- 
+    
+     
+      
+       0
+      
+      
+       0
+      
+      
+       0
+      
+      
+       0
+      
+      - 
+       
+        
+         color: rgb(255, 0, 0);
+        
+        
+         Convert ISAT jsons to COCO json.
+        
+       
+      +
- 
+       
+        
+         Qt::Horizontal
+        
+        
+         
+          40
+          20
+         
+        
+       
+      +
- 
+       
+        
+         cache
+        
+        
+         
+          :/icons/icons/关闭_close-one.svg:/icons/icons/关闭_close-one.svg
+        
+       
+      +
- 
+       
+        
+         convert
+        
+        
+         
+          :/icons/icons/校验_check-one.svg:/icons/icons/校验_check-one.svg
+        
+       
+      +     
+    
+
+  
+ 
+ 
+  
+ 
+ 
+
diff --git a/ui/MainWindow.py b/ui/MainWindow.py
index 9df6058..7e3321c 100644
--- a/ui/MainWindow.py
+++ b/ui/MainWindow.py
@@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
 class Ui_MainWindow(object):
     def setupUi(self, MainWindow):
         MainWindow.setObjectName("MainWindow")
-        MainWindow.resize(1280, 760)
+        MainWindow.resize(1280, 764)
         MainWindow.setMinimumSize(QtCore.QSize(800, 600))
         font = QtGui.QFont()
         font.setFamily("Times New Roman")
@@ -260,6 +260,9 @@ class Ui_MainWindow(object):
         icon25.addPixmap(QtGui.QPixmap(":/icon/icons/coco.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
         self.actionToCOCO.setIcon(icon25)
         self.actionToCOCO.setObjectName("actionToCOCO")
+        self.actionFromCOCO = QtWidgets.QAction(MainWindow)
+        self.actionFromCOCO.setIcon(icon25)
+        self.actionFromCOCO.setObjectName("actionFromCOCO")
         self.menuFile.addAction(self.actionOpen_dir)
         self.menuFile.addAction(self.actionSave_dir)
         self.menuFile.addSeparator()
@@ -282,6 +285,7 @@ class Ui_MainWindow(object):
         self.menuAbout.addAction(self.actionAbout)
         self.menuTools.addAction(self.actionToVOC)
         self.menuTools.addAction(self.actionToCOCO)
+        self.menuTools.addAction(self.actionFromCOCO)
         self.menuEdit.addAction(self.actionSegment_anything)
         self.menuEdit.addAction(self.actionPolygon)
         self.menuEdit.addAction(self.actionBackspace)
@@ -389,9 +393,9 @@ class Ui_MainWindow(object):
         self.actionTo_bottom.setToolTip(_translate("MainWindow", "Move polygon to bottom layer"))
         self.actionTo_bottom.setStatusTip(_translate("MainWindow", "Move polygon to bottom layer."))
         self.actionTo_bottom.setShortcut(_translate("MainWindow", "B"))
-        self.actionToVOC.setText(_translate("MainWindow", "ToVOC"))
+        self.actionToVOC.setText(_translate("MainWindow", "To VOC"))
         self.actionToVOC.setToolTip(_translate("MainWindow", "Convert ISAT to VOC"))
-        self.actionToVOC.setStatusTip(_translate("MainWindow", "Convert annotations to png image."))
+        self.actionToVOC.setStatusTip(_translate("MainWindow", "Convert ISAT jsons to VOC png image."))
         self.actionChinese.setText(_translate("MainWindow", "中文"))
         self.actionEnglish.setText(_translate("MainWindow", "English"))
         self.actionBackspace.setText(_translate("MainWindow", "Backspace"))
@@ -413,6 +417,10 @@ class Ui_MainWindow(object):
         self.actionVisible.setText(_translate("MainWindow", "Visible"))
         self.actionVisible.setStatusTip(_translate("MainWindow", "Visible"))
         self.actionVisible.setShortcut(_translate("MainWindow", "V"))
-        self.actionToCOCO.setText(_translate("MainWindow", "ToCOCO"))
+        self.actionToCOCO.setText(_translate("MainWindow", "To COCO"))
         self.actionToCOCO.setToolTip(_translate("MainWindow", "Convert ISAT to COCO"))
+        self.actionToCOCO.setStatusTip(_translate("MainWindow", "Convert ISAT jsons to COCO json."))
+        self.actionFromCOCO.setText(_translate("MainWindow", "From COCO"))
+        self.actionFromCOCO.setToolTip(_translate("MainWindow", "Convert COCO to ISAT"))
+        self.actionFromCOCO.setStatusTip(_translate("MainWindow", "Convert COCO json to ISAT jsons."))
 import icons_rc
diff --git a/ui/MainWindow.ui b/ui/MainWindow.ui
index aa18d31..e7c16e7 100644
--- a/ui/MainWindow.ui
+++ b/ui/MainWindow.ui
@@ -7,7 +7,7 @@
     0
     0
     1280
-    760
+    764
    
   
   
@@ -152,6 +152,7 @@
     
     
     
+    
    
    
  
diff --git a/widgets/COCO_to_ISAT_dialog.py b/widgets/COCO_to_ISAT_dialog.py
new file mode 100644
index 0000000..8a5afb8
--- /dev/null
+++ b/widgets/COCO_to_ISAT_dialog.py
@@ -0,0 +1,69 @@
+# -*- coding: utf-8 -*-
+# @Author  : LG
+
+from PyQt5 import QtWidgets, QtCore, QtGui
+from ui.COCO_to_ISAT_dialog import Ui_Dialog
+from tools.toCOCO import COCOConverter
+
+
+class COCOtoISATDialog(QtWidgets.QDialog, Ui_Dialog):
+    def __init__(self, parent, mainwindow):
+        super(COCOtoISATDialog, self).__init__(parent)
+        self.setupUi(self)
+        self.mainwindow = mainwindow
+        self.label_path = None
+        self.save_root = None
+        self.pause = False
+
+        self.setWindowModality(QtCore.Qt.WindowModality.WindowModal)
+
+        self.init_connect()
+
+    def reset_gui(self):
+        self.lineEdit_label_path.clear()
+        self.lineEdit_save_root.clear()
+
+    def _label_path(self):
+        path, suffix = QtWidgets.QFileDialog.getOpenFileName(self, caption='COCO json save file',
+                                                             filter="json (*.json)")
+        if path:
+            self.label_path = path
+            self.lineEdit_label_path.setText(path)
+        else:
+            self.lineEdit_label_path.clear()
+
+    def _save_root(self):
+
+        dir = QtWidgets.QFileDialog.getExistingDirectory(self, caption='ISAT jsons root')
+        if dir:
+
+            self.save_root = dir
+            self.lineEdit_save_root.setText(dir)
+        else:
+            self.lineEdit_save_root.clear()
+
+    def cache(self):
+        self.pause = True
+        self.close()
+
+    def apply(self):
+        self.pause = False
+        if self.label_path is None or self.save_root is None:
+            return
+
+        converter = COCOConverter()
+
+        self.pushButton_label_path.setEnabled(False)
+        self.pushButton_save_root.setEnabled(False)
+        self.label_info.setText('Convering...')
+        converter.convert_from_coco(self.label_path, self.save_root, keep_crowd=self.checkBox_keepcrowd.isChecked())
+        self.label_info.setText('Finish!!!')
+
+        self.pushButton_label_path.setEnabled(True)
+        self.pushButton_save_root.setEnabled(True)
+
+    def init_connect(self):
+        self.pushButton_label_path.clicked.connect(self._label_path)
+        self.pushButton_save_root.clicked.connect(self._save_root)
+        self.pushButton_apply.clicked.connect(self.apply)
+        self.pushButton_cache.clicked.connect(self.cache)
\ No newline at end of file
diff --git a/widgets/ISAT_to_COCO_dialog.py b/widgets/ISAT_to_COCO_dialog.py
new file mode 100644
index 0000000..67650a1
--- /dev/null
+++ b/widgets/ISAT_to_COCO_dialog.py
@@ -0,0 +1,69 @@
+# -*- coding: utf-8 -*-
+# @Author  : LG
+
+from PyQt5 import QtWidgets, QtCore, QtGui
+from ui.ISAT_to_COCO_dialog import Ui_Dialog
+from tools.toCOCO import COCOConverter
+
+
+class ISATtoCOCODialog(QtWidgets.QDialog, Ui_Dialog):
+    def __init__(self, parent, mainwindow):
+        super(ISATtoCOCODialog, self).__init__(parent)
+        self.setupUi(self)
+        self.mainwindow = mainwindow
+        self.label_root = None
+        self.save_path = None
+        self.pause = False
+
+        self.setWindowModality(QtCore.Qt.WindowModality.WindowModal)
+
+        self.init_connect()
+
+    def reset_gui(self):
+        self.lineEdit_label_root.clear()
+        self.lineEdit_save_path.clear()
+
+    def _label_root(self):
+        dir = QtWidgets.QFileDialog.getExistingDirectory(self, caption='ISAT jsons root')
+        if dir:
+            self.label_root = dir
+            self.lineEdit_label_root.setText(dir)
+        else:
+            self.lineEdit_label_root.clear()
+
+    def _save_path(self):
+        path, suffix = QtWidgets.QFileDialog.getSaveFileName(self, caption='COCO json save file', filter="json (*.json)")
+        if path:
+            if not path.endswith('.json'):
+                path += '.json'
+            self.save_path = path
+            self.lineEdit_save_path.setText(path)
+        else:
+            self.lineEdit_save_path.clear()
+
+    def cache(self):
+        self.pause = True
+        self.close()
+
+    def apply(self):
+        self.pause = False
+        if self.label_root is None or self.save_path is None:
+            return
+
+        converter = COCOConverter()
+
+        self.pushButton_label_root.setEnabled(False)
+        self.pushButton_save_path.setEnabled(False)
+        self.label_info.setText('Convering...')
+
+        converter.convert_to_coco(self.label_root, self.save_path)
+        self.label_info.setText('Finish!!!')
+
+        self.pushButton_label_root.setEnabled(True)
+        self.pushButton_save_path.setEnabled(True)
+
+    def init_connect(self):
+        self.pushButton_label_root.clicked.connect(self._label_root)
+        self.pushButton_save_path.clicked.connect(self._save_path)
+        self.pushButton_apply.clicked.connect(self.apply)
+        self.pushButton_cache.clicked.connect(self.cache)
\ No newline at end of file
diff --git a/widgets/ISAT_to_VOC_dialog.py b/widgets/ISAT_to_VOC_dialog.py
index 7c7a428..2062ff3 100644
--- a/widgets/ISAT_to_VOC_dialog.py
+++ b/widgets/ISAT_to_VOC_dialog.py
@@ -3,7 +3,7 @@
 
 from PyQt5 import QtWidgets, QtCore, QtGui
 from ui.ISAT_to_VOC_dialog import Ui_Dialog
-from tools.toVOC import ToVOC
+from tools.toVOC import VOCConverter
 import os
 
 
@@ -55,7 +55,7 @@ class ISATtoVOCDialog(QtWidgets.QDialog, Ui_Dialog):
                 for index, label in enumerate(self.mainwindow.cfg.get('label', [])):
                     f.write('{} {}\n'.format(label.get('name'), index))
 
-        converter = ToVOC(self.mainwindow.cfg, self.checkBox_is_instance.isChecked())
+        converter = VOCConverter(self.mainwindow.cfg, self.checkBox_is_instance.isChecked())
         jsons = [f for f in os.listdir(self.label_root) if f.endswith('.json')]
 
         self.pushButton_label_root.setEnabled(False)
diff --git a/widgets/converter.py b/widgets/converter.py
deleted file mode 100644
index 2f33183..0000000
--- a/widgets/converter.py
+++ /dev/null
@@ -1,86 +0,0 @@
-# -*- coding: utf-8 -*-
-# @Author  : LG
-
-from PyQt5 import QtWidgets, QtCore, QtGui
-from ui.ISAT_to_VOC_dialog import Ui_Dialog
-from tools.toVOC import ToVOC
-import os
-
-
-class TOVOCDialog(QtWidgets.QDialog, Ui_Dialog):
-    def __init__(self, parent, mainwindow):
-        super(TOVOCDialog, self).__init__(parent)
-        self.setupUi(self)
-        self.mainwindow = mainwindow
-        self.label_root = None
-        self.save_root = None
-        self.pause = False
-
-        self.setWindowModality(QtCore.Qt.WindowModality.WindowModal)
-
-        self.init_connect()
-
-    def reset_gui(self):
-        self.widget_process.setVisible(False)
-        self.lineEdit_label_root.clear()
-        self.lineEdit_save_root.clear()
-
-    def _label_root(self):
-        dir = QtWidgets.QFileDialog.getExistingDirectory(self)
-        if dir:
-            self.label_root = dir
-            self.lineEdit_label_root.setText(dir)
-        else:
-            self.lineEdit_label_root.clear()
-
-    def _save_root(self):
-        dir = QtWidgets.QFileDialog.getExistingDirectory(self)
-        if dir:
-            self.save_root = dir
-            self.lineEdit_save_root.setText(dir)
-        else:
-            self.lineEdit_save_root.clear()
-
-    def cache(self):
-        self.pause = True
-        self.close()
-
-    def apply(self):
-        self.pause = False
-        if self.label_root is None or self.save_root is None:
-            return
-        # 语义分割,保存类别文件
-        if not self.checkBox_is_instance.isChecked():
-            with open(os.path.join(self.save_root, 'classesition.txt'), 'w') as f:
-                for index, label in enumerate(self.mainwindow.cfg.get('label', [])):
-                    f.write('{} {}\n'.format(label.get('name'), index))
-
-        converter = ToVOC(self.mainwindow.cfg, self.checkBox_is_instance.isChecked())
-        jsons = [f for f in os.listdir(self.label_root) if f.endswith('.json')]
-
-        self.pushButton_label_root.setEnabled(False)
-        self.pushButton_save_root.setEnabled(False)
-        self.checkBox_is_instance.setEnabled(False)
-
-        self.widget_process.setVisible(True)
-        self.progressBar.setMaximum(len(jsons))
-        self.all_num.setText('{}'.format(len(jsons)))
-
-        for index, json in enumerate(jsons):
-            if self.pause:
-                break
-            label_path = os.path.join(self.label_root, json)
-            save_path = os.path.join(self.save_root, json[:-5]+'.png')
-            converter.convert(label_path, save_path)
-            self.progressBar.setValue(index+1)
-            self.current_num.setText('{}'.format(index+1))
-
-        self.pushButton_label_root.setEnabled(True)
-        self.pushButton_save_root.setEnabled(True)
-        self.checkBox_is_instance.setEnabled(True)
-
-    def init_connect(self):
-        self.pushButton_label_root.clicked.connect(self._label_root)
-        self.pushButton_save_root.clicked.connect(self._save_root)
-        self.pushButton_apply.clicked.connect(self.apply)
-        self.pushButton_cache.clicked.connect(self.cache)
\ No newline at end of file
diff --git a/widgets/mainwindow.py b/widgets/mainwindow.py
index 280f888..3382647 100644
--- a/widgets/mainwindow.py
+++ b/widgets/mainwindow.py
@@ -13,6 +13,8 @@ from widgets.right_button_menu import RightButtonMenu
 from widgets.shortcut_dialog import ShortcutDialog
 from widgets.about_dialog import AboutDialog
 from widgets.ISAT_to_VOC_dialog import ISATtoVOCDialog
+from widgets.ISAT_to_COCO_dialog import ISATtoCOCODialog
+from widgets.COCO_to_ISAT_dialog import COCOtoISATDialog
 from widgets.canvas import AnnotationScene, AnnotationView
 from configs import STATUSMode, MAPMode, load_config, save_config, CONFIG_FILE, DEFAULT_CONFIG_FILE
 from annotation import Object, Annotation
@@ -84,8 +86,6 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
             self.labelGPUResource.setText('segment anything unused.')
 
     def init_ui(self):
-        # 待完成
-        self.actionToCOCO.setEnabled(False)
         #
         self.setting_dialog = SettingDialog(parent=self, mainwindow=self)
 
@@ -103,6 +103,8 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
         self.category_edit_widget = CategoryEditDialog(self, self, self.scene)
 
         self.ISAT_to_VOC_dialog = ISATtoVOCDialog(self, mainwindow=self)
+        self.ISAT_to_COCO_dialog = ISATtoCOCODialog(self, mainwindow=self)
+        self.COCO_to_ISAT_dialog = COCOtoISATDialog(self, mainwindow=self)
 
         self.view = AnnotationView(parent=self)
         self.view.setScene(self.scene)
@@ -152,6 +154,8 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
         self.about_dialog.retranslateUi(self.about_dialog)
         self.shortcut_dialog.retranslateUi(self.shortcut_dialog)
         self.ISAT_to_VOC_dialog.retranslateUi(self.ISAT_to_VOC_dialog)
+        self.ISAT_to_COCO_dialog.retranslateUi(self.ISAT_to_COCO_dialog)
+        self.COCO_to_ISAT_dialog.retranslateUi(self.COCO_to_ISAT_dialog)
 
     def translate_to_chinese(self):
         self.translate('zh')
@@ -467,6 +471,14 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
         self.ISAT_to_VOC_dialog.reset_gui()
         self.ISAT_to_VOC_dialog.show()
 
+    def ISAT_to_COCO(self):
+        self.ISAT_to_COCO_dialog.reset_gui()
+        self.ISAT_to_COCO_dialog.show()
+
+    def COCO_to_ISAT(self):
+        self.COCO_to_ISAT_dialog.reset_gui()
+        self.COCO_to_ISAT_dialog.show()
+
     def help(self):
         self.shortcut_dialog.show()
 
@@ -509,6 +521,8 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
         self.actionVisible.triggered.connect(functools.partial(self.set_labels_visible, None))
 
         self.actionToVOC.triggered.connect(self.ISAT_to_VOC)
+        self.actionToCOCO.triggered.connect(self.ISAT_to_COCO)
+        self.actionFromCOCO.triggered.connect(self.COCO_to_ISAT)
 
         self.actionShortcut.triggered.connect(self.help)
         self.actionAbout.triggered.connect(self.about)