diff --git a/readme.md b/readme.md index d22c277..44e1ff1 100644 --- a/readme.md +++ b/readme.md @@ -7,15 +7,17 @@ A Python-based image binary segmentation evaluation toolbox. ## 一些规划 * [ ] 向执行脚本中添加配置信息合理行检测. -* 更灵活的配置脚本 +* 更灵活的配置脚本. + [ ] 使用[符合matplotlib要求的](https://matplotlib.org/stable/tutorials/introductory/customizing.html#the-default-matplotlibrc-file)的 yaml 文件来控制绘图格式. + [ ] 是否应该使用更加灵活强大的配置格式, 例如 yaml 或者 toml 来替换配置策略. -* [ ] 添加测试脚本 -* [ ] 添加更详细的注释 -* 优化导出代码 - + [ ] 导出到 XLSX 文件的代码 +* [ ] 添加测试脚本. +* [ ] 添加更详细的注释. +* 优化导出评估结果的代码. + + [x] 实现导出 XLSX 文件的代码. + + [ ] 优化导出到 XLSX 文件的代码. + [ ] 是否应该使用 CSV 这样的文本格式更好些? 既可以当做文本文件打开, 亦可使用Excel来进行整理. -* [ ] 完善关于分组数据的代码, 即CoSOD、Video Binary Segmentation等任务的支持. +* [ ] 使用 `pathlib.Path` 替换 `os.path`. +* [ ] 完善关于分组数据的代码, 即 CoSOD、Video Binary Segmentation 等任务的支持. * [x] 支持并发策略加速计算. 目前保留了多线程支持, 剔除了之前的多进程代码. * [X] 剥离 USVOS 代码到另一个仓库 [PyDavis16EvalToolbox](https://github.com/lartpang/PyDavis16EvalToolbox). * [X] 基于 github page 服务自动化生成结果汇总网页, 并支持基于某个指标进行排序的支持. @@ -59,15 +61,17 @@ A Python-based image binary segmentation evaluation toolbox. ### 安装依赖 -先安装指标代码库: `pip install pysodmetrics` . +先安装相关依赖库: `pip install -r requirements.txt` . -这来自本人的另一个项目:[PySODMetrics](https://github.com/lartpang/PySODMetrics), 欢迎捉BUG! +其中指标评估是基于本人的另一个项目: [PySODMetrics](https://github.com/lartpang/PySODMetrics), 欢迎捉BUG! ### 配置数据集与方法预测的路径信息 本项目依赖于json文件存放数据, `./examples` 中已经提供了数据集和方法配置的例子: `config_dataset_json_example.json` 和 `config_method_json_example.json` , 可以至直接修改他们用于后续步骤. -[注意] 请务必确保*数据集配置文件中数据集的名字*和方法配置文件中*数据集的名字*一致. 准备好json文件后, 建议使用提供的 `tools/check_path.py` 来检查下json文件中的路径信息是否正常. +[注意] +* 请注意, 由于本项目依赖于 OpenCV 读取图片, 所以请确保路径字符串不包含非 ASCII 字符. +* 请务必确保*数据集配置文件中数据集的名字*和方法配置文件中*数据集的名字*一致. 准备好json文件后, 建议使用提供的 `tools/check_path.py` 来检查下json文件中的路径信息是否正常.
@@ -191,10 +195,10 @@ python tools/check_path.py --method-jsons configs/methods/rgb-sod/rgb_sod_method # --curves-npy 输出曲线数据到 output/rgb_sod/curves.npy # --record-txt 输出评估结果文本到 output/rgb_sod/results.txt # --record-xlsx 输出评估结果到excel文档 output/rgb_sod/results.xlsx -# --metric-names 所有结果仅包含指标 mae fm em sm wfm 对应的信息 -# --include-methods 评估过程仅包含 configs/methods/rgb-sod/rgb_sod_methods.json 中包含的方法 MINet_R50_2020 GateNet_2020 -# --include-datasets 评估过程仅包含 configs/datasets/rgb_sod.json 中包含的数据集 PASCAL-S ECSSD -python eval.py --dataset-json configs/datasets/rgb_sod.json --method-json configs/methods/rgb-sod/rgb_sod_methods.json --metric-npy output/rgb_sod/metrics.npy --curves-npy output/rgb_sod/curves.npy --record-txt output/rgb_sod/results.txt --record-xlsx output/rgb_sod/results.xlsx --metric-names mae fm em sm wfm --include-methods MINet_R50_2020 GateNet_2020 --include-datasets PASCAL-S ECSSD +# --metric-names 所有结果仅包含给定指标的信息 +# --include-methods 评估过程仅包含 configs/methods/rgb-sod/rgb_sod_methods.json 中的给定方法 +# --include-datasets 评估过程仅包含 configs/datasets/rgb_sod.json 中的给定数据集 +python eval.py --dataset-json configs/datasets/rgb_sod.json --method-json configs/methods/rgb-sod/rgb_sod_methods.json --metric-npy output/rgb_sod/metrics.npy --curves-npy output/rgb_sod/curves.npy --record-txt output/rgb_sod/results.txt --record-xlsx output/rgb_sod/results.xlsx --metric-names sm wfm mae fmeasure em --include-methods MINet_R50_2020 GateNet_2020 --include-datasets PASCAL-S ECSSD # 得到曲线数据文件,即这里的 output/rgb_sod/curves.npy 文件后,就可以开始绘制图像了 @@ -282,6 +286,7 @@ python plot.py --style-cfg examples/single_row_style.yml --num-rows 1 --curves-n 1. 提供更丰富的指标的支持。 2. 更新`readme.md`和示例文件。 3. 提供更灵活的接口。 + 4. 更新指标库版本。 * 2022年5月15日 - 代码优化 * 2022年4月23日 diff --git a/requirements.txt b/requirements.txt index 64c0045..405f073 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,5 @@ # Automatically generated by https://github.com/damnever/pigar. -# PySODEvalToolkit/utils/misc.py: 6 -Pillow == 8.1.2 - # PySODEvalToolkit/plot.py: 6 # PySODEvalToolkit/tools/converter.py: 10 PyYAML == 5.4.1 @@ -42,7 +39,7 @@ openpyxl == 3.0.7 # PySODEvalToolkit/metrics/extra_metrics.py: 3 # PySODEvalToolkit/untracked/collect_results.py: 9 # PySODEvalToolkit/utils/recorders/metric_recorder.py: 7 -pysodmetrics == 1.3.0 +pysodmetrics == 1.4.0 # PySODEvalToolkit/utils/print_formatter.py: 3 tabulate == 0.8.9 diff --git a/utils/misc.py b/utils/misc.py index 14a782c..26f64b6 100755 --- a/utils/misc.py +++ b/utils/misc.py @@ -5,7 +5,6 @@ import cv2 import numpy as np -from PIL import Image def get_ext(path_list): @@ -145,7 +144,7 @@ def get_name_with_group_list( return name_list -def get_list_with_postfix(dataset_path: str, postfix: str): +def get_list_with_suffix(dataset_path: str, suffix: str): name_list = [] if os.path.isfile(dataset_path): print(f" ++>> {dataset_path} is a file. <<++ ") @@ -158,45 +157,12 @@ def get_list_with_postfix(dataset_path: str, postfix: str): else: print(f" ++>> {dataset_path} is a folder. <<++ ") name_list = [ - os.path.splitext(f)[0] for f in os.listdir(dataset_path) if f.endswith(postfix) + os.path.splitext(f)[0] for f in os.listdir(dataset_path) if f.endswith(suffix) ] name_list = list(set(name_list)) return name_list -def rgb_loader(path): - with open(path, "rb") as f: - img = Image.open(f) - return img.convert("L") - - -def binary_loader(path): - assert os.path.exists(path), f"`{path}` does not exist." - with open(path, "rb") as f: - img = Image.open(f) - return img.convert("L") - - -def load_data(pre_root, gt_root, name, postfixs): - pre = binary_loader(os.path.join(pre_root, name + postfixs[0])) - gt = binary_loader(os.path.join(gt_root, name + postfixs[1])) - return pre, gt - - -def normalize_pil(pre, gt): - gt = np.asarray(gt) - pre = np.asarray(pre) - gt = gt / (gt.max() + 1e-8) - gt = np.where(gt > 0.5, 1, 0) - max_pre = pre.max() - min_pre = pre.min() - if max_pre == min_pre: - pre = pre / 255 - else: - pre = (pre - min_pre) / (max_pre - min_pre) - return pre, gt - - def make_dir(path): if not os.path.exists(path): print(f"`{path}` does not exist,we will create it.") @@ -206,16 +172,13 @@ def make_dir(path): print(f"`{path}`已存在") -def imread_wich_checking(path, for_color: bool = True, with_cv2: bool = True) -> np.ndarray: +def imread_with_checking(path, for_color: bool = True) -> np.ndarray: assert os.path.exists(path=path) and os.path.isfile(path=path), path - if with_cv2: - if for_color: - data = cv2.imread(path, flags=cv2.IMREAD_COLOR) - data = cv2.cvtColor(data, cv2.COLOR_BGR2RGB) - else: - data = cv2.imread(path, flags=cv2.IMREAD_GRAYSCALE) + if for_color: + data = cv2.imread(path, flags=cv2.IMREAD_COLOR) + data = cv2.cvtColor(data, cv2.COLOR_BGR2RGB) else: - data = np.array(Image.open(path).convert("RGB" if for_color else "L")) + data = cv2.imread(path, flags=cv2.IMREAD_GRAYSCALE) return data @@ -233,8 +196,8 @@ def get_gt_pre_with_name( img_path = os.path.join(pre_root, pre_prefix + img_name + pre_suffix) gt_path = os.path.join(gt_root, gt_prefix + img_name + gt_suffix) - pre = imread_wich_checking(img_path, for_color=False) - gt = imread_wich_checking(gt_path, for_color=False) + pre = imread_with_checking(img_path, for_color=False) + gt = imread_with_checking(gt_path, for_color=False) if pre.shape != gt.shape: pre = cv2.resize(pre, dsize=gt.shape[::-1], interpolation=cv2.INTER_LINEAR).astype( @@ -271,8 +234,8 @@ def get_gt_pre_with_name_and_group( img_path = os.path.join(pre_root, pre_prefix + file_name + pre_suffix) gt_path = os.path.join(gt_root, gt_prefix + file_name + gt_suffix) - pre = imread_wich_checking(img_path, for_color=False) - gt = imread_wich_checking(gt_path, for_color=False) + pre = imread_with_checking(img_path, for_color=False) + gt = imread_with_checking(gt_path, for_color=False) if pre.shape != gt.shape: pre = cv2.resize(pre, dsize=gt.shape[::-1], interpolation=interpolation).astype(np.uint8)