乐趣区

关于python:使用YOLOv8进行工业视觉缺陷检测基于Aidlux完成本地终端部署

1. 引言

  工业视觉缺点检测零碎是一种利用计算机视觉技术,通过剖析生产过程中的图像和视频数据,来检测工业产品是否存在缺点或品质问题的零碎。有幸参加到 Aidlux 夏令营流动中,跟着东哥做了医疗注射器缺点检测零碎我的项目,在这个过程中我播种到了很多之前没有接触到的算法和实际。本我的项目旨在开发一种高效的工业视觉缺点检测零碎,利用 YOLOv8 模型进行指标检测,并基于 AidLux 平台实现本地终端部署推理,以满足工业生产中对产品质量管制的需要。

2. 我的项目背景

  工业生产中,产品质量的保障是至关重要的,而传统的品质检测办法通常须要大量的人力和工夫老本,且容易受主观因素影响。因而,利用计算机视觉技术来自动化进行缺点检测已成为一种重要的解决方案。本我的项目旨在开发一种高效且易于部署的医疗注射器缺点检测零碎,以进步生产效率和产品质量。

3. 我的项目指标

  本我的项目的次要指标是设计、开发和部署一种医疗注射器缺点检测零碎,具体指标如下:

  应用 YOLOv8 模型进行指标检测,检测对象包含胶塞、推杆尾部、针尾部、针嘴、螺口、小胶塞,并且须要额定检测歪嘴状况。

(1)实现本地终端部署推理,以满足实时性要求。

(2)提供可扩展性,反对罕用模型的部署,同时可能灵便应答新模型的更新。

(3)提供简略的部署代码,反对 Python 和 C ++ 多语言开发,实用于更多的工业级产品。

(4)放弃零碎玲珑、装置不便,具备高环境耐受性。

(5)继续保护和迭代零碎,确保产品的品质和性能一直晋升。

   在满足上述多样化需要的思考下,咱们抉择 Aidlux 平台作为我的项目的外围根底。Aidlux 平台不仅简洁,而且功能完善,可能满足咱们这个我的项目的各项要求。此外,咱们还留神到,在应用 Aidlux 进行图片推理预测时,其速度体现也相当迅速,进一步确保了零碎的高效性。通过抉择 Aidlux 平台,咱们可能更好地实现我的项目指标,进步工业视觉缺点检测的效率和准确性。

4. 技术架构

 4.1. YOLOv8 模型抉择和改良

  为了实现目标检测,本项目选择了 YOLOv8 模型,该模型集成了多种性能,包含分类、实例宰割、指标检测、关键点检测等。针对我的项目需要,咱们对 YOLOv8 模型进行了一些改良,其中包含 slimNeck 和 VoVGSCSPC。其中为了进一步改良模型性能,咱们引入了 SIou(Scale-Invariant Intersection over Union)作为一项要害的模型改良。SIou 不仅保留了其余 Iou(Intersection over Union)办法的长处,还退出了角度的计算,从而在多指标检测和缺点检测中带来了以下劣势:

  (1) 模型收敛速度更快:SIou 的引入使得模型更容易学习指标的精确地位和角度,从而减速了训练过程。

  (2) 进步训练的速度:SIou 的角度计算有助于模型更好地了解指标的方向,进而进步了检测速度。

  (3) 进步模型精度:SIou 综合思考了指标的地位和角度信息,因而在缺点检测中可能更精确地辨认缺点,进步了模型的精度。

 通过引入 SIou,咱们进一步提高了 YOLOv8 模型的性能,使其更实用于工业视觉缺点检测工作。SIoU 的综合性能劣势将有助于进步检测准确性,特地是在具备不同角度和方向的指标检测中, 所以很适宜咱们这个医疗注射器缺点检测零碎。

class VoVGSCSP(nn.Module):
    # VoVGSCSP module with GSBottleneck
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):
        super().__init__()
        c_ = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, c_, 1, 1)
        self.cv2 = Conv(c1, c_, 1, 1)
        self.gsb = nn.Sequential(*(GSBottleneck(c_, c_, e=1.0) for _ in range(n)))
        self.res = Conv(c_, c_, 3, 1, act=False)
        self.cv3 = Conv(2 * c_, c2, 1)

    def forward(self, x):
        x1 = self.gsb(self.cv1(x))
        y = self.cv2(x)
        return self.cv3(torch.cat((y, x1), dim=1))

class VoVGSCSPC(VoVGSCSP):
    # cheap VoVGSCSP module with GSBottleneck
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):
        super().__init__(c1, c2)
        c_ = int(c2 * 0.5)  # hidden channels
        self.gsb = GSBottleneckC(c_, c_, 1, 1)

 4.2. 模型导出与部署

  当进行模型转换时,咱们须要将本地基于 YOLOv8 模型训练失去的 ”best.pt” 模型文件转换为 ONNX 文件格式,以便在不同平台上进行部署和应用。这是我的项目中一个重要的步骤,为了使更多人可能更加了解咱们的我的项目,上面咱们对模型转换的代码进行一下解释:

咱们在训练了屡次,屡次调整参数,抉择训练预测辨认成果最好的一次训练后果将其转换为 onnx 模型,所以咱们抉择了当迭代训练次数为 100 轮是训练进去的模型进行转换,因为当迭代次数超过 120 轮之后因为数据集过少,导致训练过于拟合了,反而预测的成果不好。训练后果图片如下:

 在我的项目中,咱们应用了 YOLOv8 模型来进行医疗注射器缺点检测模型。为了将这个模型转换成 ONNX 格局,咱们采纳了以下的转换代码:

    if mode=="onnx" :
        model = YOLO('D:\gongye\yolov8-main\gongye.pt')
        model.export(format="onnx",opset=11,simplify=True)
        # path = model.export(format="onnx",opset=13,half=True,simplify=True)
        # path = model.export(format="onnx",opset=13,half=True,simplify=True)

 上述代码首先创立了一个 YOLOv8 模型实例,并加载了本地训练失去的 ”gongye.pt” 权重文件。而后,通过调用模型的 export 办法,将模型转换为 ONNX 格局。在这个过程中,咱们抉择了 opset=11 的算子版本。这个抉择思考了指标部署平台的广泛支持,稳定性以及社区反对。opset=11 是一个绝对较早的 ONNX 操作集版本,更多的深度学习框架和硬件加速器通常都反对这个版本,这有助于确保模型可能在不同平台上正确运行。

  这个模型转换的步骤是十分要害的,因为它容许咱们将训练好的模型转化为一种通用的格局,以便在不同的环境中进行应用。这为工业视觉缺点检测我的项目提供了跨平台部署的便当,并有助于确保我的项目的胜利施行。

4.3. 部署代码

  在本我的项目中,东哥还提供了一套残缺的模型部署代码,该代码包含了多个关键步骤,如模型加载、图像预处理、推理过程、后处理和后果保留等。这些代码以 Python 为根底,并借助相干的第三方库,旨在反对各种工业利用场景中的模型部署需要。

具体而言,给出的部署代码具备以下特点:

  • 模型加载: 部署代码可能轻松加载 TFLite 和 DLC 模型,确保在不同平台上实现无缝的模型部署。
  • 图像预处理: 部署代码包含图像预处理步骤,以确保输出图像与模型的冀望输出格局统一。这有助于进步模型的准确性和稳定性。
  • 推理过程: 同时咱们的代码实现了高效的推理过程,可能在实时性要求下实现缺点检测工作。这对于工业利用中的疾速响应至关重要。
  • 后处理: 模型输入须要进行后处理,以解析检测后果并执行进一步的操作。咱们的代码包含了这一关键步骤,以确保输入后果的准确性。
  • 后果保留: 最终,咱们的代码可能将检测后果保留到指定地位,以便后续剖析和记录。

 此外,咱们的模型部署零碎十分玲珑,易于迁徙,并具备杰出的环境耐受性。这意味着咱们的零碎能够适应各种工业环境,无论是在车间、生产线还是其余现场场景中,都可能牢靠运行。

通过东哥提供这一残缺的部署解决方案,咱们可能确保了我的项目的可用性和实用性,使其可能满足宽泛的工业视觉缺点检测需要。

5. 部署步骤

 5.1. 模型转换

在胜利将 pt 模型文件导出为 onnx 模型文件后,接下来的关键步骤是应用 Aidlux 平台自带的 AI Model Optimizer 平台将 onnx 模型转换为 TFLite(TensorFlow Lite)和 DLC(Deep Learning Container)模型,以便在不同的平台上进行部署和推理。

 为了转换为 TFLite 模型,咱们抉择了 opset=11 的算子版本。这一抉择的起因是确保了模型在不同硬件平台上的更宽泛兼容性,从而使得咱们的模型可能更灵便地利用于各种部署场景。

 TFLite 模型的导出和转换过程旨在优化模型的推理性能,使其实用于挪动设施和嵌入式零碎等资源无限的环境。这样,咱们能够确保在各种利用场景下都可能高效地执行缺点检测工作。

 此外,咱们还将 onnx 模型转换为 DLC 模型,以便在 Aidlux 平台上进行部署。DLC 模型具备高度优化的部署性能,实用于工业视觉利用,可能在 Aidlux 平台上实现疾速而精确的缺点检测。

 通过这些模型转换步骤,咱们可能确保咱们的模型在不同的部署环境中都可能顺利运行,并且可能高效地实现工业视觉缺点检测工作。这也为咱们提供了更多的灵活性,以适应不同的利用需要。

5.2. 模型代码部署

import aidlite_gpu
import cv2
from cvs import *
import numpy as np
import os
import time




model_path = "/home/gongye/tflite/gongye.tflite"
image_path = "/home/gongye/test"
NUMS_CLASS = 7

confThresh = 0.3
NmsThresh = 0.45


# 输出格局(8400,11)def postProcess(pres, confThresh, NmsThresh):
    boxes_out = []
    scores_out = []
    class_out = []
    for pred in pres:

        pred_class = pred[4:]
        box_ = pred[0:4]
        # pred_class=(pred_class-min(pred_class))/(max(pred_class)-min(pred_class))
        class_index = np.argmax(pred_class)
        if pred_class[class_index] > 0.3:
            # box=np.array([round(pred[2]-0.5*pred[0]),round(pred[3]-0.5*pred[1]),round(pred[0]),round(pred[1])])
            box_ = pred[0:4]  # w,h,xc,yc
            box = np.array([round((pred[2] / 2 - pred[0])), round((pred[3] / 2 - pred[1])), round(pred[0] * 2),
                            round(pred[1] * 2)])
            boxes_out.append(box)
            score = pred_class[class_index]
            scores_out.append(score)
            class_out.append(class_index)

    result_boxes = cv2.dnn.NMSBoxes(boxes_out, np.array(scores_out), confThresh, NmsThresh)
    # detections=[]
    boxes = []
    scores = []
    classes = []
    for result_box in result_boxes:
        index = int(result_box)
        box = boxes_out[index]
        score = scores_out[index]
        class_type = class_out[index]
        boxes.append(box)
        scores.append(score)
        classes.append(class_type)
    return boxes, scores, classes


def draw(img, xscale, yscale, boxes, scores, classes):
    width = img.shape[1]
    w1 = 1620
    w2 = 2350
    w3 = width
    S1 = []
    S2 = []
    S3 = []
    S1_res = [False for i in range(NUMS_CLASS)]
    S2_res = [False for i in range(NUMS_CLASS)]
    S3_res = [False for i in range(NUMS_CLASS)]
    S_res = [S1_res, S2_res, S3_res]

    img_ = img.copy()
    # 遍历所有 box,依照宰割区域将 box 归类
    for i in range(len(boxes)):
        # boxes=[x1,y1,w,h]
        box = boxes[i]
        score = scores[i]
        class_ = int(classes[i])
        # class_text=label[class_]
        # detect=[round(box[0]*xscale),round(box[1]*yscale),round((box[0]+box[2])*xscale),round((box[1]+box[3])*yscale)]
        detect = [round(box[0] * xscale), round(box[1] * yscale), round(box[0] * xscale + (box[2]) * xscale),
                  round(box[1] * yscale + (box[3]) * yscale)]
        text = "{}:{:.2f}".format(label[class_], float(score))
        img_ = cv2.rectangle(img_, (detect[0], detect[1]), (detect[2], detect[3]), (0, 255, 0), 2)
        cv2.putText(img_, text, (detect[0], detect[1] + 10), cv2.FONT_HERSHEY_COMPLEX, 2, (0, 0, 255), 1)

        # 宰割为三块
        if (detect[0] <= w1):
            p1 = []
            p1.append(detect)
            p1.append(class_)
            p1.append(score)
            S1.append(p1)
        elif (w1 < detect[0] <= w2):
            p2 = []
            p2.append(detect)
            p2.append(class_)
            p2.append(score)
            S2.append(p2)
        elif (w2 < detect[0] <= w3):
            p3 = []
            p3.append(detect)
            p3.append(class_)
            p3.append(score)
            S3.append(p3)

            # 判断每个宰割图像中的后果
    index = 0
    for S in [S1, S2, S3]:
        for i in range(len(S)):
            p1 = S[i]
            box_temp = p1[0]
            class_temp = p1[1]
            score_temp = p1[2]
            S_res[index][class_temp] = True
        index += 1

    # 最终宰割输入后果 true or false
    S_out = [False, False, False]
    index_out = 0
    for s_r in S_res:
        c0 = s_r[0]
        c1 = s_r[1]
        c2 = s_r[2]
        c3 = s_r[3]
        c4 = s_r[4]
        c5 = s_r[5]
        c6 = s_r[6]

        if (c0 & c1 & c2 & c3 & (~c4) & (~c5) & (~c6)):
            S_out[index_out] = True
        elif (c0 & c1 & c2 & (~c3) & (~c4) & c5 & (~c6)):
            S_out[index_out] = True
        index_out += 1

    # 打印宰割后果
    cv2.putText(img_, "OK" if S_out[0] == True else "NG", (w1 - 200, 100), cv2.FONT_HERSHEY_COMPLEX, 2, (255, 0, 0), 1)
    cv2.putText(img_, "OK" if S_out[1] == True else "NG", (w2 - 200, 100), cv2.FONT_HERSHEY_COMPLEX, 2, (255, 0, 0), 1)
    cv2.putText(img_, "OK" if S_out[2] == True else "NG", (w3 - 200, 100), cv2.FONT_HERSHEY_COMPLEX, 2, (255, 0, 0), 1)

    return img_


label = ["rubber stopper", "push rod tail", "needle tail", "mouth", "crooked mouth", "screw mouth", "small rubber plug"]

if __name__ == "__main__":

    # 1. 初始化 aidlite 类并创立 aidlite 对象
    aidlite = aidlite_gpu.aidlite()
    print("ok")

    # 2. 加载模型
    value = aidlite.ANNModel(model_path, [640 * 640 * 3 * 4], [8400 * 11 * 4], 4, 0)
    print("gpu:", value)
    # file_names=os.listdir(image_path)
    # root,dirs,files = os.walk(image_path)
    for root, dirs, files in os.walk(image_path):
        num = 0
        for file in files:
            file = os.path.join(root, file)
            frame = cv2.imread(file)
            x_scale = frame.shape[1] / 640
            y_scale = frame.shape[0] / 640

            img = cv2.resize(frame, (640, 640))
            # img_copy=img.co
            img = img / 255.0
            img = np.expand_dims(img, axis=0)
            img = img.astype(dtype=np.float32)
            print(img.shape)

            # 3. 传入模型输出数据
            aidlite.setInput_Float32(img)

            # 4. 执行推理
            start = time.time()

            aidlite.invoke()

            end = time.time()
            timerValue = 1000 * (end - start)
            print("infer time(ms):{0}", timerValue)

            # 5. 获取输入
            pred = aidlite.getOutput_Float32(0)
            # print(pred.shape)
            pred = np.array(pred)
            print(pred.shape)
            pred = np.reshape(pred, (8400, 11))
            # pred=np.reshape(pred,(11,8400)).transpose()
            print(pred.shape)  # shape=(8400,11)

            # 6. 后处理, 解析输入
            boxes, scores, classes = postProcess(pred, confThresh, NmsThresh)

            # 7. 绘制保留图像
            ret_img = draw(frame, x_scale, y_scale, boxes, scores, classes)

            ret_img = ret_img[:, :, ::-1]
            num += 1
            image_file_name = "/home/gongye/result/tfl_res" + str(num) + ".jpg"
            # 8. 保留图片
            cv2.imwrite(image_file_name, ret_img)


  • 无论是 TFLite 还是 DLC 模型,都须要进行后处理来解析模型的输入后果,并提取检测到的物体框、置信度分数和类别信息。
  • TFLite 模型的后处理可能与 DLC 模型有所不同,因为模型输入的格局可能会有差别。在后处理阶段,咱们须要依据模型的输入构造来解析后果。

 尽管基于 TFLite 和 DLC 的 YOLOv8 模型部署流程类似,但它们之间的不同之处在于模型加载和后处理步骤。TFLite 模型通常更容易在不同平台上部署,而 DLC 模型则实用于 Aidlux 平台的特定需要,如须要指定处理器为高通的处理器,因而,在抉择模型格局时,须要依据我的项目的部署要求和指标平台来进行思考。这两种格局都为医疗注射器缺点检测我的项目提供了高效的部署解决方案。

6. 试验和验证

 因为我的手机是天玑芯片,不反对 dlc 模型推理预测,所以这个我的项目中咱们应用 Aidlux 名下的基于高通 855 模组革新的 7T 算力的边缘计算设施来进行推理预测,在应用过程中推理速度也是十分的快,所以很适宜咱们进行边缘终端开发。

 在模型部署实现后,咱们进行了一系列试验和验证,以验证零碎在理论工业生产中的性能和准确性。这些试验包含对 test 文件夹内的照片进行预测,并保留预测后果的照片。

应用 Aidlux 实现本地终端的模型推理预测视频如下:https://www.bilibili.com/video/BV1ZP411b7q6/?vd_source=5d94a2…

7. 论断

 本我的项目胜利设计、开发和部署了一种高效的医疗注射器缺点检测零碎,应用 YOLOv8 模型进行指标检测,并基于 AidLux 平台实现本地终端部署推理。该零碎具备多样性、便捷性、高质量的产品与服务以及老本效益等特点,实用于工业生产中的品质管制和缺点检测需要。

8. 将来瞻望

 在训练过程中,我遇到了中文字体在验证时不能在验证图片上失常标注的问题,通过了将近一星期的解决,将网络上尽可能找到的办法都试了一遍也没有找到解决办法,最初无可奈何只能先应用英文进行代替,我初步判断可能是 YOLOv8 这个模型中存在的一个问题,所以在前期的实际优化中我会陆续改良这个问题,为了进一步晋升零碎性能,将来可思考引入更先进的模型和算法,以及优化模型训练过程。同时,继续保护和更新零碎以满足一直变动的需要,并拓展到更多工业应用领域。

9. 参考文献

[1] YOLOv8 官网文档:ultralytics/ultralytics: NEW – YOLOv8 🚀 in PyTorch > ONNX > OpenVINO > CoreML > TFLite (github.com)

[2] AidLux 平台官方网站: https://www.aidlux.com

[3] TensorFlow Lite 官网文档: https://www.tensorflow.org/lite

[4] DLC 模型部署指南: https://docs.aidlux.com/#/intro/ai/examples/ai-examples-snpe%26more?id=snpedlc%e6%a8%a1%e5%9e%8b%e4%bd%bf%e7%94%a8%e6%a1%88%e4%be%8bhttps://docs.aidlux.com/#/intro/ai/examples/ai-examples-snpe%26more?id=snpedlc%E6%A8%A1%E5%9E%8B%E4%BD%BF%E7%94%A8%E6%A1%88%E4%BE%8B

附录

咱们我的项目代码以齐全开源只 Github 上,有须要的同胞能够自取

部署代码示例:yuanfangshang888/yiliao (github.com)”)

部署模型文件:yiliao/tflite at main · yuanfangshang888/yiliao (github.com)”)

试验数据和后果:yiliao/result at main · yuanfangshang888/yiliao (github.com)”)

退出移动版