基于 PaddleDetection实现目标算法识别

发布于:2025-08-20 ⋅ 阅读:(15) ⋅ 点赞:(0)

我使用的是百度开源的飞桨平台提供的开源目标识别算法:PaddleDetection
链接如下:https://github.com/PaddlePaddle/PaddleDetection

今天整理一下算法识别的功能实现,这个东西我研究了整整一周的时间才终于有了点效果。好难。
我查了好多好多资料,都没有一个很完整的教学,包括B站教学也没有,所以我必须要写这篇文章《从0到1实现完成的目标识别》
我将从几个方面非常详细的介绍整个开发部署流程。

  1. 显卡安装部署
  2. python环境搭建
  3. paddlepaddle安装
  4. labelme图像数据标记
  5. labelme数据转换coco数据集
  6. 模型训练
  7. 模型导出
  8. 模型推理预测

这8个非常完整详细的步骤贼详细的介绍我的每一步操作。希望能帮到大家。

下面开干!

这个网盘链接有这篇文章用到的所有。
通过网盘分享的文件:shareFile
链接: https://pan.baidu.com/s/1Iz6sMA2NdhYp4HwQu3fyXw?pwd=cmed 提取码: cmed

1.显卡安装部署

文件自行提取,我的版本是11.2,所以我后面安装的paddlepaddle也是11.2版本
image.png

1、安装cudn的显卡驱动一路一直下一步完成安装就可以了。

2、安装cudnn

首先要解压文件夹,

image.png
然后把这几个文件拷贝到:C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.2
image.png

3、验证cudnn是否安装成功

复制完后,在当前目录下进入 extras -> demo_suite,可以看到有 bandwidthTest.exe 和 deviceQuery.exe
并在路径中输入 cmd 打开命令行窗口
输入 bandwidthTest.exe ,输出下图:
image.png
输入 deviceQuery.exe,输出下图:
image.png
至此, CUDA 与 cudnn 安装成功,可以使用 GPU 加速了

2、python环境搭建

我这里使用Anaconda来搭建一个python的隔离环境,能够更好的跟其他python项目隔离。安装和删除都方便。

1、安装Anaconda

这个安装包也在网盘里,双击 Anaconda3-2024.06-1-Windows-x86_64.exe 安装,一路下一步就可以,就也不放截图了。
最后安装完,再home里会有一个图标如下,就是conda
image.png

2、打开conda

点击打开
image.png

3、创建python环境

输入命令,这里是使用python 3.10 ,(建议不懂的就全跟我保持一致)
ppyoloe :是容器名字,可以修改

conda create --name ppyoloe python=3.10

4、激活环境

ppyoloe : 是刚刚创建的环境名称
输入命令

conda activate ppyoloe

image.png
可以看到前缀已经是ppyoloe了,说明进到我们自己创建的环境了。

3.paddlepaddle安装

首先可以看一下官网:https://www.paddlepaddle.org.cn/install/quick?docurl=/documentation/docs/zh/install/pip/windows-pip.html
image.png

1、安装

我们安装就是复制他的链接。

python -m pip install paddlepaddle-gpu==2.6.2.post112 -i https://www.paddlepaddle.org.cn/packages/stable/cu112/

运行这个命令要等有一会,他要下载东西。等着就好了。

2、验证安装

安装完成后您可以使用 python 进入 python 解释器,输入import paddle ,再输入 paddle.utils.run_check()

如果出现PaddlePaddle is installed successfully!,说明您已成功安装。

4.labelme图像数据标记

1、安装启动labelme

只需要一个命令直接下载安装

pip install labelme

image.png
启动labelme
输入命令

labelme

2、使用labelme

image.png
这就能看到labelme界面了。如下图
image.png
之后点击左上角的打开目录,打开我们自己的图片集就行了,
然后接下来就是标记图形了,按照我下面的操作就完成了一张图片的标记,保存之后就是生成了一个json文件。
image.png
image.png

3、labelme转换coco数据集

首先下载一下官网提供的源码文件:labelme2coco.py

import argparse
import collections
import datetime
import glob
import json
import os
import os.path as osp
import sys
import uuid
import imgviz
import numpy as np
import labelme
from sklearn.model_selection import train_test_split

try:
    import pycocotools.mask
except ImportError:
    print("Please install pycocotools:\n\n    pip install pycocotools\n")
    sys.exit(1)


def to_coco(args, label_files, train):
    # 创建 总标签data
    now = datetime.datetime.now()
    data = dict(
        info=dict(
            description=None,
            url=None,
            version=None,
            year=now.year,
            contributor=None,
            date_created=now.strftime("%Y-%m-%d %H:%M:%S.%f"),
        ),
        licenses=[dict(url=None, id=0, name=None, )],
        images=[
            # license, url, file_name, height, width, date_captured, id
        ],
        type="instances",
        annotations=[
            # segmentation, area, iscrowd, image_id, bbox, category_id, id
        ],
        categories=[
            # supercategory, id, name
        ],
    )

    # 创建一个 {类名 : id} 的字典,并保存到 总标签data 字典中。
    class_name_to_id = {}
    for i, line in enumerate(open(args.labels).readlines()):
        class_id = i - 1  # starts with -1
        class_name = line.strip()  # strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
        if class_id == -1:
            assert class_name == "__ignore__"  # background:0, class1:1, ,,
            continue
        class_name_to_id[class_name] = class_id
        data["categories"].append(
            dict(supercategory=None, id=class_id, name=class_name, )
        )

    if train:
        out_ann_file = osp.join(args.output_dir, "annotations", "instances_train2017.json")
    else:
        out_ann_file = osp.join(args.output_dir, "annotations", "instances_val2017.json")

    for image_id, filename in enumerate(label_files):

        label_file = labelme.LabelFile(filename=filename)
        base = osp.splitext(osp.basename(filename))[0]  # 文件名不带后缀
        if train:
            out_img_file = osp.join(args.output_dir, "train2017", base + ".jpg")
        else:
            out_img_file = osp.join(args.output_dir, "val2017", base + ".jpg")

        print("| ", out_img_file)

        # ************************** 对图片的处理开始 *******************************************
        # 将标签文件对应的图片进行保存到对应的 文件夹。train保存到 train2017/ test保存到 val2017/
        img = labelme.utils.img_data_to_arr(label_file.imageData)  # .json文件中包含图像,用函数提出来
        imgviz.io.imsave(out_img_file, img)  # 将图像保存到输出路径

        # ************************** 对图片的处理结束 *******************************************

        # ************************** 对标签的处理开始 *******************************************
        data["images"].append(
            dict(
                license=0,
                url=None,
                file_name=base + ".jpg",  # 只存图片的文件名
                # file_name=osp.relpath(out_img_file, osp.dirname(out_ann_file)),  # 存标签文件所在目录下找图片的相对路径

                ##   out_img_file : "/coco/train2017/1.jpg"
                ##   out_ann_file : "/coco/annotations/annotations_train2017.json"
                ##   osp.dirname(out_ann_file) : "/coco/annotations"
                ##   file_name : ..\train2017\1.jpg   out_ann_file文件所在目录下 找 out_img_file 的相对路径
                height=img.shape[0],
                width=img.shape[1],
                date_captured=None,
                id=image_id,
            )
        )

        masks = {}  # for area
        segmentations = collections.defaultdict(list)  # for segmentation
        for shape in label_file.shapes:
            points = shape["points"]
            label = shape["label"]
            group_id = shape.get("group_id")
            shape_type = shape.get("shape_type", "polygon")
            mask = labelme.utils.shape_to_mask(
                img.shape[:2], points, shape_type
            )

            if group_id is None:
                group_id = uuid.uuid1()

            instance = (label, group_id)

            if instance in masks:
                masks[instance] = masks[instance] | mask
            else:
                masks[instance] = mask

            if shape_type == "rectangle":
                (x1, y1), (x2, y2) = points
                x1, x2 = sorted([x1, x2])
                y1, y2 = sorted([y1, y2])
                points = [x1, y1, x2, y1, x2, y2, x1, y2]
            else:
                points = np.asarray(points).flatten().tolist()

            segmentations[instance].append(points)
        segmentations = dict(segmentations)

        for instance, mask in masks.items():
            cls_name, group_id = instance
            if cls_name not in class_name_to_id:
                continue
            cls_id = class_name_to_id[cls_name]

            mask = np.asfortranarray(mask.astype(np.uint8))
            mask = pycocotools.mask.encode(mask)
            area = float(pycocotools.mask.area(mask))
            bbox = pycocotools.mask.toBbox(mask).flatten().tolist()

            data["annotations"].append(
                dict(
                    id=len(data["annotations"]),
                    image_id=image_id,
                    category_id=cls_id,
                    segmentation=segmentations[instance],
                    area=area,
                    bbox=bbox,
                    iscrowd=0,
                )
            )
        # ************************** 对标签的处理结束 *******************************************

        # ************************** 可视化的处理开始 *******************************************
        if not args.noviz:
            labels, captions, masks = zip(
                *[
                    (class_name_to_id[cnm], cnm, msk)
                    for (cnm, gid), msk in masks.items()
                    if cnm in class_name_to_id
                ]
            )
            viz = imgviz.instances2rgb(
                image=img,
                labels=labels,
                masks=masks,
                captions=captions,
                font_size=15,
                line_width=2,
            )
            out_viz_file = osp.join(
                args.output_dir, "visualization", base + ".jpg"
            )
            imgviz.io.imsave(out_viz_file, viz)
        # ************************** 可视化的处理结束 *******************************************

    with open(out_ann_file, "w") as f:  # 将每个标签文件汇总成data后,保存总标签data文件
        json.dump(data, f)


# 主程序执行
def main():
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter
    )
    parser.add_argument("--input_dir", help="input annotated directory")
    parser.add_argument("--output_dir", help="output dataset directory")
    parser.add_argument("--labels", help="labels file", required=True)
    parser.add_argument("--noviz", help="no visualization", action="store_true")
    args = parser.parse_args()

    if osp.exists(args.output_dir):
        print("Output directory already exists:", args.output_dir)
        sys.exit(1)
    os.makedirs(args.output_dir)
    print("| Creating dataset dir:", args.output_dir)
    if not args.noviz:
        os.makedirs(osp.join(args.output_dir, "visualization"))

    # 创建保存的文件夹
    if not os.path.exists(osp.join(args.output_dir, "annotations")):
        os.makedirs(osp.join(args.output_dir, "annotations"))
    if not os.path.exists(osp.join(args.output_dir, "train2017")):
        os.makedirs(osp.join(args.output_dir, "train2017"))
    if not os.path.exists(osp.join(args.output_dir, "val2017")):
        os.makedirs(osp.join(args.output_dir, "val2017"))

    # 获取目录下所有的.jpg文件列表
    feature_files = glob.glob(osp.join(args.input_dir, "*.jpg"))
    print('| Image number: ', len(feature_files))

    # 获取目录下所有的joson文件列表
    label_files = glob.glob(osp.join(args.input_dir, "*.json"))
    print('| Json number: ', len(label_files))

    # feature_files:待划分的样本特征集合    label_files:待划分的样本标签集合    test_size:测试集所占比例
    # x_train:划分出的训练集特征      x_test:划分出的测试集特征     y_train:划分出的训练集标签    y_test:划分出的测试集标签
    x_train, x_test, y_train, y_test = train_test_split(feature_files, label_files, test_size=0.3)
    print("| Train number:", len(y_train), '\t Value number:', len(y_test))

    # 把训练集标签转化为COCO的格式,并将标签对应的图片保存到目录 /train2017/
    print("—" * 50)
    print("| Train images:")
    to_coco(args, y_train, train=True)

    # 把测试集标签转化为COCO的格式,并将标签对应的图片保存到目录 /val2017/
    print("—" * 50)
    print("| Test images:")
    to_coco(args, y_test, train=False)


if __name__ == "__main__":
    print("—" * 50)
    main()
    print("—" * 50)

接下来,我们要在ppyoloe的环境中先cd到我们的这个图片路径下,然后执行下面的命令。

python labelme2coco.py --input_dir images --output_dir coco --labels labels.txt

上面的命令中:
images是刚刚生成的json文件的文件夹名,我这里用的是相对路径;
coco 是指定生成的文件夹名,这个不能存在;
labels.txt 是一个标签文件,里面保存刚刚标记的标签名。

labels.txt文件如下:

__ignore__
_background_
chepai

image.png

运行完命令后会有coco文件夹生成
image.png
打开后是这样的目录结构,并且里面都有数据,就说明你成功了。
image.png

5、模型训练

1、下载源码

先在git上下载项目源码,我直接给出gitee的地址,国内gitee比较好访问。

https://gitee.com/paddlepaddle/PaddleDetection.git
这个官网有安装教程可以看一下,我下面直接贴官网关键操作的教程吧。

# 克隆PaddleDetection仓库
cd <path/to/clone/PaddleDetection>
git clone https://github.com/PaddlePaddle/PaddleDetection.git

# 安装其他依赖
cd PaddleDetection
pip install -r requirements.txt

# 编译安装paddledet
python setup.py install

# 安装后确认测试通过:
python ppdet/modeling/tests/test_architectures.py

# 测试通过后会提示如下信息:
.......
----------------------------------------------------------------------
Ran 7 tests in 12.816s
OK

跟上面一样就是成功了。

2、模型训练

image.png

3、配置文件

下面开始重点部分,简单修改一下配置文件。
configs->yolov3->yolov3_r50vd_dcn_270e_coco.yml ,找到这个文件,可以每个版本的这个文件位置不太一样啊,那就搜索一下。
我做一下简单解释:这个yolov3其实就是一个识别算法,configs文件夹下面都是配置文件,其实可以选择任何一种算法,例如还有ppyoloe文件夹,那这个就是它这种算法,选择这个也行,我一开始就用的ppyoloe算法,后来又换的这个算法。这都可以。
image.png
然后我们看一下这个配置文件,首先第一行有个配置,“‘…/datasets/coco_detection.yml’”很重要,我们也只需要改这一个配置文件就行。
接下来找到打开这个文件,image.png
右侧文件中,我注释掉的是原本的内容,下面是我重新写的要训练我们自己模型的配置。

metric: COCO
num_classes: 2     # 这个是我们labelme标记时的一共设置了多少个类别,然后类别+1。(我这里写的2是因为我只有一个类别)

TrainDataset:		# 训练数据集
  name: COCODataSet		
  image_dir: train2017			# 图片目录
  anno_path: annotations\instances_train2017.json		# 数据集目录,是相对于下面的dataset_dir的路径
  dataset_dir: dataset\coco0619\coco		# 这里必须写到 coco这个文件夹路径
  data_fields: ['image', 'gt_bbox', 'gt_class', 'is_crowd']  #  不用改

EvalDataset:						# 评估数据集
  name: COCODataSet
  image_dir: val2017
  anno_path: annotations\instances_val2017.json.
  dataset_dir: dataset\coco0619\coco
  data_fields: ['image', 'gt_bbox', 'gt_class', 'is_crowd']

TestDataset:						# 预测数据集
  name: COCODataSet
  image_dir: train2017
  anno_path: annotations\instances_train2017.json
  dataset_dir: dataset\coco0619\coco
  data_fields: ['image', 'gt_bbox', 'gt_class', 'is_crowd']

ok,到现在,配置文件也修改完了,开始训练。

4、模型训练命令

打开Anaconda,输入下面命令,注意,一定要先cd到咱们的python项目目录下在运行命令,如下图

python tools/train.py -c configs/yolov3/yolov3_r50vd_dcn_270e_coco.yml -o use_gpu=true

image.png
如果几百上千张图片,大概率要训练三四个小时,这个在cmd中有一个打印 eta ,是预计完成时间。
等待。。。。。
等训练完成后,模型会输出到out文件夹。
image.png
可以看到out文件夹下有很多文件,但是其实我这里好像有文件,它直接把模型输入到out了,但是我的配置文件配置的输出路径是这个 yolov3_r50vd_dcn_270e_coco.yml文件里的这个 “weights: output/yolov3_r50vd_dcn_270e_coco/model_final”,按道理应该再创建一个yolov3_r50vd_dcn_270e_coco文件夹再保存model_final,但是但是但是,没有,我也不知道为啥,但是不影响先继续,所以你们再训练完模型后要看一下具体生成的模型保存到了哪里,下一步模型导出的时候要用这个地址。

6.模型导出命令

python tools/export_model.py -c configs/yolov3/yolov3_r50vd_dcn_270e_coco.yml --output_dir=./inference_model  -o weights=output/model_final.pdparams

“-o weights=output/model_final.pdparams” 这个参数就是上面的模型保存位置,我的模型就这这个位置,大家看自己的模型保存到了哪里,然后调整一下参数。
image.png
模型导出很快,我导出到了inference_model 目录下。
image.png
到此,模型导出完成,可以部署到任意服务器进行目标识别了。

7.模型推理预测

python deploy/python/infer.py --model_dir=inference_model/yolov3_r50vd_dcn_270e_coco --image_dir=output/input/ --output_dir=output/results --device=GPU

image_dir参数就是想要识别的图片目录,把要识别的图片放到这个文件夹下,运行命令,识别结果就会输出到output_dir配置的目录下。
image.png
image.png
打开一张看看,
image.png
可以看到i经识别出来了,但是不太精准,这是因为我的模型训练数据太少了,我一共就标注了30张图片,这是远远不够的,我后来在项目中测试,想要准确度高一定要达到每个场景的图片要在100张以上才行,才能够做到识别准确。
但是我们的识别效果已经达到了。

完结,大家有问题可以留言。


网站公告

今日签到

点亮在社区的每一天
去签到