Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
O
Oil_Level_Recognition_System
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
柳青君
Oil_Level_Recognition_System
Commits
026ceb91
Commit
026ceb91
authored
Nov 25, 2025
by
Yuhaibo
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
13
parent
582c107b
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
170 additions
and
352 deletions
+170
-352
.gitignore
.gitignore
+2
-0
IMPORT_PATH_FIX.md
handlers/modelpage/IMPORT_PATH_FIX.md
+0
-314
MODEL_TEST_MIGRATION_PLAN.md
handlers/modelpage/MODEL_TEST_MIGRATION_PLAN.md
+2
-1
model_test_handler.py
handlers/modelpage/model_test_handler.py
+0
-0
model_training_handler.py
handlers/modelpage/model_training_handler.py
+119
-1
modelset_page.py
widgets/modelpage/modelset_page.py
+47
-36
No files found.
.gitignore
View file @
026ceb91
...
...
@@ -10,6 +10,8 @@
!__main__.py
!__init__.py
!.gitignore
!*.md
!**/*.md
# 忽略Python缓存文件
__pycache__/
...
...
handlers/modelpage/IMPORT_PATH_FIX.md
deleted
100644 → 0
View file @
582c107b
# model_page_handler.py 导入路径修复说明
## 文件位置变更
### 变更前
```
widgets/modelpage/model_page_handler.py
```
### 变更后
```
handlers/modelpage/model_page_handler.py ✅
```
---
## 导入路径修复
### 问题分析
文件从
`widgets/modelpage/`
移动到
`handlers/modelpage/`
后,所有导入路径都需要相应调整:
#### 目录结构
```
项目根目录/
├── widgets/
│ └── modelpage/
│ ├── model_loader.py
│ ├── model_operations.py
│ ├── modelset_page.py
│ └── training_page.py
│
└── handlers/
└── modelpage/
├── model_page_handler.py ← 当前文件位置
└── model_training_handler.py
```
---
## 修复的导入路径
### 1. ModelLoader 和 ModelOperations
#### ❌ 修复前(错误)
```
python
from
.model_loader
import
ModelLoader
from
.model_operations
import
ModelOperations
```
**问题**
:
-
使用相对导入
`.`
,表示从当前包
`handlers.modelpage`
导入
-
但这两个文件在
`widgets.modelpage`
包中,不在当前包
#### ✅ 修复后(正确)
```
python
# 导入插件接口(从 widgets.modelpage)
try
:
# 优先使用相对导入
from
...widgets.modelpage.model_loader
import
ModelLoader
from
...widgets.modelpage.model_operations
import
ModelOperations
except
ImportError
:
try
:
# 备用:绝对导入
from
widgets.modelpage.model_loader
import
ModelLoader
from
widgets.modelpage.model_operations
import
ModelOperations
except
ImportError
:
# 如果都失败,创建占位类
class
ModelLoader
:
def
__init__
(
self
,
handler
=
None
):
pass
class
ModelOperations
:
def
__init__
(
self
,
handler
=
None
):
pass
```
**说明**
:
-
`...widgets.modelpage`
:向上3层(
`modelpage`
→
`handlers`
→ 项目根),然后进入
`widgets/modelpage`
-
添加备用的绝对导入和占位类,确保导入失败时不会崩溃
---
### 2. ModelSetPage 和 TrainingPage
#### ❌ 修复前(错误)
```
python
from
.modelset_page
import
ModelSetPage
from
.training_page
import
TrainingPage
```
**问题**
:同样使用了错误的相对导入
#### ✅ 修复后(正确)
```
python
# 导入页面组件(从 widgets.modelpage)
try
:
from
...widgets.modelpage.modelset_page
import
ModelSetPage
from
...widgets.modelpage.training_page
import
TrainingPage
except
ImportError
:
try
:
from
widgets.modelpage.modelset_page
import
ModelSetPage
from
widgets.modelpage.training_page
import
TrainingPage
except
ImportError
as
e
:
print
(
f
"[ERROR] 无法导入必要的页面组件: {e}"
)
return
QtWidgets
.
QWidget
()
```
**说明**
:
-
使用相对导入
`...widgets.modelpage`
从正确的包导入
-
提供备用的绝对导入
-
添加错误处理
---
### 3. ModelTrainingHandler
#### ❌ 修复前(错误)
```
python
from
...handlers.modelpage.model_training_handler
import
ModelTrainingHandler
```
**问题**
:
-
使用了错误的相对路径
`...handlers.modelpage`
-
应该使用
`.model_training_handler`
,因为在同一个包内
#### ✅ 修复后(正确)
```
python
# 导入训练处理器
try
:
# 优先使用相对导入(同一包内)
from
.model_training_handler
import
ModelTrainingHandler
except
ImportError
:
try
:
# 备用:绝对导入
from
handlers.modelpage.model_training_handler
import
ModelTrainingHandler
except
ImportError
:
ModelTrainingHandler
=
None
print
(
"[WARNING] 无法导入ModelTrainingHandler,训练功能将不可用"
)
```
**说明**
:
-
`.model_training_handler`
:从当前包
`handlers.modelpage`
导入
-
只需要一层相对导入,因为在同一个目录下
---
## 相对导入层级说明
### 相对导入语法
```
python
from
.
import
xxx
# 当前包
from
..
import
xxx
# 父包(上一层)
from
...
import
xxx
# 祖父包(上两层)
from
....
import
xxx
# 曾祖父包(上三层)
```
### 当前文件位置导入路径
当前文件:
`handlers/modelpage/model_page_handler.py`
| 目标模块 | 相对路径 | 层级解释 |
|---------|---------|---------|
|
`handlers.modelpage.model_training_handler`
|
`.model_training_handler`
| 同一包内 |
|
`handlers.model_load_handler`
|
`..model_load_handler`
| 父包(handlers) |
|
`widgets.modelpage.model_loader`
|
`...widgets.modelpage.model_loader`
| 祖父包(项目根) → widgets |
| 项目根目录模块 |
`...module_name`
| 祖父包(项目根) |
### 路径计算示例
从
`handlers/modelpage/model_page_handler.py`
导入
`widgets/modelpage/model_loader.py`
:
```
当前位置: handlers/modelpage/model_page_handler.py
目标位置: widgets/modelpage/model_loader.py
相对路径计算:
1. 从 model_page_handler.py 向上到 modelpage/ (.)
2. 从 modelpage/ 向上到 handlers/ (..)
3. 从 handlers/ 向上到 项目根/ (...)
4. 从 项目根/ 进入 widgets/modelpage/ (...widgets.modelpage)
5. 导入 model_loader.py (...widgets.modelpage.model_loader)
最终导入语句:
from ...widgets.modelpage.model_loader import ModelLoader
```
---
## 修复总结
### 修复的导入数量
-
✅
**ModelLoader**
- 从 widgets.modelpage 导入
-
✅
**ModelOperations**
- 从 widgets.modelpage 导入
-
✅
**ModelSetPage**
- 从 widgets.modelpage 导入
-
✅
**TrainingPage**
- 从 widgets.modelpage 导入
-
✅
**ModelTrainingHandler**
- 从 handlers.modelpage 导入(同一包)
### 修复原则
1.
**跨包导入**
(widgets ↔ handlers):
-
使用多层相对导入
`...widgets.xxx`
或
`...handlers.xxx`
-
提供绝对导入作为备用
2.
**同包导入**
(handlers.modelpage 内部):
-
使用单层相对导入
`.module_name`
-
提供绝对导入作为备用
3.
**错误处理**
:
-
所有导入都包裹在 try-except 中
-
提供多层备用方案
-
导入失败时不会导致程序崩溃
---
## 验证检查
### ✅ Linter 检查
```
bash
# 无 linter 错误
No linter errors found.
```
### 🔍 导入测试
```
python
# 测试导入是否成功
try
:
from
handlers.modelpage.model_page_handler
import
ModelPageHandler
print
(
"✅ 导入成功"
)
except
ImportError
as
e
:
print
(
f
"❌ 导入失败: {e}"
)
```
### 📋 检查清单
-
[
x
]
ModelLoader 导入路径正确
-
[
x
]
ModelOperations 导入路径正确
-
[
x
]
ModelSetPage 导入路径正确
-
[
x
]
TrainingPage 导入路径正确
-
[
x
]
ModelTrainingHandler 导入路径正确
-
[
x
]
无 linter 错误
-
[
x
]
提供多层备用导入方案
-
[
x
]
添加错误处理
---
## 相关文件
### 当前文件
-
`handlers/modelpage/model_page_handler.py`
- 已修复
### 依赖文件
-
`widgets/modelpage/model_loader.py`
- 插件接口
-
`widgets/modelpage/model_operations.py`
- 插件接口
-
`widgets/modelpage/modelset_page.py`
- 页面组件
-
`widgets/modelpage/training_page.py`
- 页面组件
-
`handlers/modelpage/model_training_handler.py`
- 训练处理器
---
## 注意事项
### ⚠️ 文件位置重要性
-
文件位置决定了导入路径
-
移动文件后必须更新所有导入语句
-
相对导入层级取决于文件在包结构中的位置
### 💡 最佳实践
1.
**优先使用相对导入**
:便于重构和移动包
2.
**提供备用绝对导入**
:增加兼容性
3.
**添加错误处理**
:防止导入失败导致崩溃
4.
**添加注释说明**
:帮助理解导入路径
### 🔄 如果再次移动文件
如果将来再次移动
`model_page_handler.py`
,需要:
1.
重新计算相对导入的层级
2.
更新所有
`from ...`
导入语句
3.
测试所有导入是否成功
4.
运行 linter 检查
---
## 测试建议
### 单元测试
```
python
def
test_imports
():
"""测试所有导入是否成功"""
try
:
from
handlers.modelpage.model_page_handler
import
ModelPageHandler
assert
ModelPageHandler
is
not
None
# 测试创建实例
handler
=
ModelPageHandler
()
assert
handler
is
not
None
print
(
"✅ 所有导入测试通过"
)
except
Exception
as
e
:
print
(
f
"❌ 导入测试失败: {e}"
)
raise
```
### 集成测试
1.
启动应用程序
2.
访问模型管理页面
3.
确认所有功能正常
4.
检查控制台无导入错误
---
**修复时间**
: 2025-11-06
**问题类型**
: 导入路径错误(文件位置变更)
**影响范围**
: model_page_handler.py
**修复状态**
: ✅ 已完成
**测试状态**
: ✅ Linter 检查通过
handlers/modelpage/MODEL_TEST_MIGRATION_PLAN.md
View file @
026ceb91
...
...
@@ -3,7 +3,8 @@
## 目标
将
`model_training_handler.py`
中所有模型测试相关的代码迁移到
`model_test_handler.py`
## 需要迁移的方法列表
## 需要迁移的方法列表14324141
### 1. 测试入口和控制方法
-
[
x
]
`_handleStartTest()`
- 开始/停止测试按钮处理 (第2005-2014行)
...
...
handlers/modelpage/model_test_handler.py
View file @
026ceb91
This diff is collapsed.
Click to expand it.
handlers/modelpage/model_training_handler.py
View file @
026ceb91
...
...
@@ -2514,7 +2514,7 @@ class ModelTrainingHandler(ModelTestHandler):
print
(
f
"🔧 [模型加载] ULTRALYTICS_OFFLINE = {os.environ.get('ULTRALYTICS_OFFLINE')}"
)
print
(
f
"🚀 [模型加载] 开始加载YOLO模型: {model_path}"
)
model
=
YOLO
(
model_path
)
(
model_path
)
print
(
f
"✅ [模型加载] YOLO模型加载成功"
)
# 读取标注配置
...
...
@@ -2669,3 +2669,121 @@ class ModelTrainingHandler(ModelTestHandler):
print
(
f
"[错误] 显示测试摘要失败: {e}"
)
import
traceback
traceback
.
print_exc
()
def
_refreshModelSetPage
(
self
):
"""刷新模型集管理页面"""
try
:
# 获取主窗口的模型集页面
if
hasattr
(
self
,
'main_window'
)
and
hasattr
(
self
.
main_window
,
'modelSetPage'
):
print
(
"[信息] 正在刷新模型集管理页面..."
)
self
.
main_window
.
modelSetPage
.
loadModelsFromConfig
()
print
(
"[信息] 模型集管理页面刷新完成"
)
else
:
print
(
"[警告] 无法访问模型集管理页面"
)
except
Exception
as
e
:
print
(
f
"[错误] 刷新模型集管理页面失败: {e}"
)
import
traceback
traceback
.
print_exc
()
def
_refreshModelTestPage
(
self
):
"""刷新模型测试页面的模型列表"""
try
:
# 获取主窗口的模型测试页面
if
hasattr
(
self
,
'main_window'
)
and
hasattr
(
self
.
main_window
,
'testModelPage'
):
print
(
"[信息] 正在刷新模型测试页面..."
)
# 如果有模型集页面,从模型集页面加载模型
if
hasattr
(
self
.
main_window
,
'modelSetPage'
):
self
.
main_window
.
testModelPage
.
loadModelsFromModelSetPage
(
self
.
main_window
.
modelSetPage
)
else
:
# 否则直接刷新模型测试页面
if
hasattr
(
self
.
main_window
.
testModelPage
,
'loadModelsFromConfig'
):
self
.
main_window
.
testModelPage
.
loadModelsFromConfig
()
print
(
"[信息] 模型测试页面刷新完成"
)
else
:
print
(
"[警告] 无法访问模型测试页面"
)
except
Exception
as
e
:
print
(
f
"[错误] 刷新模型测试页面失败: {e}"
)
import
traceback
traceback
.
print_exc
()
def
_addTrainedModelToModelSet
(
self
,
converted_files
,
weights_dir
):
"""将训练好的模型添加到模型集配置"""
try
:
if
not
converted_files
:
print
(
"[信息] 没有转换的模型文件,跳过添加到模型集"
)
return
print
(
f
"[信息] 正在将 {len(converted_files)} 个训练模型添加到模型集..."
)
# 获取项目根目录
project_root
=
get_project_root
()
# 为每个转换的模型文件创建模型信息
for
dat_file
in
converted_files
:
try
:
# 获取模型文件信息
model_path
=
Path
(
dat_file
)
model_name
=
f
"训练模型-{model_path.parent.name}-{model_path.stem}"
# 检查模型是否已存在
if
hasattr
(
self
,
'main_window'
)
and
hasattr
(
self
.
main_window
,
'modelSetPage'
):
existing_models
=
self
.
main_window
.
modelSetPage
.
getAllModels
()
if
any
(
model_name
in
model
for
model
in
existing_models
):
print
(
f
"[信息] 模型 {model_name} 已存在,跳过添加"
)
continue
# 创建模型参数
model_params
=
{
'name'
:
model_name
,
'type'
:
'YOLOv11'
,
'path'
:
str
(
dat_file
),
'config_path'
:
''
,
'description'
:
f
'训练于 {weights_dir}'
if
weights_dir
else
'自动训练生成的模型'
,
'size'
:
self
.
_getFileSize
(
str
(
dat_file
)),
'classes'
:
3
,
# liquid, foam, air
'input'
:
'640x640'
,
'confidence'
:
0.5
,
'iou'
:
0.45
,
'device'
:
'CUDA:0 (GPU)'
,
'batch_size'
:
16
,
'blur_training'
:
100
,
'epochs'
:
300
,
'workers'
:
8
,
'model_type'
:
'训练模型'
,
'source'
:
'training'
}
# 添加到模型集页面
if
hasattr
(
self
,
'main_window'
)
and
hasattr
(
self
.
main_window
,
'modelSetPage'
):
self
.
main_window
.
modelSetPage
.
_model_params
[
model_name
]
=
model_params
self
.
main_window
.
modelSetPage
.
addModelToList
(
model_name
)
print
(
f
"[信息] 已添加模型: {model_name}"
)
except
Exception
as
model_error
:
print
(
f
"[错误] 添加模型 {dat_file} 失败: {model_error}"
)
continue
print
(
"[信息] 训练模型添加到模型集完成"
)
except
Exception
as
e
:
print
(
f
"[错误] 添加训练模型到模型集失败: {e}"
)
import
traceback
traceback
.
print_exc
()
def
_getFileSize
(
self
,
file_path
):
"""获取文件大小(格式化字符串)"""
try
:
if
os
.
path
.
exists
(
file_path
):
size_bytes
=
os
.
path
.
getsize
(
file_path
)
if
size_bytes
<
1024
:
return
f
"{size_bytes} B"
elif
size_bytes
<
1024
*
1024
:
return
f
"{size_bytes / 1024:.1f} KB"
elif
size_bytes
<
1024
*
1024
*
1024
:
return
f
"{size_bytes / (1024 * 1024):.1f} MB"
else
:
return
f
"{size_bytes / (1024 * 1024 * 1024):.1f} GB"
else
:
return
"未知"
except
:
return
"未知"
widgets/modelpage/modelset_page.py
View file @
026ceb91
...
...
@@ -1237,45 +1237,56 @@ class ModelSetPage(QtWidgets.QWidget):
try
:
# 获取模型目录路径
current_dir
=
Path
(
__file__
)
.
parent
.
parent
.
parent
model_dir
=
current_dir
/
"database"
/
"model"
/
"detection_model"
if
not
model_dir
.
exists
():
pass
return
models
pass
# 遍历所有子目录,并按目录名排序(确保模型1最先)
sorted_subdirs
=
sorted
(
model_dir
.
iterdir
(),
key
=
lambda
x
:
x
.
name
if
x
.
is_dir
()
else
''
)
for
subdir
in
sorted_subdirs
:
if
subdir
.
is_dir
():
# 查找 .dat 文件(优先)
for
model_file
in
sorted
(
subdir
.
glob
(
"*.dat"
)):
models
.
append
({
'name'
:
f
"模型-{subdir.name}-{model_file.stem}"
,
'path'
:
str
(
model_file
),
'subdir'
:
subdir
.
name
,
'source'
:
'scan'
,
'format'
:
'dat'
})
pass
# 然后查找 .pt 文件
for
model_file
in
sorted
(
subdir
.
glob
(
"*.pt"
)):
models
.
append
({
'name'
:
f
"模型-{subdir.name}-{model_file.stem}"
,
'path'
:
str
(
model_file
),
'subdir'
:
subdir
.
name
,
'source'
:
'scan'
,
'format'
:
'pt'
})
pass
pass
# 扫描多个模型目录
model_dirs
=
[
(
current_dir
/
"database"
/
"model"
/
"detection_model"
,
"检测模型"
),
(
current_dir
/
"database"
/
"model"
/
"train_model"
,
"训练模型"
),
(
current_dir
/
"database"
/
"model"
/
"test_model"
,
"测试模型"
)
]
for
model_dir
,
dir_type
in
model_dirs
:
if
not
model_dir
.
exists
():
print
(
f
"[信息] {dir_type}目录不存在: {model_dir}"
)
continue
print
(
f
"[信息] 正在扫描{dir_type}目录: {model_dir}"
)
# 遍历所有子目录,并按目录名排序(确保模型1最先)
sorted_subdirs
=
sorted
(
model_dir
.
iterdir
(),
key
=
lambda
x
:
x
.
name
if
x
.
is_dir
()
else
''
)
for
subdir
in
sorted_subdirs
:
if
subdir
.
is_dir
():
# 查找 .dat 文件(优先)
for
model_file
in
sorted
(
subdir
.
glob
(
"*.dat"
)):
models
.
append
({
'name'
:
f
"{dir_type}-{subdir.name}-{model_file.stem}"
,
'path'
:
str
(
model_file
),
'subdir'
:
subdir
.
name
,
'source'
:
'scan'
,
'format'
:
'dat'
,
'model_type'
:
dir_type
})
print
(
f
"[信息] 找到{dir_type}: {model_file}"
)
# 然后查找 .pt 文件
for
model_file
in
sorted
(
subdir
.
glob
(
"*.pt"
)):
models
.
append
({
'name'
:
f
"{dir_type}-{subdir.name}-{model_file.stem}"
,
'path'
:
str
(
model_file
),
'subdir'
:
subdir
.
name
,
'source'
:
'scan'
,
'format'
:
'pt'
,
'model_type'
:
dir_type
})
print
(
f
"[信息] 找到{dir_type}: {model_file}"
)
print
(
f
"[信息] 模型扫描完成,共找到 {len(models)} 个模型"
)
except
Exception
as
e
:
pass
print
(
f
"[错误] 扫描模型目录失败: {e}"
)
import
traceback
traceback
.
print_exc
()
return
models
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment