画像処理実習 02-yolov5 ターゲット検出

ヨロフ5

YOLOv5 は、YOLO (You Only Look Once) シリーズのアルゴリズムの最新バージョンであるターゲット検出アルゴリズムです。YOLOv5 は、CSPNet (Cross Stage Partial Network) に基づくバックボーン ネットワークと、マルチスケール トレーニング、データ強化、ネットワーク混合精度トレーニングなどの一連の改良された技術を含む新しいアーキテクチャを採用し、それによってより高速な検出速度を実現します。検出精度も向上します。

YOLOv5 は、物体検出、顔検出、車両検出など、複数種類のターゲット検出タスクをサポートしており、インテリジェント セキュリティ、自動運転、ロボット ビジョンなどのさまざまな実用的なシナリオに適用できます。同時に、YOLOv5 は、開発者によるモデルのトレーニングと適用を容易にする、事前トレーニングされたモデルとオープン ソース コードも提供します。

github アドレス: https://github.com/ultralytics/yolov5/blob/master/README.zh-CN.md
公式 Web サイト: https://ultralytics.com/

開発パス

YOLO (You Only Look Once) は、Joseph Redmon らが開発した一連のターゲット検出モデルです。YOLOシリーズの開発経緯は以下の通りです。

  1. YOLOv1: 2015 年に初めて提案された、YOLO シリーズの最初のバージョンです。YOLOv1 は、画像をグリッドに分割し、物体検出タスクを回帰問題に変換することで、各グリッドの境界ボックスとクラス確率を予測します。ただし、YOLOv1 には、不正確な位置決めと小さなターゲットへの感度という問題があります。

  2. YOLOv2 (YOLO9000): 2016 年に提案された、YOLO シリーズの 2 番目のバージョンです。YOLOv2 は、アンカー ボックスとマルチスケール予測を使用して Darknet-19 ネットワーク構造を導入することにより、検出パフォーマンスを向上させます。同時に、YOLOv2 ではターゲット カテゴリのセマンティック セグメンテーションも導入されており、より多くのカテゴリのターゲットを検出できます。

  3. YOLOv3: 2018 年に提案された、YOLO シリーズの 3 番目のバージョンです。YOLOv3 は、YOLOv2 に存在する問題を改善し、マルチスケール予測、FPN 構造の使用、より小さなアンカー ボックスの使用などのテクノロジーを導入し、検出精度と小さなターゲットの検出能力を向上させます。

  4. YOLOv4: 2020 年に提案された、YOLO シリーズの 4 番目のバージョンです。YOLOv4 では、バックボーン ネットワークとしての CSPDarknet53、特徴抽出のための SAM および PANet モジュールの使用、初期化のための YOLOv3 と YOLOv4 の事前トレーニングされた重みの使用など、YOLOv3 に基づく一連の改善が導入されており、検出パフォーマンスと速度が向上しています。

  5. YOLOv5: 2020 年に提案された、YOLO シリーズの 5 番目のバージョンです。YOLOv5 は軽量ネットワーク構造を採用し、検出速度を向上させ、YOLOv5 セグメンテーション モデル、Paddle Paddle エクスポート機能、YOLOv5 AutoCache 自動キャッシュ機能、Comet のロギングと可視化の統合機能などの新機能を導入しています。

全体として、YOLO シリーズ モデルは、継続的な改善と最適化を通じてターゲット検出のパフォーマンスと速度を向上させ、コンピューター ビジョンの分野で重要な進歩を遂げました。

8

YOLOv8 は、YOLOv5 に基づいて改良および最適化された YOLO シリーズ モデルのバリアントです。YOLOv8 モデルには、検出、セグメント化、ポーズ、追跡、分類などの機能が含まれています。以下にこれらの機能について簡単に説明します。

  1. 検出: YOLOv8 モデルは、画像またはビデオ内のターゲットに対してリアルタイムのオブジェクト検出を実行できます。ターゲットの境界ボックスとカテゴリ情報を予測することで、検出タスクを完了します。

  2. セグメント: YOLOv8 モデルは、画像内の各ピクセルを分類し、異なるターゲット領域をセグメント化するターゲット セグメンテーションの機能もサポートしています。この機能を使用すると、画像内のさまざまなオブジェクトを識別し、より正確な位置決めと分析を実行できます。

  3. 姿勢推定 (Pose): YOLOv8 モデルは、検出されたターゲットに対して姿勢推定を実行することもできます。つまり、3 次元空間内のターゲットの姿勢情報を推測します。これは、人間の姿勢分析、ロボットのナビゲーションなど、ターゲットの方向と位置を知る必要がある一部のアプリケーションで非常に役立ちます。

  4. 追跡: YOLOv8 モデルには、ターゲット追跡の機能もあります。つまり、ビデオ内の同じターゲットの位置と軌道を継続的に追跡します。これは、ビデオ監視や自動運転などのアプリケーションにとって非常に重要です。

  5. 分類: ターゲットの検出およびセグメンテーション機能に加えて、YOLOv8 モデルは、検出されたターゲットを分類することもできます。つまり、ターゲット カテゴリ情報を提供します。これは、ターゲットの特性を理解し、より詳細な分析を行うために重要です。

全体として、YOLOv8 モデルは、検出、セグメンテーション、姿勢推定、追跡および分類などを含むさまざまな機能を統合し、より幅広いアプリケーションとより強力な機能を提供します。
ここに画像の説明を挿入します
Github アドレス: https://github.com/ultralytics/ultralytics

v5 の開始例

インストール

リポジトリのクローンを作成し、Python>=3.7.0 環境および PyTorch>=1.7 にrequirements.txt をインストールする必要があります。

micromamba create prefix=d:/python380 python=3.8  #创建3.8的虚拟环境
micromamba activate d:/python380
git clone https://github.com/ultralytics/yolov5  # clone
cd yolov5
pip install -r requirements.txt  # install

ソースコードのディレクトリ構造

yolov5/
├── data/                  # 数据集配置目录
│   ├── coco.yaml            # COCO数据集配置文件,里面有数据集的下载地址和加载的python脚本
│   ├──ImageNet.yaml           # ImageNet数据集
│   ├── custom.yaml          # 自定义数据集配置文件
│   └── ...                  # 其他数据集配置文件
├── models/                # 模型定义目录
│   ├── common.py            # 通用函数和类定义
│   ├── experimental.py      # 实验性模型定义
│   ├── export.py            # 导出模型为ONNX的脚本
│   ├── models.py            # YOLOv5模型定义
│   ├── yolo.py              # YOLO类定义
│   └── ...                  # 其他模型定义文件
├── utils/                 # 实用工具目录
│   ├── autoanchor.py        # 自动锚框生成工具
│   ├── datasets.py          # 数据集处理工具
│   ├── general.py           # 通用实用函数
│   ├── google_utils.py      # Google云平台工具
│   ├── loss.py              # 损失函数定义
│   ├── metrics.py           # 评估指标定义
│   ├── torch_utils.py       # PyTorch工具
│   ├── wandb_logging.py     # WandB日志记录工具
│   └── ...                  # 其他实用工具文件
├── runs/                 # 训练和预测的结果输出目录
│   ├── detect        # 使用detect.py训练后输出目录,输出的目录是[ex自增数字]
│   ├── train        # 使用detect.py训练后输出目录,输出的目录是[ex自增数字],包含了训练好的模型和测试集效果
├── weights/               # 预训练模型权重目录
├── .gitignore             # Git忽略文件配置
├── Dockerfile             # Docker容器构建文件
├── LICENSE                # 许可证文件
├── README.md              # 项目说明文档
├── requirements.txt       # 项目依赖包列表
├── train.py               # 训练脚本
├── detect.py               # 预测脚本
├── export.py               # 导出YOLOv5 PyTorch model to 其他格式
├── hubconf.py               # hubconf.py文件是用于定义模型和数据集的Python模块
└── ...                    # 其他源代码文件

ここでは、yolov5 を通じて一般的に使用される多くのトレーニング データ セットをダウンロードできます。また、ImageNet、
coco128 などのダウンロード アドレスを簡単に見つけることができるため、自分で一生懸命探す必要はありません。

モデルのダウンロード

ダウンロードアドレス: https://github.com/ultralytics/yolov5/releases

v6.1

ここでのバージョンは v6.1 で、これは yolov5 のサブバージョン番号です。

事前トレーニングされたチェックポイント

Pretrained Checkpoints は、事前トレーニングされた重みファイルの名前です。深層学習では、事前トレーニングの重みは、大規模なデータセットでの教師なし学習または教師あり学習を通じて取得されたモデル パラメーターを指します。これらのパラメーターは、多くの場合、新しいモデルを初期化するために使用され、それによってモデルのトレーニングが高速化され、モデルのパフォーマンスが向上します。

事前トレーニング済みチェックポイントは、トレーニング済みの事前トレーニング済み重みファイルを指し、新しいモデルを初期化し、新しいタスクやデータセットに適応するようにモデルをトレーニングし続けるために使用できます。この方法は転移学習と呼ばれ、モデルの学習効率と汎化能力を大幅に向上させることができます。コンピューター ビジョンの分野では、一般的な事前トレーニング済みネットワークには、VGG、ResNet、Inception、MobileNet などが含まれます。

モデル概要

以下のモデル列の説明

リスト 説明する
モデル モデル名
サイズ(ピクセル) 入力画像のサイズ (ピクセル単位)
mAPval0.5:0.95 検証セットの平均平均精度。0.5 ~ 0.95 のすべての IOU しきい値を考慮し、精度は % です。
mAPval0.5 IOU しきい値が 0.5 の場合のみを考慮した、検証セットの平均精度
速度CPU b1(ms) バッチサイズ 1 を使用した場合の CPU での推論速度 (ミリ秒)
速度V100 b1(ms) バッチ サイズ 1 を使用した NVIDIA V100 GPU での推論速度 (ミリ秒)
速度 V100 b32(ms) バッチ サイズ 32 を使用した NVIDIA V100 GPU での推論速度 (ミリ秒単位)
パラメータ(M) モデルのパラメータの数 (百万単位)
フロップス @640 (B) 入力イメージ サイズが 640 の場合のモデルの浮動小数点演算の数 (10 億単位)
モデル サイズ(ピクセル) mAPval0.5:0.95 mAPval0.5 速度CPU b1(ms) 速度V100 b1(ms) 速度 V100 b32(ms) パラメータ(M) フロップス @640 (B)
YOLOv5n 640 28.0 45.7 45 6.3 0.6 1.9 4.5
YOLOv5s 640 37.4 56.8 98 6.4 0.9 7.2 16.5
YOLOv5m 640 45.4 64.1 224 8.2 1.7 21.2 49.0
YOLOv5l 640 49.0 67.3 430 10.1 2.7 46.5 109.1
YOLOv5x 640 50.7 68.9 766 12.1 4.8 86.7 205.7
YOLOv5n6 1280 36.0 54.4 153 8.1 2.1 3.2 4.6
YOLOv5s6 1280 44.8 63.7 385 8.2 3.6 12.6 16.8
YOLOv5m6 1280 51.3 69.3 887 11.1 6.8 35.7 50.0
YOLOv5l6 1280 53.7 71.3 1784年 15.8 10.5 76.8 111.4

v7.0

新しい YOLOv5 v7.0 インスタンス セグメンテーション モデルは、世界最速かつ最も正確で、現在のすべての SOTA ベンチマークを上回ります。これらは非常に使いやすく、簡単にトレーニング、検証、展開できるようにしています。
このリリースの主な目標は、既存のオブジェクト検出モデルと同様の非常にシンプルな YOLOv5 セグメンテーション ワークフローを導入することです。
重要なアップデート

  • セグメンテーション モデル ⭐ 新しい: SOTA YOLOv5-seg COCO 事前トレーニング済みセグメンテーション モデルが初めて提供されました (#9052 は @glenn-jocher、@AyushExel、@Laughing-q によって開発されました)
  • パドル パドル エクスポート: python export.py --include paddle を使用して、YOLOv5 モデル (cls、seg、det) をパドル形式 (#9459 開発者 @glenn-jocher) にエクスポートします。
  • YOLOv5 AutoCache: python train.py --cache ram を使用すると、利用可能なメモリがスキャンされ、予測されたデータセットの RAM 使用量と比較されるようになりました。これにより、キャッシュのリスクが軽減され、データセット キャッシュ機能の使用率が向上し、トレーニングが大幅に高速化されます。(#10027 開発者: @glenn-jocher)
  • Comet のロギングと視覚化の統合: Comet は永久に無料で、YOLOv5 モデルを保存し、トレーニングを再開し、インタラクティブな視覚化とデバッグ予測を行うことができます。(#9232 開発者: @DN6)
モデル サイズ (ピクセル) mAPbox
50-95
mAP マスク
50-95
列車時間 300 エポック
A100 (時間)
ONNX CPU の速度
(ミリ秒)
速度 TRT A100
(ms)
パラメータ(M) フロップ @640(B)
YOLOv5n-se 640 27.6 23.4 80:17 62.7 1.2 2.0 7.1
YOLOv5s-se 640 37.6 31.7 88:16 173.3 1.4 7.6 26.4
YOLOv5mセグ 640 45.0 37.1 108:36 427.0 2.2 22.0 70.8
YOLOv5l-se 640 49.0 39.9 66:43 (2x) 857.4 2.9 47.9 147.7
YOLOv5x セグメント 640 50.7 41.4 62:56 (3x) 1579.2 4.5 88.8 265.7

ここでは、V6.1 モデルyolov5n6.pt
を選択し、そのモデルを yolov5 プロジェクトのルート ディレクトリにスローします。
ここに画像の説明を挿入します

予測する

事前トレーニングされたモデルには特定のカテゴリを検出する機能がすでに備わっているため、data/coco.yml 内の名前を確認すると、合計 80 個のカテゴリがあることがわかります
ここに画像の説明を挿入します
。対象アイテムを検出するスクリプト。
以下は、「./detect.py」スクリプトの共通パラメータの詳細な説明です。

  1. --source: 入力ソースを指定します。画像パス、ビデオ ファイル パス、またはカメラ インデックスを指定できます (デフォルトは、現在のディレクトリのデータ/画像で、画像が 2 つだけ含まれています)。

  2. --weights: モデルウェイトファイルへのパスを指定します。ローカル パスまたは PaddleHub モデル センターのモデル名を指定できます。デフォルトは、現在のディレクトリの yolov5s.pt です。

  3. --data: 使用するデータセットの構成ファイルを指定します。データセットの設定ファイルには、データセットのパス、カテゴリラベル、トレーニングセット、検証セット、テストセットの分割などの情報が含まれており、デフォルトはdata/coco128.yamlです(オプション)。

  4. --img-size:入力画像のサイズを「640,480」のように「,」の形式で指定します。デフォルトは 640x640 です。

  5. --conf-thres: ターゲットの信頼度のしきい値 (0 ~ 1 の範囲)。このしきい値を超えるターゲットは保持されます。デフォルトは 0.25 です。

  6. --iou-thres: NMS (非最大抑制) の IoU (交差オーバーユニオン) しきい値。範囲は 0 ~ 1。このしきい値を超えるオーバーラップを持つターゲットはマージされます。デフォルトは 0.45 です。

  7. --max-det: 各画像内で検出されたターゲットの最大数。デフォルトは 100 です。

  8. --device: 使用するデバイスを指定します。「cpu」または「cuda」を指定できます。デフォルトは「CPU」です。

  9. --view-img: 検出中に画像ウィンドウを表示します。

  10. --save-txt: テスト結果を保存する txt ファイル。

  11. --save-conf: 検出結果の信頼度を保存します。

  12. --save-crop:検出結果のトリミング画像を保存します。

  13. --half: 推論には半精度浮動小数点数を使用します。

これらのパラメータは、ニーズに応じて調整して、最良の検出結果を得ることができます。スクリプトの実行時に--helpパラメータを使用すると、より多くのパラメータ オプションと説明を表示できます。

実行コマンド予測

python ./detect.py --source ./data/images --weight ./yolov5n6.pt

の結果

(D:\condaenv\yolov5) D:\code1\yolov5-master\yolov5-master>python ./detect.py --source ./data/images --weight ./yolov5n6.pt
detect: weights=['./yolov5n6.pt'], source=./data/images, data=data\coco128.yaml, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=Fal
se, augment=False, visualize=False, update=False, project=runs\detect, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False, vid_stride=1
YOLOv5  2023-5-30 Python-3.8.16 torch-2.0.1+cpu CPU

Fusing layers...
YOLOv5n6 summary: 280 layers, 3239884 parameters, 0 gradients
image 1/2 D:\code1\yolov5-master\yolov5-master\data\images\bus.jpg: 640x512 4 persons, 1 bus, 211.9ms
image 2/2 D:\code1\yolov5-master\yolov5-master\data\images\zidane.jpg: 384x640 3 persons, 1 tie, 152.9ms
Speed: 1.0ms pre-process, 182.4ms inference, 3.0ms NMS per image at shape (1, 3, 640, 640)
Results saved to runs\detect\exp8

runs\detect\exp8 を見つけてディレクトリを開き、分類された画像を表示します。
ここに画像の説明を挿入します
ここに画像の説明を挿入します

トレーニングモデル

公式 Web サイトからの参照: https://docs.ultralytics.com/yolov5/tutorials/train_custom_data/#before-you-start

データセットの準備

データセットyamlを作成する

COCO128 は、COCO train2017 の最初の 128 枚の画像で構成される小さなチュートリアル データセットの例です。これら 128 枚の画像はトレーニングと検証の両方に使用され、トレーニング プロセスがオーバーフィットする可能性があることを確認します。data/coco128.yaml はデータセット構成ファイルで、以下を定義します:
1) データセットのルート ディレクトリ パスとトレーニング/検証/テスト イメージ ディレクトリへの相対パス (またはイメージ パスを含む *.txt ファイル);
2) カテゴリ名辞書。

# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
path: ../datasets/coco128  # dataset root dir
train: images/train2017  # train images (relative to 'path') 128 images
val: images/train2017  # val images (relative to 'path') 128 images
test:  # test images (optional)

# Classes (80 COCO classes)
names:
  0: person
  1: bicycle
  2: car
  ...
  77: teddy bear
  78: hair drier
  79: toothbrush
  # Download script/URL (optional)
download: https://ultralytics.com/assets/coco128.zip

https://ultralytics.com/assets/coco128.zip をダウンロードした後のディレクトリ構造は次のとおりです.
ここに画像の説明を挿入します
ここでは ID カードの表裏を判断するトレーニングに使用します. プロジェクトのルートに新しい idcard ディレクトリを作成しますこのディレクトリは、異なる ID カード情報を区別するためにトレーニングするためにのみ使用され、すべてのデータセットは mul ディレクトリにあります。

# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
path: ./idcard/mul  # dataset root dir
train: images  # train images 
val: images  # val images
test: images   # test images 

# Classes
names:
  0: idcard_z  #表示身份证正面
  1: idcard_f   #表示身份证反面

yolov5 はパスの下に train ディレクトリを自動的に見つけて、イメージ ディレクトリとして画像を追加することに注意してください。
たとえば、実際のトレーニング ディレクトリは ./idcard/mul/train/images です。同じレベルのディレクトリの下に label ディレクトリがあります。注
: 検証セットのディレクトリは ./idcard/mul/val/images
テスト セットのディレクトリは ./idcard/test/val/images
ここに画像の説明を挿入します

一般的に、データ セットをトレーニング セット、検証セット、テスト セットに分割するのが一般的です。たとえば、データを 70% のトレーニング セット、15% の検証セット、15% のテスト セットに分割します。このスケールは通常、小規模なデータ セットに適しています。データ セットが大きい場合は、テスト セットに対する検証セットの比率を増やすことを検討してください。

ラベルの作成

注釈ツール (labelme、labelimg) を使用して画像に注釈を付けた後、ラベルを YOLO 形式にエクスポートします。各画像は *.txt ファイルに対応します (画像内にオブジェクトがない場合、*.txt ファイルは必要ありません)。*.txt ファイルの仕様は次のとおりです。

  • 各オブジェクトは 1 行を占めます
  • 各行の形式は、カテゴリ x 中心点 y 中心点 幅 高さです。
    ボックスの座標は、正規化された xywh 形式 (範囲 0 ~ 1) である必要があります。ボックスの座標がピクセル単位の場合は、x の中心点と幅を画像の幅で割り、y の中心点と高さを画像の高さで割る必要があります。
  • カテゴリ番号はゼロ (インデックスは 0) から始まり、データ セット yaml の名前インデックスに対応します。

注釈には labelimg を使用することをお勧めします。

pip install labelimg -i https://pypi.tuna.tsinghua.edu.cn/simple

現在の環境に切り替えて「labelimg」と入力し、labelimage コマンドを入力して開きます。
ここに画像の説明を挿入します

[開くディレクトリ] を選択してラベルを付ける必要がある画像のディレクトリ (idcard/mul/train/images ディレクトリ) を選択し、[保存ディレクトリ] を変更して idcard/mul/train/labels ディレクトリを選択し、YOLO 形式を選択して画像を 1 つずつ開きます。
画像にマークを付けるには、一般的に次の手順を使用します。

  1. w を押して長方形のボックスを表示し、選択するターゲットを選択します。選択すると、ラベルがポップアップ表示されます。最初に data.yaml にインデックス 0 のラベルを付け、次に 1 のラベルを付ける必要があることに注意してください。後ほどポップアップで表示されます。
    ここに画像の説明を挿入します
  2. 標準が完了したら、ctrl+s で保存します。
  3. キーボードの d キーを押して次の画像に切り替え、すべての画像が完了するまで w を押し続けて四角形をマークします。

ラベル ディレクトリにclasses.txtがあります。その順序がdata.yamlと一致しているかどうかを確認してください。一致していない場合は、classes.txtを調整せずに、data.yamlを調整して一貫性を保ちます。

電車

ここでは注釈付きの画像を 350 枚近く用意しましたが、トレーニング後の認識率は 98% でした。
train.pyを使って実行する

#  --weight是指定初始的权重,可以用它来fine tuning调整训练你自己的模型。
python train.py --batch-size 4 --epochs 10 --data .\idcard\mul\idcard.yaml --weight .\yolov5n6.pt

実行が完了すると、runs\trains\expn\weights\best.pt がトレーニング済みモデルになります。前の detect.py を使用して、このモデルを予測するように指定できます。

python ./detect.py --source .\idcard\mul\test\images --weight .\runs\train\exp3\weights\best.pt

run\detect\expn\ の下の予測イメージを表示します。
ここに画像の説明を挿入します
ここに画像の説明を挿入します
ここに画像の説明を挿入します

モデルアプリケーション

生成された best.pt モデルをアプリケーションで使用する必要があります。

#使用我们本地之前用于训练的yolov5-master,我有把best.pt拷贝到当前目录
model = torch.hub.load('D:\\code1\\yolov5-master\\yolov5-master', 'custom', path='./best.pt', source='local')  # local repo
#print(model)
# 读取图像
img = cv2.imread('../images/zm.jpg')
# 进行预测
results = model(img)
resultLabel=[]
# 解析预测结果
for result in results.xyxy[0]:
    x1, y1, x2, y2, conf, cls = result.tolist()
    if conf > 0.5:
        # 绘制边框和标签
        cv2.rectangle(img, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)
        cv2.putText(img, f"{model.names[int(cls)]} {conf:.2f}", (int(x1), int(y1 - 10)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
        resultLabel.append(model.names[int(cls)])
# 显示图像
print("预测的结果是",resultLabel)
plt.imshow(img)
plt.show()

ここに画像の説明を挿入します

これは公式のオンライン バージョンの呼び出しですが、プログラムは、ultralytics/yolov5 パッケージと yolov5s モデルを自動的にダウンロードしますが、これは非常に時間がかかります。

import torch
# Model
model = torch.hub.load("ultralytics/yolov5", "yolov5s")  # or yolov5n - yolov5x6, custom
# Images
img = "https://ultralytics.com/images/zidane.jpg"  # or file, Path, PIL, OpenCV, numpy, list
# Inference
results = model(img)
# Results
results.print()  # or .show(), .save(), .crop(), .pandas(), etc.

おすすめ

転載: blog.csdn.net/liaomin416100569/article/details/131213359