Commit 96bbf790 authored by 叶璨铭's avatar 叶璨铭
Browse files

feat: 引入yolo标注结果,增加手动标注工具

parent faa868fd
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
[submodule "public/data/0.pdfs/a-complete-collection-of-bronzes-unearthed-in-china"]
	path = public/data/0.pdfs/a-complete-collection-of-bronzes-unearthed-in-china
	url = https://mirrors.sustech.edu.cn/git/12011404/a-complete-collection-of-bronzes-unearthed-in-china.git
[submodule "users/ycm/图中图提取/labelGo-Yolov5AutoLabelImg"]
	path = users/ycm/图中图提取/labelGo-Yolov5AutoLabelImg
	url = https://github.com/cnyvfang/labelGo-Yolov5AutoLabelImg.git
+48 −0
Original line number Diff line number Diff line
import json
import math
from typing import Tuple
import cv2
import numpy as np
from matplotlib import pyplot as plt
@@ -15,6 +17,9 @@ def cv_imread(filePath):
    cv_img = cv2.cvtColor(cv_img, cv2.COLOR_RGB2BGR)
    return cv_img

def cv_imwrite(filename, src, format=".png"):
    cv2.imencode(format ,src)[1].tofile(filename)


def cv_imshow(img):
    # plt.style.use("default")
@@ -32,6 +37,49 @@ def cv_imshow_single_channel(img):
    tmp = Image.fromarray(img).convert('L')
    return tmp

def cv_rect2slice(rect:Tuple[int, int, int, int]):
    x, y, w, h = rect
    return (y, y+h, x, x+w)
def slice2xyxy(slice:Tuple[int, int, int, int]):
    # python 的 numpy array,横着升高的是列,竖着向下的是行。而CV中是https://roboflow.com/formats/yolov5-pytorch-txt
    y1, y2, x1, x2 = slice
    return (x1, y1, x2, y2)

def xyxy2yolo_xywh(image_size:Tuple[int, int], box:Tuple[int, int, int, int]):
    # size是图片的大小 (width, height)
    # 比如, 
    # box = 'xmin': 1580.0, 'ymin': 758.667, 'xmax': 1638.6667, 'ymax': 818.6667
    # converts to yolo format
    # 拆解
    global_width, global_height = image_size
    x_min, y_min, x_max, y_max = box
    # 计算
    center_x = (x_min + x_max)/2.0  
    center_y = (y_min + y_max)/2.0  
    box_width = x_max - x_min  # xmax-xmin
    box_height = y_max - y_min  # ymax-ymin
    # 中心化
    center_x /= global_width
    box_width /= global_width
    center_y /= global_height
    box_height /= global_height
    return (center_x , center_y, box_width, box_height)

def yolo_xywh2cv_rect(image_size:Tuple[int, int], yolo_box:Tuple[float, float, float, float]):
    # 拆解
    global_width, global_height = image_size
    center_x , center_y, box_width, box_height = yolo_box
    # 计算
    center_x, box_width = center_x*global_width, box_width*global_width
    center_y, box_height = center_y*global_height, box_height*global_height
    x = center_x-box_width/2
    y = center_y-box_height/2
    process = lambda x, limit: min(max(int(round(x)), 0), limit)
    return (process(x, global_width), process(y, global_height), 
            process(box_width, global_width), process(box_height, global_height))
    


from deep_translator import (GoogleTranslator,
                             ChatGptTranslator,
                             MicrosoftTranslator,

labelGo-Yolov5AutoLabelImg @ b873a7d5

Original line number Diff line number Diff line
Subproject commit b873a7d5482d152ded714120fcc7e34e7a038fb7
+56 −13
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@
# 5. 按q退出程序。
# 可以调节的参数介绍:见下面 var_dict 的定义

from typing import Tuple
from typing import List, Tuple
from commons import *
from pathlib import Path
import json
@@ -30,6 +30,11 @@ img_path = lambda number: input_folder / f'第{number}页-{number}.PNG'
# img = cv_imread(img_path)   
# cv_imshow(img)

classes_txt_path = output_folder/'classes.txt'
if not classes_txt_path.exists():
    with open(classes_txt_path, 'w') as f:
        f.write("image\n")

# 2. 处理函数
parameter_path = this_directory/'标注器保存的参数.json'
max_area_possible = 2900*4000
@@ -103,18 +108,56 @@ window_size = (2900 // 5, (4000+800) // 5)



current_img, valid_rects = None, None
def save_rois(image, rects):
    path = f"{var_dict['number']['value']}-*.png"

def make_yolo(txt_path:str, array_shape:Tuple[int, int, int], cv_rects:List[Tuple[int, int, int, int]], label_type=0):
    # 保存YOLO风格标注框
    # 格式参考说明:https://roboflow.com/formats https://roboflow.com/formats/yolov8-pytorch-txt
    # yolo v8: class_id center_x center_y width height
    res = list(map(lambda rect: 
        " ".join([str(label_type)]+
                 [str(f) for f in 
                  xyxy2yolo_xywh((array_shape[1], array_shape[0]), slice2xyxy(cv_rect2slice(rect)))]), 
                   cv_rects))
    with open(txt_path, 'w') as f:
        f.write("\n".join(res)+"\n")

yolo_txt_path = lambda number: output_folder / f'{number}页-{number}.txt'

inner_png_path = lambda number, subimage_num: output_folder / f"{number}页-{number}-内图{subimage_num}.png"

def is_annotated(number:int):
    return yolo_txt_path(number).exists()
def remove_annotated(number:int):
    # 删除旧的标注结果
    # path = f"{number}-*.png"
    path = inner_png_path(number, "*").relative_to(output_folder).as_posix()
    for f in output_folder.glob(path):
        f.unlink()
    if len(rects)==0:
        with open(output_folder/f"{var_dict['number']['value']}-stub.png", 'w') as f:
            f.write("该页没有文物图片。\n")
    yolo_txt_path(number).unlink()
    
def make_sub_image_from_yolo(txt_path:str, number:int, image:np.ndarray):
    pass
    
    
current_img, valid_rects = None, None
def save_rois(image:np.ndarray, rects:List[Tuple[int, int, int, int]]):
    current_num = int(var_dict['number']['value'])
    yolo_path = yolo_txt_path(current_num)
    if is_annotated(current_num):
        print(f'警告:{current_num}号图片有已知标注成果,正在使用新的标注结果覆盖。')
        remove_annotated(current_num)
    make_yolo(yolo_path.as_posix(), image.shape, rects)
    
        
    # 保存小图片    
    for i, rect in enumerate(rects):
        roi = image[rect[1]:rect[1]+rect[3], rect[0]:rect[0]+rect[2]]
        cv2.imwrite((output_folder/f"{var_dict['number']['value']}-{i}.png").as_posix(), roi)
    print(f"enter: 确认标注,已保存标注结果到{output_folder/path}")
        y1, y2, x1, x2 = cv_rect2slice(rect)
        roi = image[y1:y2, x1:x2]
        # cv2.imwrite((output_folder/f"{current_num}-{i}.png").as_posix(), roi)
        cv_imwrite(inner_png_path(current_num, i).as_posix(), roi)
    
        
    print(f"enter: 确认标注,已保存标注结果到{yolo_path}")

import time
last_prompt_time = time.time()
@@ -171,6 +214,7 @@ while (True):
        break
    key = cv2.waitKey(10) % 255
    if key == ord('s'):
        print(f"当前参数已保存到{parameter_path}")
        dump_json_file(var_dict, parameter_path)
    #https://blog.csdn.net/listener51/article/details/89353247
    # elif key==get_keycode('KEYCODE_ENTER'):
@@ -184,10 +228,9 @@ while (True):
        print("down: 下一张图片。")
        cv2.setTrackbarPos('number', window_name, min(pages, var_dict['number']['value']+1))
    elif key==ord('j') or key==ord('k'):
        new_page = var_dict['number']['value']+1
        new_page = -1
        for new_page in range(var_dict['number']['value']+1, pages+1):
            path = f"{new_page}-*.png"
            if len(list(output_folder.glob(path)))==0:
            if not is_annotated(new_page):
                break
        cv2.setTrackbarPos('number', window_name, new_page)
    elif key == ord('q'):
+34 −0
Original line number Diff line number Diff line
%% Cell type:code id: tags:

``` python
from commons import *
```

%% Cell type:code id: tags:

``` python
image_size = 200, 100
cv_rect = (20, 30, 30, 20)
slice = cv_rect2slice(cv_rect)
slice
```

%% Cell type:code id: tags:

``` python
xyxy = slice2xyxy(slice)
xyxy
```

%% Cell type:code id: tags:

``` python
yolo = xyxy2yolo_xywh(image_size, xyxy)
yolo
```

%% Cell type:code id: tags:

``` python
cv_rect = yolo_xywh2cv_rect(image_size, cv_rect)
```
Loading