Commit 8612a557 by Yuhaibo

1

parent f8cfcff7
......@@ -6,6 +6,16 @@
!widgets/**
!handlers/
!handlers/**
!database/
!database/**
!hooks/
!hooks/**
!icons/
!icons/**
!labelme/
!labelme/**
!rules/
!rules/**
!app.py
!__main__.py
!__init__.py
......
channel1:
annotation_count: 1
areas:
area_1:
height: 20mm
name: 通道1_区域1
boxes:
- - 617
- 415
- 192
fixed_bottoms:
- 482
fixed_tops:
- 387
last_updated: '2025-11-27 15:55:10'
channel2:
annotation_count: 1
areas:
area_1:
height: 20mm
name: 我去饿_区域1
boxes:
- - 643
- 558
- 160
fixed_bottoms:
- 616
fixed_tops:
- 534
last_updated: '2025-11-26 20:09:26'
channel3:
annotation_count: 1
areas:
area_1:
height: 20mm
name: 3_区域1
boxes:
- - 1365
- 915
- 128
fixed_bottoms:
- 939
fixed_tops:
- 886
last_updated: '2025-11-26 20:09:35'
channel4:
annotation_count: 1
areas:
area_1:
height: 20mm
name: asfdhuu_区域1
boxes:
- - 1689
- 884
- 96
fixed_bottoms:
- 908
fixed_tops:
- 860
last_updated: '2025-11-26 20:02:17'
通道1:
annotation_count: 2
areas:
area_1:
height: 20mm
name: 通道1_区域1
area_2:
height: 22mm
name: 通道1_
boxes:
- - 653
- 281
- 192
- - 337
- 520
- 160
fixed_bottoms:
- 204
- 579
fixed_tops:
- 300
- 456
last_updated: '2025-11-03 15:58:08'
channels:
1:
address: rtsp://admin:cei345678@192.168.0.127:8000/stream1
channel_id: 1
name: 不后悔1
2:
address: rtsp://admin:cei345678@192.168.0.127:8000/stream1
channel_id: 2
name: '2'
3:
address: rtsp://admin:cei345678@192.168.0.127:8000/stream1
channel_id: 3
name: '3'
4:
address: rtsp://admin:cei345678@192.168.0.127:8000/stream1
channel_id: 4
name: '4'
channel2:
general:
task_id: '123'
task_name: '21'
save_liquid_data_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\123_21
channel3:
general:
task_id: '123'
task_name: '21'
save_liquid_data_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\123_21
channel4:
general:
task_id: '1'
task_name: '1'
save_liquid_data_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\1_1
channel1:
general:
task_id: '1'
task_name: '1'
area_count: 0
safe_low: 2.0mm
safe_high: 10.0mm
frequency: 25fps
video_format: AVI
push_address: ''
video_path: ''
save_liquid_data_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\1_1
areas:
area_1: 通道1_区域1
area_2: 通道1_区域2
area_heights:
area_1: 20mm
area_2: 20mm
model:
model_path: d:\restructure\liquid_level_line_detection_system\database\model\detection_model\5\best.dat
channel_1:
general:
task_id: '1'
task_name: '1'
save_liquid_data_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\1_1
channel_2:
general:
task_id: '2'
task_name: '2'
save_liquid_data_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\2_2
channel_3:
general:
task_id: '3'
task_name: '3'
save_liquid_data_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\3_3
channel_4:
general:
task_id: '4'
task_name: '4'
save_liquid_data_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\4_4
address_list: 'rtsp://admin:cei345678@192.168.0.121:8000/stream1
rtsp://admin:cei345678@192.168.0.122:8000/stream1
rtsp://admin:cei345678@192.168.0.123:8000/stream1
rtsp://admin:cei345678@192.168.0.124:8000/stream1
rtsp://admin:cei345678@192.168.0.125:8000/stream1'
batch_processing_enabled: false
channel1:
name: 通道1
address: rtsp://admin:cei345678@192.168.0.127:8000/stream1
channel1_model_path: database/model/detection_model/detect/best.dat
channel2:
name: 通道2
address: rtsp://admin:cei345678@192.168.0.127:8000/stream1
channel2_model_path: database/model/detection_model/detect/best.dat
channel3:
name: 通道3
address: rtsp://admin:cei345678@192.168.0.127:8000/stream1
channel3_model_path: database/model/detection_model/detect/best.dat
channel4:
name: 通道4
address: rtsp://admin:cei345678@192.168.0.127:8000/stream1
channel4_model_path: database/model/detection_model/detect/best.dat
classes:
- color: '#FF0000'
enabled: true
id: 0
name: person
- color: '#00FF00'
enabled: true
id: 1
name: car
- color: '#0000FF'
enabled: true
id: 2
name: bicycle
compilation: release
crop_frame_rate: 2
curve_frame_rate: 2
default_batch_size: 4
default_device: cuda
default_model: 模型-5-best
detection_frame_rate: 5
display_frame_rate: 25
gpu_enabled: true
max_batch_wait_time: 0.05
mission:
auto_start: false
max_missions: 10
mission_result_format: json
save_mission_results: true
model:
agnostic_nms: false
batch_size: 1
confidence_threshold: 0.5
config_path: null
dynamic_shape: false
half_precision: false
input_size:
- 640
- 640
iou_threshold: 0.45
keep_ratio: true
max_det: 100
model_path: null
model_type: YOLOv5
multi_label: false
profiler: false
use_coreml: false
use_openvino: false
use_tensorrt: false
verbose: false
visualize_features: false
model_base_path: database/model/detection_model
paths:
auto_create_dirs: true
export_path: ./exports
log_path: ./logs
model_path: ./models
project_path: ./projects
performance:
cache_size: 1000
enable_cache: true
gpu_device: cuda:0
num_threads: 4
use_gpu: false
safety_limit:
lower_limit: 0.0
show_limits: true
upper_limit: 20.0
save_data_rate: 2
shape:
fill_color:
- 255
- 0
- 0
- 100
hvertex_fill_color:
- 255
- 0
- 0
- 255
label_font: Arial
label_font_size: 16
line_color:
- 0
- 255
- 0
- 128
point_size: 8
scale: 1.0
select_fill_color:
- 0
- 255
- 0
- 155
select_line_color:
- 255
- 255
- 255
- 255
vertex_fill_color:
- 0
- 255
- 0
- 255
shortcuts:
add_channel: Ctrl+Shift+C
add_mission: Ctrl+N
connect_channel: Ctrl+C
export_mission_result: Ctrl+E
fullscreen: F11
general_settings: Ctrl+,
model_settings: Ctrl+M
open_file: Ctrl+O
open_video: Ctrl+Shift+O
quit: Ctrl+Q
save_mission_result: Ctrl+S
start_mission: Ctrl+R
stop_mission: Ctrl+T
toggle_channel_panel: F1
toggle_mission_panel: F2
test_model_memory: D:\restructure\liquid_level_line_detection_system\database\model\detection_model\5\best.dat
logging:
level: INFO
console: true
file_enabled: true
log_dir: logs
max_file_size: 10
backup_count: 5
ui:
channel_dock:
closable: true
floatable: true
movable: true
show: true
confirm_exit: true
font_family: null
font_size: 10
mission_dock:
closable: true
floatable: true
movable: true
show: true
show_statusbar: true
show_toolbar: true
theme: light
task_id: '123'
task_name: '21'
status: 待配置
selected_channels:
- 通道2
- 通道3
created_time: '2025-11-26 14:55:31'
mission_result_folder_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\123_21
task_id: '1'
task_name: '1'
status: 待配置
selected_channels:
- 通道1
- 通道2
- 通道3
- 通道4
created_time: '2025-11-26 19:53:35'
mission_result_folder_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\1_1
task_id: '1'
task_name: '2'
status: 待配置
selected_channels:
- 通道1
- 通道2
created_time: '2025-11-26 16:24:36'
mission_result_folder_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\1_2
task_id: '1'
task_name: '222'
status: 待配置
selected_channels:
- 通道1
- 通道2
- 通道3
- 通道4
created_time: '2025-11-26 19:58:15'
mission_result_folder_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\1_222
task_id: '1'
task_name: test
status: 待配置
selected_channels:
- 通道1
- 通道2
- 通道3
- 通道4
created_time: '2025-11-26 19:46:34'
mission_result_folder_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\1_test
task_id: '21'
task_name: '321'
status: 待配置
selected_channels:
- 通道1
- 通道2
- 通道3
- 通道4
created_time: '2025-11-26 20:08:46'
mission_result_folder_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\21_321
task_id: '2'
task_name: test
status: 待配置
selected_channels:
- 通道1
- 通道2
- 通道3
- 通道4
created_time: '2025-11-26 20:01:16'
mission_result_folder_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\2_test
task_id: 2恶趣味
task_id: 2恶趣味
task_name: q'we
status: 待配置
selected_channels:
- 通道2
created_time: '2025-11-26 14:56:26'
mission_result_folder_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\2恶趣味_q'we
task_id: 吃个海鲜
task_id: 吃个海鲜
task_name: 显示提醒他
status: 待配置
selected_channels:
- 通道4
created_time: '2025-11-27 11:06:03'
mission_result_folder_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\吃个海鲜_显示提醒他
task_id: 大润发给
task_id: 大润发给
task_name: 上方
status: 待配置
selected_channels:
- 通道1
- 通道2
- 通道3
created_time: '2025-11-27 11:00:31'
mission_result_folder_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\大润发给_上方
task_id: 的使得发
task_id: 的使得发
task_name: 如图微软
status: 待配置
selected_channels:
- 通道1
- 通道3
- 通道4
created_time: '2025-11-27 11:02:21'
mission_result_folder_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\的使得发_如图微软
task_id: 的啊
task_id: 的啊
task_name: 而突然
status: 待配置
selected_channels:
- 通道1
- 通道2
- 通道3
- 通道4
created_time: '2025-11-27 11:03:28'
mission_result_folder_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\的啊_而突然
test_model:
areas:
area_1:
height: 20mm
name: test_model_区域1
area_2:
height: 20mm
name: test_model_区域2
bottoms:
- !!python/tuple
- 1082
- 1028
- !!python/tuple
- 1140
- 283
boxes:
- !!python/tuple
- 1078
- 934
- 192
- !!python/tuple
- 1141
- 222
- 128
tops:
- !!python/tuple
- 1076
- 839
- !!python/tuple
- 1140
- 159
# 物理变焦设备配置示例
# 用于配置海康威视摄像头的物理变焦功能
# 通道1配置 - 海康威视球机
channel1_device:
ip: "192.168.1.100" # 设备IP地址
port: 8000 # 设备端口,默认8000
username: "admin" # 登录用户名
password: "admin123" # 登录密码
channel: 1 # 设备通道号
enable_physical_zoom: true # 是否启用物理变焦
zoom_capabilities:
min_zoom: 1.0 # 最小变焦倍数
max_zoom: 30.0 # 最大变焦倍数
zoom_step: 0.5 # 变焦步长
auto_focus: true # 是否支持自动聚焦
# 通道2配置 - 海康威视枪机(不支持变焦)
channel2_device:
ip: "192.168.1.101"
port: 8000
username: "admin"
password: "admin123"
channel: 1
enable_physical_zoom: false # 枪机通常不支持变焦
# 通道3配置 - 海康威视球机
channel3_device:
ip: "192.168.1.102"
port: 8000
username: "admin"
password: "admin123"
channel: 1
enable_physical_zoom: true
zoom_capabilities:
min_zoom: 1.0
max_zoom: 20.0 # 不同型号支持的倍数可能不同
zoom_step: 0.5
auto_focus: true
# 通道4配置 - 海康威视球机
channel4_device:
ip: "192.168.1.103"
port: 8000
username: "admin"
password: "admin123"
channel: 1
enable_physical_zoom: true
zoom_capabilities:
min_zoom: 1.0
max_zoom: 25.0
zoom_step: 0.5
auto_focus: true
# 全局配置
global_settings:
# 物理变焦优先级:true表示优先使用物理变焦,false表示优先使用数字变焦
prefer_physical_zoom: true
# 连接超时时间(秒)
connection_timeout: 10
# 变焦操作超时时间(秒)
zoom_timeout: 15
# 自动重连间隔(秒)
reconnect_interval: 30
# 错误重试次数
max_retry_count: 3
# 使用说明:
# 1. 将此文件重命名为 physical_zoom_config.yaml
# 2. 根据实际设备信息修改IP地址、用户名、密码等
# 3. 确保设备支持PTZ控制功能
# 4. 在放大窗口中使用以下快捷键:
# - 鼠标滚轮:变焦放大/缩小
# - R键:重置变焦到1倍
# - D键:显示物理变焦状态
# - F键:自动聚焦
# - H键:显示/隐藏帮助信息
# - E键:切换锐化增强
# - N键:切换降噪处理
# - C键:切换对比度增强
#
# 注意:系统只支持物理变焦,需要海康威视PTZ设备支持
{
"model_config": {
"model_type": "YOLOv8",
"model_size": "n",
"pretrained": true,
"input_size": [640, 640]
},
"training_config": {
"epochs": 100,
"batch_size": 16,
"learning_rate": 0.01,
"optimizer": "SGD",
"momentum": 0.937,
"weight_decay": 0.0005
},
"dataset_config": {
"num_classes": 3,
"class_names": ["liquid", "foam", "background"],
"data_yaml": "database/config/train_configs/data.yaml"
},
"augmentation_config": {
"hsv_h": 0.015,
"hsv_s": 0.7,
"hsv_v": 0.4,
"degrees": 0.0,
"translate": 0.1,
"scale": 0.5,
"shear": 0.0,
"perspective": 0.0,
"flipud": 0.0,
"fliplr": 0.5,
"mosaic": 1.0,
"mixup": 0.0
},
"validation_config": {
"val_interval": 1,
"save_period": 10,
"patience": 50
},
"device_config": {
"device": "cuda",
"workers": 8,
"amp": true
}
}
# 模板1 - 快速训练配置(轻量级)
# 用于快速验证模型和数据集
task: segment
mode: train
model: database/model/detection_model/5/best.dat
data: database/dataset/data_template_1.yaml
epochs: 50
batch: 8
imgsz: 416
save: true
save_period: 10
cache: false
device: gpu
workers: 4
project: runs/train
name: template_1_exp
exist_ok: false
pretrained: false
optimizer: SGD
verbose: false
seed: 0
deterministic: true
single_cls: false
rect: false
cos_lr: false
close_mosaic: 10
resume: false
amp: false
fraction: 1.0
profile: false
freeze: null
multi_scale: false
overlap_mask: true
mask_ratio: 4
dropout: 0.0
val: true
split: val
save_json: false
conf: null
iou: 0.7
max_det: 300
half: false
dnn: false
plots: true
source: null
vid_stride: 1
stream_buffer: false
visualize: false
augment: false
agnostic_nms: false
classes: null
retina_masks: false
embed: null
show: false
save_frames: false
save_txt: false
save_conf: false
save_crop: false
show_labels: true
show_conf: true
show_boxes: true
line_width: null
format: torchscript
keras: false
optimize: false
int8: false
dynamic: false
simplify: true
opset: null
workspace: null
nms: false
lr0: 0.01
lrf: 0.01
momentum: 0.937
weight_decay: 0.0005
warmup_epochs: 3.0
warmup_momentum: 0.8
warmup_bias_lr: 0.1
box: 7.5
cls: 0.5
dfl: 1.5
pose: 12.0
kobj: 1.0
nbs: 64
hsv_h: 0.015
hsv_s: 0.7
hsv_v: 0.4
degrees: 0.0
translate: 0.1
scale: 0.5
shear: 0.0
perspective: 0.0
flipud: 0.0
fliplr: 0.5
bgr: 0.0
mosaic: 1.0
mixup: 0.0
cutmix: 0.0
copy_paste: 0.0
copy_paste_mode: flip
auto_augment: randaugment
erasing: 0.4
cfg: null
tracker: botsort.yaml
# 模板2 - 标准训练配置(平衡型)
# 用于常规模型训练,平衡精度和速度
task: segment
mode: train
model: database/model/detection_model/5/best.dat
data: database/dataset/data_template_2.yaml
epochs: 100
batch: 16
imgsz: 640
save: true
save_period: 10
cache: false
device: gpu
workers: 4
project: runs/train
name: template_2_exp
exist_ok: false
pretrained: false
optimizer: SGD
verbose: false
seed: 0
deterministic: true
single_cls: false
rect: false
cos_lr: false
close_mosaic: 10
resume: false
amp: false
fraction: 1.0
profile: false
freeze: null
multi_scale: false
overlap_mask: true
mask_ratio: 4
dropout: 0.0
val: true
split: val
save_json: false
conf: null
iou: 0.7
max_det: 300
half: false
dnn: false
plots: true
source: null
vid_stride: 1
stream_buffer: false
visualize: false
augment: false
agnostic_nms: false
classes: null
retina_masks: false
embed: null
show: false
save_frames: false
save_txt: false
save_conf: false
save_crop: false
show_labels: true
show_conf: true
show_boxes: true
line_width: null
format: torchscript
keras: false
optimize: false
int8: false
dynamic: false
simplify: true
opset: null
workspace: null
nms: false
lr0: 0.01
lrf: 0.01
momentum: 0.937
weight_decay: 0.0005
warmup_epochs: 3.0
warmup_momentum: 0.8
warmup_bias_lr: 0.1
box: 7.5
cls: 0.5
dfl: 1.5
pose: 12.0
kobj: 1.0
nbs: 64
hsv_h: 0.015
hsv_s: 0.7
hsv_v: 0.4
degrees: 0.0
translate: 0.1
scale: 0.5
shear: 0.0
perspective: 0.0
flipud: 0.0
fliplr: 0.5
bgr: 0.0
mosaic: 1.0
mixup: 0.0
cutmix: 0.0
copy_paste: 0.0
copy_paste_mode: flip
auto_augment: randaugment
erasing: 0.4
cfg: null
tracker: botsort.yaml
# 模板3 - 高精度训练配置(精度优先)
# 用于追求最高精度的模型训练
task: segment
mode: train
model: database/model/detection_model/5/best.dat
data: database/dataset/data_template_3.yaml
epochs: 200
batch: 32
imgsz: 768
save: true
save_period: 10
cache: false
device: gpu
workers: 4
project: runs/train
name: template_3_exp
exist_ok: false
pretrained: false
optimizer: Adam
verbose: false
seed: 0
deterministic: true
single_cls: false
rect: false
cos_lr: true
close_mosaic: 10
resume: false
amp: false
fraction: 1.0
profile: false
freeze: null
multi_scale: true
overlap_mask: true
mask_ratio: 4
dropout: 0.0
val: true
split: val
save_json: false
conf: null
iou: 0.7
max_det: 300
half: false
dnn: false
plots: true
source: null
vid_stride: 1
stream_buffer: false
visualize: false
augment: false
agnostic_nms: false
classes: null
retina_masks: false
embed: null
show: false
save_frames: false
save_txt: false
save_conf: false
save_crop: false
show_labels: true
show_conf: true
show_boxes: true
line_width: null
format: torchscript
keras: false
optimize: false
int8: false
dynamic: false
simplify: true
opset: null
workspace: null
nms: false
lr0: 0.01
lrf: 0.01
momentum: 0.937
weight_decay: 0.0005
warmup_epochs: 3.0
warmup_momentum: 0.8
warmup_bias_lr: 0.1
box: 7.5
cls: 0.5
dfl: 1.5
pose: 12.0
kobj: 1.0
nbs: 64
hsv_h: 0.015
hsv_s: 0.7
hsv_v: 0.4
degrees: 0.0
translate: 0.1
scale: 0.5
shear: 0.0
perspective: 0.0
flipud: 0.0
fliplr: 0.5
bgr: 0.0
mosaic: 1.0
mixup: 0.0
cutmix: 0.0
copy_paste: 0.0
copy_paste_mode: flip
auto_augment: randaugment
erasing: 0.4
cfg: null
tracker: botsort.yaml
task_id: 2恶趣味
task_id: 2恶趣味
task_name: q'we
status: 待配置
selected_channels:
- 通道2
created_time: '2025-11-26 14:56:26'
mission_result_folder_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\2恶趣味_q'we
然后我去佛i好的食品发酵食品的
然后我去佛i好的食品发酵食品的
\ No newline at end of file
{
"d:\\restructure\\liquid_level_line_detection_system\\database\\data\\111\\recording_20251114_161804.mp4": {
"save_path": "d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture",
"region_paths": [
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\recording_20251114_161804_区域1",
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\recording_20251114_161804_区域2",
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\recording_20251114_161804_区域3"
],
"timestamp": 1763623553.6413627
},
"d:\\restructure\\liquid_level_line_detection_system\\database\\data\\111\\采集视频_20251115_213950.mp4": {
"save_path": "d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture",
"region_paths": [
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251115_213950_区域1",
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251115_213950_区域2",
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251115_213950_区域3"
],
"timestamp": 1763623570.4085448
},
"d:\\restructure\\liquid_level_line_detection_system\\database\\data\\111\\11.mp4": {
"save_path": "d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture",
"region_paths": [
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\11_区域1"
],
"timestamp": 1764162728.0737584
},
"D:\\restructure\\liquid_level_line_detection_system\\database\\data\\111\\11.mp4": {
"save_path": "d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture",
"region_paths": [
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\11_区域1",
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\11_区域2"
],
"timestamp": 1763809441.0187602
},
"D:\\restructure\\liquid_level_line_detection_system\\database\\data\\111\\recording_20251114_161804.mp4": {
"save_path": "d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture",
"region_paths": [
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\recording_20251114_161804_区域1",
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\recording_20251114_161804_区域2",
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\recording_20251114_161804_区域3"
],
"timestamp": 1763652978.8164835
},
"D:\\restructure\\liquid_level_line_detection_system\\database\\data\\111\\采集视频_20251114_162238.mp4": {
"save_path": "d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture",
"region_paths": [
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251114_162238_区域1",
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251114_162238_区域2",
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251114_162238_区域3"
],
"timestamp": 1763653387.158211
},
"D:\\restructure\\liquid_level_line_detection_system\\database\\data\\111\\采集视频_20251115_213950.mp4": {
"save_path": "d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture",
"region_paths": [
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251115_213950_区域1",
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251115_213950_区域2",
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251115_213950_区域3"
],
"timestamp": 1763653027.766409
},
"D:\\restructure\\liquid_level_line_detection_system\\database\\data\\111\\采集视频_20251118_102818.mp4": {
"save_path": "d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture",
"region_paths": [
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251118_102818_区域1",
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251118_102818_区域2",
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251118_102818_区域3"
],
"timestamp": 1763653036.4475722
},
"D:\\restructure\\liquid_level_line_detection_system\\database\\data\\111\\采集视频_20251120_152702.mp4": {
"save_path": "d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture",
"region_paths": [
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251120_152702_区域1",
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251120_152702_区域2",
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251120_152702_区域3"
],
"timestamp": 1763653067.312616
},
"D:\\restructure\\liquid_level_line_detection_system\\database\\data\\111\\采集视频_20251120_153508.mp4": {
"save_path": "d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture",
"region_paths": [
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251120_153508_区域1",
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251120_153508_区域2",
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251120_153508_区域3"
],
"timestamp": 1763801356.5907655
},
"d:\\restructure\\liquid_level_line_detection_system\\database\\data\\111\\采集视频_20251118_102818.mp4": {
"save_path": "d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture",
"region_paths": [
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251118_102818_区域1",
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251118_102818_区域2",
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251118_102818_区域3"
],
"timestamp": 1764210156.5055494
},
"d:\\restructure\\liquid_level_line_detection_system\\database\\data\\test2\\采集视频_20251127_094018.mp4": {
"save_path": "d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture",
"region_paths": [
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251127_094018_区域1",
"d:\\restructure\\liquid_level_line_detection_system\\database\\Corp_picture\\采集视频_20251127_094018_区域2"
],
"timestamp": 1764210266.1624653
}
}
\ No newline at end of file
"""
Pythonexe
SDK_internal
"""
import os
import base64
from pathlib import Path
def embed_file_to_python(file_path, output_path, var_name):
"""
Pythonbase64
Args:
file_path:
output_path: Python
var_name:
"""
with open(file_path, 'rb') as f:
data = f.read()
encoded = base64.b64encode(data).decode('utf-8')
# Python
code = f'''"""
: {file_path}
"""
import base64
import io
# Base64
_{var_name}_data = """{encoded}"""
def get_{var_name}():
""""""
return base64.b64decode(_{var_name}_data)
def get_{var_name}_path():
""""""
import tempfile
import os
data = get_{var_name}()
#
ext = os.path.splitext("{os.path.basename(file_path)}")[1]
#
fd, temp_path = tempfile.mkstemp(suffix=ext, prefix='embedded_resource_')
try:
with os.fdopen(fd, 'wb') as f:
f.write(data)
return temp_path
except:
os.close(fd)
raise
'''
with open(output_path, 'w', encoding='utf-8') as f:
f.write(code)
print(f" : {file_path} -> {output_path} (: {var_name})")
def embed_directory_to_python(dir_path, output_dir, max_size_mb=1):
"""
Python
Args:
dir_path:
output_dir:
max_size_mb: MB
"""
os.makedirs(output_dir, exist_ok=True)
embedded_files = []
skipped_files = []
for root, dirs, files in os.walk(dir_path):
for file in files:
file_path = os.path.join(root, file)
rel_path = os.path.relpath(file_path, dir_path)
#
size_mb = os.path.getsize(file_path) / (1024 * 1024)
if size_mb > max_size_mb:
skipped_files.append((rel_path, size_mb))
continue
#
var_name = rel_path.replace(os.sep, '_').replace('.', '_').replace('-', '_')
#
output_path = os.path.join(output_dir, f"embedded_{var_name}.py")
try:
embed_file_to_python(file_path, output_path, var_name)
embedded_files.append((rel_path, file_path))
except Exception as e:
print(f" : {file_path} - {e}")
skipped_files.append((rel_path, size_mb))
print(f"\n:")
print(f" : {len(embedded_files)} ")
print(f" : {len(skipped_files)} {max_size_mb}MB")
return embedded_files, skipped_files
if __name__ == '__main__':
# icons
project_root = os.path.abspath('.')
icons_dir = os.path.join(project_root, 'icons')
output_dir = os.path.join(project_root, 'hooks', 'embedded_resources')
if os.path.exists(icons_dir):
print("icons...")
embed_directory_to_python(icons_dir, output_dir, max_size_mb=0.5) # 0.5MB
else:
print(f": {icons_dir}")
# -*- coding: utf-8 -*-
"""
PyInstaller hook for encodings module
encodings encodings
"""
from PyInstaller.utils.hooks import collect_submodules
# encodings
hiddenimports = collect_submodules('encodings')
# encodings exe.spec
# encodings base_library.zip
datas = []
"""
PyArmor Hook for PyInstaller
PyInstallerPyArmor
"""
from PyInstaller.utils.hooks import collect_data_files, collect_submodules
# PyArmor
hiddenimports = [
'pyarmor',
'pyarmor.pyarmor_runtime',
'pyarmor.pyarmor_runtime_000000',
'pyarmor.pytransform',
'pytransform',
]
# pyarmor
try:
hiddenimports += collect_submodules('pyarmor')
except:
pass
# PyArmor
datas = []
try:
datas += collect_data_files('pyarmor')
except:
pass
# PyArmorhook
# PyArmor.so/.dll
binaries = []
try:
from PyInstaller.utils.hooks import collect_dynamic_libs
binaries += collect_dynamic_libs('pyarmor')
except:
pass
from PyInstaller.utils.hooks import collect_submodules, collect_dynamic_libs
#
# - torch .py _internal/torch
# - DLL/PYD Python PYZ.pyc
hiddenimports = collect_submodules('torch')
binaries = collect_dynamic_libs('torch')
datas = []
import os
import sys
import faulthandler
import traceback
from datetime import datetime
def _log_dir() -> str:
# onedir: sys.executable dist/exe/exe.exe
base_dir = os.path.dirname(getattr(sys, "executable", sys.argv[0]))
path = os.path.join(base_dir, "logs")
try:
os.makedirs(path, exist_ok=True)
except Exception:
#
path = os.path.join(os.path.abspath(os.getcwd()), "logs")
os.makedirs(path, exist_ok=True)
return path
def _open_log_file():
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
log_path = os.path.join(_log_dir(), f"app_{timestamp}.log")
#
# encodings
try:
return open(log_path, mode="a", encoding="utf-8", buffering=1)
except (LookupError, NameError):
# encodings
return open(log_path, mode="a", buffering=1)
def _install_handlers():
log_fh = _open_log_file()
#
print_fn = lambda *args: log_fh.write(" ".join(str(a) for a in args) + "\n")
print_fn("===== Application Start =====")
print_fn("Executable:", getattr(sys, "executable", sys.argv[0]))
print_fn("CWD:", os.getcwd())
print_fn("Args:", " ".join(sys.argv))
# stdout/stderr
sys.stdout = log_fh
sys.stderr = log_fh
# faulthandler
try:
faulthandler.enable(log_fh)
except Exception:
pass
#
def _excepthook(exc_type, exc, tb):
log_fh.write("===== Uncaught Exception =====\n")
traceback.print_exception(exc_type, exc, tb, file=log_fh)
log_fh.flush()
sys.excepthook = _excepthook
# import Python
# sys.modules encodings
def _delayed_install():
try:
# encodings
import encodings
_install_handlers()
except Exception:
# encodings
try:
_install_handlers()
except Exception:
#
pass
#
import sys
if hasattr(sys, '_getframe'):
# sys._getframe
try:
_delayed_install()
except:
pass
else:
#
try:
_delayed_install()
except:
pass
import os
import sys
import json
import tempfile
import shutil
# hook
# - Python
# - _internal/encrypted .bin DLL
# - /IV
AES256_KEY = b'0123456789ABCDEF0123456789ABCDEF' # exe.spec
AES_IV = b'ABCDEF0123456789' # exe.spec
PROTECT_KEYWORDS = ['torch', 'torchvision', 'torchaudio']
def _try_import_crypto():
try:
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
return Cipher, algorithms, modes, default_backend
except Exception:
return None, None, None, None
def _decrypt_bytes(data: bytes) -> bytes:
Cipher, algorithms, modes, default_backend = _try_import_crypto()
if Cipher is not None:
cipher = Cipher(algorithms.AES(AES256_KEY), modes.CTR(AES_IV), backend=default_backend())
decryptor = cipher.decryptor()
return decryptor.update(data) + decryptor.finalize()
# XOR
key = AES256_KEY
out = bytearray(len(data))
for i, b in enumerate(data):
out[i] = b ^ key[i % len(key)]
return bytes(out)
def _get_base_dir():
# PyInstaller onedir _MEIPASS _internal
# _MEIPASS
if hasattr(sys, '_MEIPASS') and sys._MEIPASS:
return sys._MEIPASS
# exe
exe_dir = os.path.dirname(sys.executable)
# dist/exe/exe.exe dist/exe/_internal
# a.datas encrypted _internal/encrypted
return os.path.join(exe_dir, '_internal')
def _load_manifest(encrypted_root):
manifest_path = os.path.join(encrypted_root, 'manifest.json')
if not os.path.exists(manifest_path):
return []
try:
with open(manifest_path, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception:
return []
def _prepare_temp_dir():
base = tempfile.gettempdir()
target = os.path.join(base, 'lllds_decrypt_bins')
os.makedirs(target, exist_ok=True)
return target
def _add_search_path(path):
# Windows: DLL
try:
if hasattr(os, 'add_dll_directory'):
os.add_dll_directory(path)
except Exception:
pass
if path not in os.environ.get('PATH', ''):
os.environ['PATH'] = path + os.pathsep + os.environ.get('PATH', '')
if path not in sys.path:
sys.path.insert(0, path)
def _main():
try:
base_dir = _get_base_dir()
encrypted_root = os.path.join(base_dir, 'encrypted')
if not os.path.isdir(encrypted_root):
return
manifest = _load_manifest(encrypted_root)
if not manifest:
return
out_dir = _prepare_temp_dir()
wrote_any = False
for item in manifest:
name = item.get('name')
cipher_rel = item.get('cipher_path')
if not name or not cipher_rel:
continue
#
low = name.lower()
if not any(k in low for k in PROTECT_KEYWORDS):
continue
cipher_abs = os.path.join(base_dir, cipher_rel.replace('/', os.sep))
if not os.path.exists(cipher_abs):
continue
with open(cipher_abs, 'rb') as f:
enc = f.read()
raw = _decrypt_bytes(enc)
out_path = os.path.join(out_dir, name)
with open(out_path, 'wb') as wf:
wf.write(raw)
wrote_any = True
if wrote_any:
_add_search_path(out_dir)
except Exception:
#
pass
_main()
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
PyInstaller Hook - ultralytics
ultralytics
"""
import os
import sys
import tempfile
from pathlib import Path
def setup_ultralytics_environment():
""" ultralytics """
try:
#
if getattr(sys, 'frozen', False):
#
app_dir = Path(sys.executable).parent
else:
#
app_dir = Path(__file__).parent.parent
# ultralytics
os.environ['YOLO_CONFIG_DIR'] = str(app_dir / 'database' / 'config')
# ultralytics
temp_dir = tempfile.mkdtemp(prefix='ultralytics_')
os.environ['ULTRALYTICS_CONFIG_DIR'] = temp_dir
# ultralytics
os.environ['YOLO_VERBOSE'] = 'False'
os.environ['ULTRALYTICS_ANALYTICS'] = 'False'
print(f" ultralytics : {app_dir}")
except Exception as e:
print(f" ultralytics : {e}")
#
setup_ultralytics_environment()
"""
PyArmor Runtime Hook
PyInstallerPyArmor
"""
import os
import sys
def _init_pyarmor_runtime():
"""
PyArmor
PyArmor
"""
try:
# _internalonedir
if hasattr(sys, '_MEIPASS'):
# onefile
base_dir = sys._MEIPASS
else:
# onedirexe.exe_internal
exe_dir = os.path.dirname(sys.executable)
base_dir = os.path.join(exe_dir, '_internal')
# _internalsys.path
if base_dir not in sys.path:
sys.path.insert(0, base_dir)
# PyArmorPyArmor
try:
import pyarmor.pyarmor_runtime # type: ignore #
except ImportError:
# PyArmor
pass
except Exception:
#
pass
#
_init_pyarmor_runtime()
File added
# flake8: noqa
import logging
import sys
from qtpy import QT_VERSION
__appname__ = "labelme"
# Semantic Versioning 2.0.0: https://semver.org/
# 1. MAJOR version when you make incompatible API changes;
# 2. MINOR version when you add functionality in a backwards-compatible manner;
# 3. PATCH version when you make backwards-compatible bug fixes.
# e.g., 1.0.0a0, 1.0.0a1, 1.0.0b0, 1.0.0rc0, 1.0.0, 1.0.0.post0
__version__ = "5.2.1"
QT4 = QT_VERSION[0] == "4"
QT5 = QT_VERSION[0] == "5"
del QT_VERSION
PY2 = sys.version[0] == "2"
PY3 = sys.version[0] == "3"
del sys
from labelme.label_file import LabelFile
from labelme import testing
from labelme import utils
import argparse
import codecs
import logging
import os
import os.path as osp
import sys
import yaml
# Python
parent_dir = osp.dirname(osp.dirname(osp.abspath(__file__)))
if parent_dir not in sys.path:
sys.path.insert(0, parent_dir)
from qtpy import QtCore
from qtpy import QtWidgets
from labelme import __appname__
from labelme import __version__
from labelme.app import MainWindow
from labelme.config import get_config
from labelme.logger import logger
from labelme.utils import newIcon
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
"--version", "-V", action="store_true", help="show version"
)
parser.add_argument(
"--reset-config", action="store_true", help="reset qt config"
)
parser.add_argument(
"--logger-level",
default="info",
choices=["debug", "info", "warning", "fatal", "error"],
help="logger level",
)
parser.add_argument("filename", nargs="?", help="image or label filename")
parser.add_argument(
"--output",
"-O",
"-o",
help="output file or directory (if it ends with .json it is "
"recognized as file, else as directory)",
)
default_config_file = os.path.join(os.path.expanduser("~"), ".labelmerc")
parser.add_argument(
"--config",
dest="config",
help="config file or yaml-format string (default: {})".format(
default_config_file
),
default=default_config_file,
)
# config for the gui
parser.add_argument(
"--nodata",
dest="store_data",
action="store_false",
help="stop storing image data to JSON file",
default=argparse.SUPPRESS,
)
parser.add_argument(
"--autosave",
dest="auto_save",
action="store_true",
help="auto save",
default=argparse.SUPPRESS,
)
parser.add_argument(
"--nosortlabels",
dest="sort_labels",
action="store_false",
help="stop sorting labels",
default=argparse.SUPPRESS,
)
parser.add_argument(
"--flags",
help="comma separated list of flags OR file containing flags",
default=argparse.SUPPRESS,
)
parser.add_argument(
"--labelflags",
dest="label_flags",
help=r"yaml string of label specific flags OR file containing json "
r"string of label specific flags (ex. {person-\d+: [male, tall], "
r"dog-\d+: [black, brown, white], .*: [occluded]})", # NOQA
default=argparse.SUPPRESS,
)
parser.add_argument(
"--labels",
help="comma separated list of labels OR file containing labels",
default=argparse.SUPPRESS,
)
parser.add_argument(
"--validatelabel",
dest="validate_label",
choices=["exact"],
help="label validation types",
default=argparse.SUPPRESS,
)
parser.add_argument(
"--keep-prev",
action="store_true",
help="keep annotation of previous frame",
default=argparse.SUPPRESS,
)
parser.add_argument(
"--epsilon",
type=float,
help="epsilon to find nearest vertex on canvas",
default=argparse.SUPPRESS,
)
args = parser.parse_args()
if args.version:
print("{0} {1}".format(__appname__, __version__))
sys.exit(0)
logger.setLevel(getattr(logging, args.logger_level.upper()))
if hasattr(args, "flags"):
if os.path.isfile(args.flags):
with codecs.open(args.flags, "r", encoding="utf-8") as f:
args.flags = [line.strip() for line in f if line.strip()]
else:
args.flags = [line for line in args.flags.split(",") if line]
if hasattr(args, "labels"):
if os.path.isfile(args.labels):
with codecs.open(args.labels, "r", encoding="utf-8") as f:
args.labels = [line.strip() for line in f if line.strip()]
else:
args.labels = [line for line in args.labels.split(",") if line]
if hasattr(args, "label_flags"):
if os.path.isfile(args.label_flags):
with codecs.open(args.label_flags, "r", encoding="utf-8") as f:
args.label_flags = yaml.safe_load(f)
else:
args.label_flags = yaml.safe_load(args.label_flags)
config_from_args = args.__dict__
config_from_args.pop("version")
reset_config = config_from_args.pop("reset_config")
filename = config_from_args.pop("filename")
output = config_from_args.pop("output")
config_file_or_yaml = config_from_args.pop("config")
config = get_config(config_file_or_yaml, config_from_args)
if not config["labels"] and config["validate_label"]:
logger.error(
"--labels must be specified with --validatelabel or "
"validate_label: true in the config file "
"(ex. ~/.labelmerc)."
)
sys.exit(1)
output_file = None
output_dir = None
if output is not None:
if output.endswith(".json"):
output_file = output
else:
output_dir = output
translator = QtCore.QTranslator()
translator.load(
QtCore.QLocale.system().name(),
osp.dirname(osp.abspath(__file__)) + "/translate",
)
app = QtWidgets.QApplication(sys.argv)
app.setApplicationName(__appname__)
app.setWindowIcon(newIcon("icon"))
app.installTranslator(translator)
win = MainWindow(
config=config,
filename=filename,
output_file=output_file,
output_dir=output_dir,
)
if reset_config:
logger.info("Resetting Qt config: %s" % win.settings.fileName())
win.settings.clear()
sys.exit(0)
win.show()
win.raise_()
sys.exit(app.exec_())
# this main block is required to generate executable by pyinstaller
if __name__ == "__main__":
main()
This diff is collapsed. Click to expand it.
# flake8: noqa
from . import draw_json
from . import draw_label_png
from . import json_to_dataset
from . import on_docker
#!/usr/bin/env python
import argparse
import sys
import imgviz
import matplotlib.pyplot as plt
from labelme.label_file import LabelFile
from labelme import utils
PY2 = sys.version_info[0] == 2
def main():
parser = argparse.ArgumentParser()
parser.add_argument("json_file")
args = parser.parse_args()
label_file = LabelFile(args.json_file)
img = utils.img_data_to_arr(label_file.imageData)
label_name_to_value = {"_background_": 0}
for shape in sorted(label_file.shapes, key=lambda x: x["label"]):
label_name = shape["label"]
if label_name in label_name_to_value:
label_value = label_name_to_value[label_name]
else:
label_value = len(label_name_to_value)
label_name_to_value[label_name] = label_value
lbl, _ = utils.shapes_to_label(
img.shape, label_file.shapes, label_name_to_value
)
label_names = [None] * (max(label_name_to_value.values()) + 1)
for name, value in label_name_to_value.items():
label_names[value] = name
lbl_viz = imgviz.label2rgb(
lbl,
imgviz.asgray(img),
label_names=label_names,
font_size=30,
loc="rb",
)
plt.subplot(121)
plt.imshow(img)
plt.subplot(122)
plt.imshow(lbl_viz)
plt.show()
if __name__ == "__main__":
main()
import argparse
import imgviz
import matplotlib.pyplot as plt
import numpy as np
import PIL.Image
from labelme.logger import logger
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument("label_png", help="label PNG file")
args = parser.parse_args()
lbl = np.asarray(PIL.Image.open(args.label_png))
logger.info("label shape: {}".format(lbl.shape))
logger.info("unique label values: {}".format(np.unique(lbl)))
lbl_viz = imgviz.label2rgb(lbl)
plt.imshow(lbl_viz)
plt.show()
if __name__ == "__main__":
main()
import argparse
import base64
import json
import os
import os.path as osp
import imgviz
import PIL.Image
from labelme.logger import logger
from labelme import utils
def main():
logger.warning(
"This script is aimed to demonstrate how to convert the "
"JSON file to a single image dataset."
)
logger.warning(
"It won't handle multiple JSON files to generate a "
"real-use dataset."
)
parser = argparse.ArgumentParser()
parser.add_argument("json_file")
parser.add_argument("-o", "--out", default=None)
args = parser.parse_args()
json_file = args.json_file
if args.out is None:
out_dir = osp.basename(json_file).replace(".", "_")
out_dir = osp.join(osp.dirname(json_file), out_dir)
else:
out_dir = args.out
if not osp.exists(out_dir):
os.mkdir(out_dir)
data = json.load(open(json_file))
imageData = data.get("imageData")
if not imageData:
imagePath = os.path.join(os.path.dirname(json_file), data["imagePath"])
with open(imagePath, "rb") as f:
imageData = f.read()
imageData = base64.b64encode(imageData).decode("utf-8")
img = utils.img_b64_to_arr(imageData)
label_name_to_value = {"_background_": 0}
for shape in sorted(data["shapes"], key=lambda x: x["label"]):
label_name = shape["label"]
if label_name in label_name_to_value:
label_value = label_name_to_value[label_name]
else:
label_value = len(label_name_to_value)
label_name_to_value[label_name] = label_value
lbl, _ = utils.shapes_to_label(
img.shape, data["shapes"], label_name_to_value
)
label_names = [None] * (max(label_name_to_value.values()) + 1)
for name, value in label_name_to_value.items():
label_names[value] = name
lbl_viz = imgviz.label2rgb(
lbl, imgviz.asgray(img), label_names=label_names, loc="rb"
)
PIL.Image.fromarray(img).save(osp.join(out_dir, "img.png"))
utils.lblsave(osp.join(out_dir, "label.png"), lbl)
PIL.Image.fromarray(lbl_viz).save(osp.join(out_dir, "label_viz.png"))
with open(osp.join(out_dir, "label_names.txt"), "w") as f:
for lbl_name in label_names:
f.write(lbl_name + "\n")
logger.info("Saved to: {}".format(out_dir))
if __name__ == "__main__":
main()
#!/usr/bin/env python
from __future__ import print_function
import argparse
import distutils.spawn
import json
import os
import os.path as osp
import platform
import shlex
import subprocess
import sys
def get_ip():
dist = platform.platform().split("-")[0]
if dist == "Linux":
return ""
elif dist == "Darwin":
cmd = "ifconfig en0"
output = subprocess.check_output(shlex.split(cmd))
if str != bytes: # Python3
output = output.decode("utf-8")
for row in output.splitlines():
cols = row.strip().split(" ")
if cols[0] == "inet":
ip = cols[1]
return ip
else:
raise RuntimeError("No ip is found.")
else:
raise RuntimeError("Unsupported platform.")
def labelme_on_docker(in_file, out_file):
ip = get_ip()
cmd = "xhost + %s" % ip
subprocess.check_output(shlex.split(cmd))
if out_file:
out_file = osp.abspath(out_file)
if osp.exists(out_file):
raise RuntimeError("File exists: %s" % out_file)
else:
open(osp.abspath(out_file), "w")
cmd = (
"docker run -it --rm"
" -e DISPLAY={0}:0"
" -e QT_X11_NO_MITSHM=1"
" -v /tmp/.X11-unix:/tmp/.X11-unix"
" -v {1}:{2}"
" -w /home/developer"
)
in_file_a = osp.abspath(in_file)
in_file_b = osp.join("/home/developer", osp.basename(in_file))
cmd = cmd.format(
ip,
in_file_a,
in_file_b,
)
if out_file:
out_file_a = osp.abspath(out_file)
out_file_b = osp.join("/home/developer", osp.basename(out_file))
cmd += " -v {0}:{1}".format(out_file_a, out_file_b)
cmd += " wkentaro/labelme labelme {0}".format(in_file_b)
if out_file:
cmd += " -O {0}".format(out_file_b)
subprocess.call(shlex.split(cmd))
if out_file:
try:
json.load(open(out_file))
return out_file
except Exception:
if open(out_file).read() == "":
os.remove(out_file)
raise RuntimeError("Annotation is cancelled.")
def main():
parser = argparse.ArgumentParser()
parser.add_argument("in_file", help="Input file or directory.")
parser.add_argument("-O", "--output")
args = parser.parse_args()
if not distutils.spawn.find_executable("docker"):
print("Please install docker", file=sys.stderr)
sys.exit(1)
try:
out_file = labelme_on_docker(args.in_file, args.output)
if out_file:
print("Saved to: %s" % out_file)
except RuntimeError as e:
sys.stderr.write(e.__str__() + "\n")
sys.exit(1)
if __name__ == "__main__":
main()
import os.path as osp
import shutil
import yaml
from labelme.logger import logger
here = osp.dirname(osp.abspath(__file__))
def update_dict(target_dict, new_dict, validate_item=None):
for key, value in new_dict.items():
if validate_item:
validate_item(key, value)
if key not in target_dict:
logger.warn("Skipping unexpected key in config: {}".format(key))
continue
if isinstance(target_dict[key], dict) and isinstance(value, dict):
update_dict(target_dict[key], value, validate_item=validate_item)
else:
target_dict[key] = value
# -----------------------------------------------------------------------------
def get_default_config():
# labelme
config_file = osp.join(here, "default_config.yaml")
with open(config_file, encoding='utf-8') as f:
config = yaml.safe_load(f)
# save default config to ~/.labelmerc
user_config_file = osp.join(osp.expanduser("~"), ".labelmerc")
if not osp.exists(user_config_file):
try:
shutil.copy(config_file, user_config_file)
except Exception:
logger.warn("Failed to save config: {}".format(user_config_file))
return config
def validate_config_item(key, value):
if key == "validate_label" and value not in [None, "exact"]:
raise ValueError(
"Unexpected value for config key 'validate_label': {}".format(
value
)
)
if key == "shape_color" and value not in [None, "auto", "manual"]:
raise ValueError(
"Unexpected value for config key 'shape_color': {}".format(value)
)
if key == "labels" and value is not None and len(value) != len(set(value)):
raise ValueError(
"Duplicates are detected for config key 'labels': {}".format(value)
)
def get_config(config_file_or_yaml=None, config_from_args=None):
# 1. default config
config = get_default_config()
# 2. specified as file or yaml
if config_file_or_yaml is not None:
config_from_yaml = yaml.safe_load(config_file_or_yaml)
if not isinstance(config_from_yaml, dict):
with open(config_from_yaml, encoding='utf-8') as f:
logger.info(
"Loading config file from: {}".format(config_from_yaml)
)
config_from_yaml = yaml.safe_load(f)
update_dict(
config, config_from_yaml, validate_item=validate_config_item
)
# 3. command line argument or specified config file
if config_from_args is not None:
update_dict(
config, config_from_args, validate_item=validate_config_item
)
return config
auto_save: true
display_label_popup: true
store_data: true
keep_prev: false
keep_prev_scale: false
keep_prev_brightness: false
keep_prev_contrast: false
logger_level: info
flags: null
label_flags: null
labels: null
file_search: null
sort_labels: true
validate_label: null
default_shape_color: [0, 255, 0]
shape_color: auto # null, 'auto', 'manual'
shift_auto_shape_color: 0
label_colors: null
shape:
# drawing
line_color: [0, 255, 0, 128]
fill_color: [0, 255, 0, 0] # transparent
vertex_fill_color: [0, 255, 0, 255]
# selecting / hovering
select_line_color: [255, 255, 255, 255]
select_fill_color: [0, 255, 0, 155]
hvertex_fill_color: [255, 255, 255, 255]
point_size: 8
# main
flag_dock:
show: true
closable: true
movable: true
floatable: true
label_dock:
show: true
closable: true
movable: true
floatable: true
shape_dock:
show: true
closable: true
movable: true
floatable: true
file_dock:
show: true
closable: true
movable: true
floatable: true
# label_dialog
show_label_text_field: true
label_completion: startswith
fit_to_content:
column: true
row: false
# canvas
epsilon: 10.0
canvas:
# None: do nothing
# close: close polygon
double_click: close
# The max number of edits we can undo
num_backups: 10
# show crosshair
crosshair:
polygon: false
rectangle: true
circle: false
line: false
point: false
linestrip: false
shortcuts:
close: Ctrl+W
open: Ctrl+O
open_dir: Ctrl+U
quit: Ctrl+Q
save: Ctrl+S
save_as: Ctrl+Shift+S
save_to: null
delete_file: Ctrl+Delete
open_next: [D, Ctrl+Shift+D]
open_prev: [A, Ctrl+Shift+A]
zoom_in: [Ctrl++, Ctrl+=]
zoom_out: Ctrl+-
zoom_to_original: Ctrl+0
fit_window: Ctrl+F
fit_width: Ctrl+Shift+F
create_polygon: Ctrl+N
create_rectangle: Ctrl+R
create_circle: null
create_line: null
create_point: null
create_linestrip: null
edit_polygon: Ctrl+J
delete_polygon: Delete
duplicate_polygon: Ctrl+D
copy_polygon: Ctrl+C
paste_polygon: Ctrl+V
undo: Ctrl+Z
undo_last_point: Ctrl+Z
add_point_to_edge: Ctrl+Shift+P
edit_label: Ctrl+E
toggle_keep_prev_mode: Ctrl+P
remove_selected_point: [Meta+H, Backspace]
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment