Selaa lähdekoodia

新增标注工具

jiyuhang 3 kuukautta sitten
vanhempi
commit
a853cd7331

+ 2 - 0
.env

@@ -0,0 +1,2 @@
+PATCH_WIDTH=256
+PATCH_HEIGHT=256

+ 2 - 2
calculator.py

@@ -376,7 +376,7 @@ if __name__ == '__main__':
     # path3 = r'D:\code\water_turbidity_det\data\day_202511211129\3_video_202511211128.dav'
     # path4 = r'D:\code\water_turbidity_det\data\day_202511211129\4_video_202511211128.dav'
     #
-    # path1 = r'D:\code\water_turbidity_det\data\night\1_video_2025_1120.dav'
+    # path1 = r'D:\code\water_turbidity_det\data\night\1_video_20251120.dav'
     # path2 = r'D:\code\water_turbidity_det\data\night\2_video_20251120_1801.dav'
     # path3 = r'D:\code\water_turbidity_det\data\night\3_video_20251120_1759.dav'
     # path4 = r'D:\code\water_turbidity_det\data\night\4_video_20251120_1800.dav'
@@ -400,7 +400,7 @@ if __name__ == '__main__':
     # for t in threads:
     #     if t.is_alive():
     #         t.join()
-    main(video_dir=r'D:\code\water_turbidity_det\data\records_202512031553\video4_20251129053218_20251129060528.mp4',
+    main(video_dir=r'/video/records_202512031553\video4_20251129053218_20251129060528.mp4',
          mask_dir=r'D:\code\water_turbidity_det\draw_mask\mask\4_device_capture.png',
          id=4)
     cv2.destroyAllWindows()

+ 0 - 0
check/检查标注结果是否正确.md


+ 7 - 0
data/1_video_202511211128/label.txt

@@ -0,0 +1,7 @@
+0,1280,256,256,-1
+256,1280,256,256,-1
+2304,0,256,256,-1
+2048,0,256,256,-1
+1792,0,256,256,-1
+2304,256,256,256,-1
+2560,256,256,256,-1

+ 19 - 0
data/2_video_202511211128/label.txt

@@ -0,0 +1,19 @@
+1280,1280,256,256,1
+1024,1280,256,256,1
+1024,1024,256,256,1
+1280,1024,256,256,1
+1536,1280,256,256,1
+1536,768,256,256,1
+1280,768,256,256,1
+1536,1024,256,256,1
+1792,256,256,256,-1
+1536,256,256,256,-1
+0,0,256,256,-1
+256,0,256,256,-1
+1024,512,256,256,-1
+768,512,256,256,-1
+512,512,256,256,-1
+256,512,256,256,-1
+256,768,256,256,-1
+512,768,256,256,-1
+0,768,256,256,-1

+ 8 - 0
data/3_video_202511211127/label.txt

@@ -0,0 +1,8 @@
+768,512,256,256,1
+512,512,256,256,1
+256,256,256,256,1
+512,256,256,256,1
+768,0,256,256,-1
+1024,0,256,256,-1
+0,0,256,256,-1
+256,0,256,256,-1

+ 19 - 0
data/4_video_202511211127/label.txt

@@ -0,0 +1,19 @@
+256,1280,256,256,-1
+0,1280,256,256,-1
+768,1280,256,256,1
+768,1024,256,256,1
+768,768,256,256,1
+768,512,256,256,1
+768,256,256,256,1
+768,0,256,256,1
+512,0,256,256,1
+512,256,256,256,1
+512,512,256,256,1
+512,768,256,256,1
+512,1024,256,256,1
+512,1280,256,256,1
+256,512,256,256,1
+256,768,256,256,1
+256,1024,256,256,1
+256,256,256,256,1
+256,0,256,256,-1

+ 6 - 0
data/video1_20251129120104_20251129123102/label.txt

@@ -0,0 +1,6 @@
+0,1280,256,256,-1
+256,1280,256,256,-1
+2304,0,256,256,-1
+1792,0,256,256,-1
+2048,0,256,256,-1
+2304,256,256,256,-1

+ 23 - 0
data/video4_20251129120320_20251129123514/label.txt

@@ -0,0 +1,23 @@
+0,1280,256,256,-1
+256,1280,256,256,-1
+256,0,256,256,-1
+0,768,256,256,-1
+0,1024,256,256,-1
+512,0,256,256,1
+768,0,256,256,1
+768,256,256,256,1
+512,256,256,256,1
+256,256,256,256,1
+256,512,256,256,1
+256,768,256,256,1
+512,1280,256,256,1
+512,1024,256,256,1
+256,1024,256,256,1
+512,768,256,256,1
+768,768,256,256,1
+768,512,256,256,1
+512,512,256,256,1
+768,1280,256,256,1
+768,1024,256,256,1
+1024,256,256,256,1
+1024,512,256,256,1

+ 0 - 0
data/标注好的视频帧.md


+ 62 - 0
labelme/check_label.py

@@ -0,0 +1,62 @@
+"""检查标注是否正确,读取标签,信息"""
+import cv2
+import os
+import sys
+sys.path.append(os.path.dirname(os.path.abspath(__file__)))
+from utils import draw_grid
+from dotenv import load_dotenv
+load_dotenv() # 加载环境变量
+
+patch_w = int(os.getenv('PATCH_WIDTH', 256))
+patch_h = int(os.getenv('PATCH_HEIGHT', 256))
+scale = 2
+clicked_points = []  # u v w h cls
+
+def main():
+    """检查标注结果是否正确"""
+    # 标注文件路径
+    global patch_w
+    global patch_h
+    global scale
+    global clicked_points
+    # TODO:修改为要检查的图片路径
+    imgs_path = r'D:\code\water_turbidity_det\data\video4_20251129120320_20251129123514'
+    output_root = r'D:\code\water_turbidity_det\check'
+    label_path = os.path.join(imgs_path, 'label.txt')
+    if os.path.exists(label_path):
+        with open(label_path, 'r') as fr:
+            lines = fr.readlines()
+        lines = [line.strip() for line in lines]
+        for line in lines:
+            point = line.split(',')
+            clicked_points.append([int(point[0])//scale, int(point[1])//scale, int(point[2])//scale, int(point[3])//scale, int(point[4])])
+        del lines
+    # 检查结果输出路径
+    output_path = os.path.join(output_root, os.path.basename(imgs_path)+'_check')
+    if not os.path.exists(output_path):
+        os.makedirs(output_path)
+    # 获取所有照片
+    all_imgs = os.listdir(imgs_path)
+    all_imgs = [img for img in all_imgs if img.split('.')[-1] == 'jpg' or img.split('.')[-1] == 'png']
+
+    for img in all_imgs:
+        img_path = os.path.join(imgs_path, img)
+        img = cv2.imread(img_path)
+        img = cv2.resize(img, (img.shape[1] // scale, img.shape[0] // scale))
+        # 绘制网格线
+        img = draw_grid(img, patch_w // scale, patch_h // scale)
+        # 绘制标记点
+        for point in clicked_points:
+            # 计算中心点
+            center_x = point[0]+point[2]//scale
+            center_y = point[1]+point[3]//scale
+            cv2.circle(img, (center_x, center_y), 5, (0, 0, 255), -1)
+            # 显示标签文本
+            cv2.putText(img, str(point[4]), (center_x + 10, center_y + 10),
+                        cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
+        cv2.imwrite(os.path.join(output_path, os.path.basename(img_path)),
+                    img)
+        print(f"检查结果保存在: {os.path.join(output_path, os.path.basename(img_path))}")
+
+if __name__ == '__main__':
+    main()

+ 81 - 0
labelme/crop_patch.py

@@ -0,0 +1,81 @@
+# 根据标注文件,生成patch,每个类别放在一个文件夹下
+import os
+import sys
+sys.path.append(os.path.dirname(os.path.abspath(__file__)))
+
+import numpy as np
+import cv2
+from dotenv import load_dotenv
+load_dotenv()
+
+# 从图像中截取patch_w*patch_h大小的图像,并打上标签
+patch_w = int(os.getenv('PATCH_WIDTH', 256))
+patch_h = int(os.getenv('PATCH_HEIGHT', 256))
+
+def main():
+    # TODO:需要修改为标注好的图片路径
+    input_path = r'D:\code\water_turbidity_det\data\video4_20251129120320_20251129123514'
+    # TODO: 需要修改为保存patch的根目录
+    output_path_root = r'D:\code\water_turbidity_det\label_data\train'
+
+    # 读取标注文件
+    label_path = os.path.join(input_path, 'label.txt')
+    if not os.path.exists(label_path):  # 强制要求必须标注点什么
+        raise FileNotFoundError(f"{label_path} 不存在")
+    with open(label_path, 'r') as fr:
+        lines = fr.readlines()
+        lines = [line.strip() for line in lines]
+    # 恢复标注的格网
+    grids_info = [] # clicked_points
+    for line in lines:
+        point = line.split(',')
+        grids_info.append([int(point[0]), int(point[1]), int(point[2]), int(point[3]), int(point[4])])
+    # 我们先创建一些类别文件夹
+    # 0类
+    if not os.path.exists(os.path.join(output_path_root, str(0))):
+        os.makedirs(os.path.join(output_path_root, str(0)))
+    # 其余类
+    for grid in grids_info:
+        if grid[4] <= 0:
+            continue
+        if not os.path.exists(os.path.join(output_path_root, str(grid[4]))):
+            os.makedirs(os.path.join(output_path_root, str(grid[4])))
+    # 获取图像
+    all_imgs = [os.path.join(input_path, i) for i in os.listdir(input_path) if i.split('.')[-1] == 'jpg' or i.split('.')[-1] == 'png']
+    for img_path in all_imgs:
+        img_base_name = os.path.basename(img_path).split('.')[0]
+        img = cv2.imread(img_path)
+        # 获取图像高宽
+        img_h, img_w, _ = img.shape
+        # 先将不参与训练的patch重置为0
+        for g in grids_info:
+            if g[4] < 0:  # 标签小于零的不参与训练
+                img[g[1]:min(g[1]+g[3], img_h), g[0]:min(g[0]+g[2], img_w), :] = 0
+        # 再将大于0的patch保存到对应的类别文件夹下
+        for g in grids_info:
+            if g[4] > 0:  # 标签大于零的放到相应的文件夹下
+                patch_name = f'{img_base_name}_{g[0]}_{g[1]}_{g[4]}.jpg'  # 图块保存名称:图片名_左上角x_左上角y_类别.jpg
+                patch = img[g[1]:min(g[1]+g[3], img_h), g[0]:min(g[0]+g[2], img_w), :]
+                # 保存图块
+                cv2.imwrite(os.path.join(output_path_root,str(g[4]), patch_name), patch)
+                # 置零已经保存的patch区域
+                img[g[1]:min(g[1]+g[3], img_h), g[0]:min(g[0]+g[2], img_w), :] = 0
+        # 最后将剩余的patch保存到0类文件夹下
+        for i in range(img_h // patch_h + 1):
+            for j in range(img_w // patch_w + 1):
+                patch = img[i*patch_h:min(i*patch_h+patch_h, img_h), j*patch_w:min(j*patch_w+patch_w, img_w), :]
+                patch_name = f'{img_base_name}_{j*patch_w}_{i*patch_h}_0.jpg'
+                # 长宽比过滤
+                if patch.shape[0] / patch.shape[1] > 1.314 or patch.shape[0] / patch.shape[1] < 0.75:
+                    print(f"长宽比过滤: {patch_name}")
+                    continue
+                # 纯黑图像过滤
+                if np.mean(patch) < 10.10:
+                    print(f"纯黑图像过滤: {patch_name}")
+                    continue
+                cv2.imwrite(os.path.join(output_path_root, '0', patch_name), patch)
+                print(f"保存图块: {patch_name}到{os.path.join(output_path_root, '0', patch_name)}")
+
+
+if __name__ == '__main__':
+    main()

+ 165 - 0
labelme/fixed_label.py

@@ -0,0 +1,165 @@
+# 要求保证视频不能移动,且全过程没有任何遮挡物
+import os
+import sys
+sys.path.append(os.path.dirname(os.path.abspath(__file__)))
+from utils import draw_grid
+
+import cv2
+import numpy as np
+import tkinter as tk
+from tkinter import simpledialog
+from dotenv import load_dotenv
+load_dotenv()  # 加载环境变量
+
+# 所要切分的图块宽高
+patch_w = int(os.getenv('PATCH_WIDTH', 256))
+patch_h = int(os.getenv('PATCH_HEIGHT', 256))
+scale = 2
+# 存储标记点
+clicked_points = []
+
+def get_text_input(prompt):
+    """创建弹窗获取文本输入"""
+    root = tk.Tk()
+    root.withdraw()  # 隐藏主窗口
+    root.attributes('-topmost', True)  # 确保弹窗置顶
+    result = simpledialog.askstring(' ', prompt)
+    root.destroy()
+    if result is None:
+        result = ""
+    if not result.strip().isdigit():
+        result = -1
+    return int(result)
+
+def mouse_callback(event, x, y, flags, param):
+    """
+    鼠标回调函数
+    """
+    global clicked_points
+    global patch_w
+    global patch_h
+    global scale
+
+    if event == cv2.EVENT_LBUTTONDOWN:  # 左键点击
+        # 在点击位置绘制红色圆点
+        scale_patch_w = patch_w // scale
+        scale_patch_h = patch_h // scale
+        # 格子角点
+        circle_x_corner = (x // scale_patch_w)*scale_patch_w
+        circle_y_corner = (y // scale_patch_h)*scale_patch_h
+        # 格子中心点
+        circle_x_center = circle_x_corner + scale_patch_w//2
+        circle_y_center = circle_y_corner + scale_patch_h//2
+        cv2.circle(param, (circle_x_center, circle_y_center), 5, (0, 0, 255), -1)
+        cv2.circle(param, (circle_x_corner, circle_y_corner), 5, (255, 0, 0), -1)
+
+        # 更新显示
+        cv2.imshow('img', param)
+
+        cls = get_text_input('请输入类别:0.背景 1.浑浊 -1.不参与')
+        # 显示标签文本
+        cv2.putText(param, str(cls), (circle_x_center + 10, circle_y_center + 10),
+                    cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
+        # 更新显示
+        cv2.imshow('img', param)
+        valid_cls = [0, 1, -1]
+        if cls in valid_cls:
+            print(f"点击网格角点: ({circle_x_corner}, {circle_y_corner}) 中心点: ({circle_x_center}, {circle_y_center}) 类别:{cls}")
+            # 记录标注数据,角点 u v w h cls
+            clicked_points.append([circle_x_corner, circle_y_corner, scale_patch_w, scale_patch_h, cls])
+        else:
+            print("请输入正确的类别!")
+    elif event == cv2.EVENT_RBUTTONDOWN:  # 右键点击
+        removed_point = clicked_points.pop()
+        print(f"撤销标注点: ({removed_point[0]}, {removed_point[1]}) 类别: {removed_point[4]}")
+        # 将撤销点标记为黑色
+        x = removed_point[0]
+        y = removed_point[1]
+        # 在点击位置绘制黑色圆点
+        scale_patch_w = patch_w // scale
+        scale_patch_h = patch_h // scale
+        # 格子角点
+        circle_x_corner = (x // scale_patch_w)*scale_patch_w
+        circle_y_corner = (y // scale_patch_h)*scale_patch_h
+        # 格子中心点
+        circle_x_center = circle_x_corner + scale_patch_w//2
+        circle_y_center = circle_y_corner + scale_patch_h//2
+        cv2.circle(param, (circle_x_center, circle_y_center), 5, (128, 128, 128), -1)
+        cv2.circle(param, (circle_x_corner, circle_y_corner), 5, (128, 128, 128), -1)
+        # 更新显示
+        cv2.imshow('img', param)
+
+
+def remove_duplicates(arr:list):
+    """列表去重"""
+    unique_list = []
+    [unique_list.append(item) for item in arr if item not in unique_list]
+    return unique_list
+
+def main():
+    """
+    固定摄像头标注,只需要标注一张图像,后续图像保持一致
+    1.标注过程,先将图像划分为图框,用cv2划线工具在图像上划网格线
+    2.用鼠标进行交互,点击图块输入标签,按下空格键完成交互过程,保存标签
+    3.标签格式:u,v,w,h,label u,v为块左上角坐标,w,h为块的宽和高,label为块的标签
+    """
+    global clicked_points
+    global patch_w
+    global patch_h
+    global scale
+    # TODO: 需要更改为准备标注的图像路径,使用当前目录下的000000.jpg,结果保存在当前目录下label.txt
+    img_path = r'D:\code\water_turbidity_det\data\video1_20251129120104_20251129123102\000000.jpg'
+    img = cv2.imread(img_path)
+    # resize 图像太大了显示不全
+    img = cv2.resize(img, (img.shape[1] // scale, img.shape[0] // scale))
+    # 绘制网格线
+    draw_grid(img, patch_w // scale, patch_h // scale)
+    # 交互标注
+    print("操作说明:")
+    print("- 点击鼠标左键在图像上添加红色标记点: 0.其他 1.浑浊 -1.忽略,不参与训练和测试")
+    print("- 按 'c' 键清除所有标记点")
+    print("- 按 ESC 键退出程序")
+    cv2.namedWindow('img')
+    cv2.setMouseCallback('img', mouse_callback, img)
+    # 交互标注
+    while True:
+        cv2.imshow('img', img)
+        key = cv2.waitKey(1) & 0xFF
+
+        # 按 'c' 键清除所有标记点
+        if key == ord('c'):
+            img = cv2.imread(img_path)
+            img = cv2.resize(img, (img.shape[1] // scale, img.shape[0] // scale))
+            draw_grid(img, patch_w // scale, patch_h // scale)
+            clicked_points.clear()
+            cv2.setMouseCallback('img', mouse_callback, img)
+
+        # 按 ESC 键退出
+        elif key == 27:  # ESC键
+            break
+    cv2.destroyAllWindows()
+    # 输出所有点击位置
+    # 列表去重
+    clicked_points = remove_duplicates(clicked_points)
+
+    print(f"总共标记了 {len(clicked_points)} 个点:")
+    for i, point in enumerate(clicked_points):
+        print(f"  点 {i + 1}: ({point[0]}, {point[1]}, {point[2]}, {point[3]}, {point[4]})")
+    # 恢复尺寸
+    clicked_points = [[p[0]*scale, p[1]*scale, p[2]*scale, p[3]*scale, p[4]] for p in clicked_points]
+    # 写入txt
+    if clicked_points:
+        with open(os.path.join(os.path.dirname(img_path), 'label.txt'), 'w') as fw:
+            for point in clicked_points:
+                fw.write(f"{point[0]},{point[1]},{point[2]},{point[3]},{point[4]}\n")
+        # 保存点
+        print(f"保存标记点 {len(clicked_points)} 个:")
+        for i, point in enumerate(clicked_points):
+            print(f"  点 {i + 1}: ({point[0]}, {point[1]}, {point[2]}, {point[3]}, {point[4]})")
+    else :
+        print("没有标记点!不保存任何文件!")
+
+
+
+if __name__ == '__main__':
+    main()

+ 13 - 0
labelme/utils.py

@@ -0,0 +1,13 @@
+import numpy as np
+import cv2
+
+def draw_grid(img: np.ndarray, grid_w: int, grid_h:int):
+    """划格网"""
+    img_h, img_w, _ = img.shape
+    # 绘制横向网格线
+    for i in range((img_h // grid_h)+1):
+        cv2.line(img, (0, i*grid_h), (img_w, i*grid_h), (0, 255, 0), 2)
+    # 绘制纵向网格线
+    for i in range((img_w // grid_w)+1):
+        cv2.line(img, (i*grid_w, 0), (i*grid_w, img_h), (0, 255, 0), 2)
+    return img

+ 34 - 0
labelme/video_depart.py

@@ -0,0 +1,34 @@
+# 将视频图像分离为单帧序列
+import cv2
+import os
+
+def main():
+    # 视频路径
+    # TODO: 修改视频路径为自己的视频路径
+    path = r'/video/day_202511211129\4_video_202511211127.dav'
+    output_rootpath = r'D:\code\water_turbidity_det\data'  # 输出路径的根目录
+
+    # 我们将图像输出到根目录下的子目录中,子目录和视频名称相同
+    # 创建路径
+    img_base = os.path.basename(path).split('.')[0]
+    imgs_output_path = os.path.join(output_rootpath, img_base)  # 视频名称不要有.符号混淆后缀名
+    if not os.path.exists(imgs_output_path):
+        os.mkdir(imgs_output_path)
+
+    # 打开视频文件
+    cap = cv2.VideoCapture(path)
+    # 检查视频是否成功打开
+    if not cap.isOpened():
+        raise Exception('错误:无法打开视频文件。')
+    frame_count = 0
+    while True:
+        ret, frame = cap.read()
+        if not ret:
+            break
+        img_save_path = os.path.join(imgs_output_path,f"{frame_count:06d}.jpg")
+        cv2.imwrite(img_save_path, frame)
+        frame_count += 1
+        print(f"已处理{frame_count}帧, 保存至{img_save_path}")
+if __name__ == '__main__':
+    main()
+

+ 31 - 4
play.py

@@ -1,6 +1,7 @@
 import cv2
 import numpy as np
 from calculator import region_ndti, colorful_ndti_matrix
+import threading
 
 
 def main(video_path, video_mask_path, video_id):
@@ -12,7 +13,7 @@ def main(video_path, video_mask_path, video_id):
         print("错误:无法打开视频文件。")
         print("可能的原因:文件路径错误,或系统缺少必要的解码器。")
         exit()
-    scale = 4
+    scale = 2
     mask = cv2.imread(video_mask_path, cv2.IMREAD_GRAYSCALE)
     if mask is None:
         raise RuntimeError('mask open failed')
@@ -54,6 +55,7 @@ def main(video_path, video_mask_path, video_id):
         text = f'pixs:{int(np.sum(roi_ndti_fla))} mean:{roi_ndti_fla.mean():.3f} std:{roi_ndti_fla.std():.3f} {'night' if is_night else 'day'}'
         cv2.putText(frame, text, (10, 25), cv2.FONT_HERSHEY_DUPLEX, 0.6, (0, 255, 0), 2, cv2.LINE_AA)
         cv2.imshow(f'original_{video_id}', frame)
+        cv2.imshow(f'ndti_color_{video_id}', color_ndti)
         cv2.waitKey(30)
 
         # 退出逻辑
@@ -62,7 +64,32 @@ def main(video_path, video_mask_path, video_id):
             break
 
 if __name__ == '__main__':
-    main(video_path=r'D:\code\water_turbidity_det\data\day_202511211129\1_video_202511211128.dav',
-         video_mask_path=r'D:\code\water_turbidity_det\draw_mask\mask\1_device_capture.png',
-         video_id=1)
+    # main(video_path=r'D:\code\water_turbidity_det\data\night\4_video_20251120_1800.dav',
+    #      video_mask_path=r'D:\code\water_turbidity_det\draw_mask\mask\4_device_capture.png',
+    #      video_id=1)
+
+    t1 = threading.Thread(target=main,
+                     args=(r'D:\code\water_turbidity_det\data\records_202512031553\video4_20251129120320_20251129123514.mp4',
+                           r'D:\code\water_turbidity_det\draw_mask\mask\4_device_capture.png',
+                           4))
+
+    # t2 = threading.Thread(target=main,
+    #                  args=(r'D:\code\water_turbidity_det\data\day_202511211129\4_video_202511211127.dav',
+    #                        r'D:\code\water_turbidity_det\draw_mask\mask\4_device_capture.png',
+    #                        4))
+
+    # t1 = threading.Thread(target=main,
+    #                  args=(r'D:\code\water_turbidity_det\data\records_202512031553\video1_20251129055729_20251129063102.mp4',
+    #                        r'D:\code\water_turbidity_det\draw_mask\mask\1_device_capture.png',
+    #                        1))
+    #
+    # t2 = threading.Thread(target=main,
+    #                  args=(r'D:\code\water_turbidity_det\data\records_202512031553\video4_20251129053218_20251129060528.mp4',
+    #                        r'D:\code\water_turbidity_det\draw_mask\mask\4_device_capture.png',
+    #                        4))
+    t1.start()
+    # t2.start()
+
+    t1.join()
+    # t2.join()
     cv2.destroyAllWindows()

+ 13 - 0
readme.md

@@ -1 +1,14 @@
 初始化
+
+
+浊度检测深度学习方案:
+一、样本标注
+我们首先将一张图片划分为多个小块,每个小块都对应一个标签。标签类别如下:
+0:表示背景;1:表示清澈水体;2:表示浑浊水体
+
+1.工具开发
+添加图片标注工具,对原始图像进行标注,生成对应的标签文件,存储格式为:
+文件名称:与图片名称一致,后缀为txt;
+文件内容:对应图片的标签信息,每行表示一个块;
+文件格式:u,v,w,h,label u,v为块左上角坐标,w,h为块的宽和高,label为块的标签
+添加标注信息展示工具,将图片和标签信息进行展示,方便用户查看标注信息

BIN
temp_4.png


+ 0 - 0
video/原始视频文件.md