基于卷积神经网络和OpenCV的轴套零件内外径测量系统

本文介绍了一个基于卷积神经网络(CNN)和OpenCV的圆柱类零件内外径测量系统,旨在提高测量准确性和自动化水平。系统通过CNN进行图像识别和尺寸测量,利用OpenCV进行图像预处理,实现了高精度和高效的测量。文章详细阐述了系统设计、图像处理、模型训练与验证、核心代码以及系统整合,展示了系统的实际应用前景。
摘要由CSDN通过智能技术生成

1.研究背景与意义

项目参考AAAI Association for the Advancement of Artificial Intelligence

研究背景与意义

近年来,随着工业制造技术的不断发展,圆柱类零件在各个领域中的应用越来越广泛。然而,对于圆柱类零件的内外径测量一直是一个重要且具有挑战性的问题。传统的测量方法往往需要人工参与,不仅耗时耗力,而且容易受到人为因素的影响,导致测量结果的不准确性。因此,开发一种基于卷积神经网络和OpenCV的圆柱类零件内外径测量系统具有重要的研究意义和实际应用价值。

首先,基于卷积神经网络的圆柱类零件内外径测量系统可以提高测量的准确性和稳定性。卷积神经网络是一种强大的图像处理工具,具有良好的特征提取和模式识别能力。通过训练网络模型,可以使系统具备自动识别和测量圆柱类零件内外径的能力,减少人为因素的干扰,提高测量结果的准确性和稳定性。

其次,基于OpenCV的圆柱类零件内外径测量系统可以实现自动化和高效率的测量。OpenCV是一个开源的计算机视觉库,提供了丰富的图像处理和分析功能。通过利用OpenCV中的图像处理算法,可以对圆柱类零件的图像进行预处理、边缘检测和轮廓提取等操作,从而实现对圆柱类零件内外径的自动测量。相比传统的人工测量方法,基于OpenCV的测量系统可以大大提高测量的效率和精度。

此外,基于卷积神经网络和OpenCV的圆柱类零件内外径测量系统还具有广泛的应用前景。圆柱类零件广泛应用于机械制造、汽车工业、航空航天等领域,对其内外径的测量要求非常严格。开发一种准确、稳定、自动化的测量系统,可以提高生产效率,降低成本,提高产品质量。此外,该测量系统还可以应用于零件检测、质量控制、自动化生产线等领域,具有广阔的市场前景和经济效益。

综上所述,基于卷积神经网络和OpenCV的圆柱类零件内外径测量系统具有重要的研究意义和实际应用价值。通过引入卷积神经网络和OpenCV的先进技术,可以提高测量的准确性和稳定性,实现自动化和高效率的测量,满足工业制造中对圆柱类零件内外径测量的需求。同时,该测量系统还具有广泛的应用前景,可以在机械制造、汽车工业、航空航天等领域发挥重要作用,促进产业升级和经济发展。因此,开展基于卷积神经网络和OpenCV的圆柱类零件内外径测量系统的研究具有重要的理论和实践意义。

2.图片演示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.视频演示

基于卷积神经网络和OpenCV的圆柱类零件内外径测量系统_哔哩哔哩_bilibili

4.圆柱类零件尺寸测量系统总体设计

机器视觉尺寸测量系统是指在合适的光照条件下,利用工业相机拍摄空间物体的二维平面图像,将其传送给计算机,计算机利用数字图像处理技术对其进行初步处理,删去无关信息,保留加强有用信息[1],再采用某些拟合方法对保留下来的有用信息进行拟合,接着采用些数学方法对拟合的曲线进行测量,从而实现物体的尺寸测量。图为尺寸测量系统流程图。
在这里插入图片描述

基于机器视觉的圆柱类零件尺寸测量系统也遵循图的流程图,为了实现多个圆柱类零件高度和直径尺寸的同步测量,结合圆柱类零件的特点,设计本系统的硬件组成为:工业相机、镜头、光源、计算机、转动盘、底盘、步进电机,其作用分别为:工业相机完成圆柱类零件二维图像的拍照,光源为工业相机采集图像提供照明,计算机用于处理圆柱类零件图像实现尺寸测量,转动盘推动圆柱类零件转动,底盘用于支撑圆柱类零件,步进电机提供转动盘转动动力。图为圆柱类零件尺寸测量系统硬件示意图。
在这里插入图片描述

基于机器视觉的圆柱类零件尺寸测量原理如下:首先启动步进电机,使步进电机做间歇式转动,由于步进电机与转动盘为固定连接、与底盘为活动连接,此步进电机转动时带动转动盘转动、底盘不动,接着转动盘转动推动圆柱类零件滚动,当转动盘不转动、圆柱类零件静止时,相机拍照采集一张含有多个圆柱类零件的图像,然后步进电机转动,当步进电机再次不转动、圆柱类零件静止时,相机再拍照采集一张含有多个圆柱类零件的图像,如此循环,可采集多张含有多个圆柱类零件的图像,分别对每张含有多个圆柱类零件的图像做图像处理,求取
每张图像中每个圆柱类零件高度和真在尺寸。月I道R过外=张含有多个圆柱类圆柱类零件尺寸求平均值的方法求出测量值,即通过处理三张含有多个零件的图像,求出每张图像中每个圆柱类零件高度和直径尺寸测量值,圆柱类零件高度和直径尺寸测量值相加求平均值,以此值作为最终圆柱类零件高度和直径尺寸测量值,以上就是圆柱类零件尺寸测量原理。

5.核心代码讲解

5.1 export.py

def export_formats():
    # YOLOv5 export formats
    x = [
        ['PyTorch', '-', '.pt', True, True],
        ['TorchScript', 'torchscript', '.torchscript', True, True],
        ['ONNX', 'onnx', '.onnx', True, True],
        ['OpenVINO', 'openvino', '_openvino_model', True, False],
        ['TensorRT', 'engine', '.engine', False, True],
        ['CoreML', 'coreml', '.mlmodel', True, False],
        ['TensorFlow SavedModel', 'saved_model', '_saved_model', True, True],
        ['TensorFlow GraphDef', 'pb', '.pb', True, True],
        ['TensorFlow Lite', 'tflite', '.tflite', True, False],
        ['TensorFlow Edge TPU', 'edgetpu', '_edgetpu.tflite', False, False],
        ['TensorFlow.js', 'tfjs', '_web_model', False, False],
        ['PaddlePaddle', 'paddle', '_paddle_model', True, True],]
    return pd.DataFrame(x, columns=['Format', 'Argument', 'Suffix', 'CPU', 'GPU'])


def try_export(inner_func):
    # YOLOv5 export decorator, i..e @try_export
    inner_args = get_default_args(inner_func)

    def outer_func(*args, **kwargs):
        prefix = inner_args['prefix']
        try:
            with Profile() as dt:
                f, model = inner_func(*args, **kwargs)
            LOGGER.info(f'{prefix} export success ✅ {dt.t:.1f}s, saved as {f} ({file_size(f):.1f} MB)')
            return f, model
        except Exception as e:
            LOGGER.info(f'{prefix} export failure ❌ {dt.t:.1f}s: {e}')
            return None, None

    return outer_func


@try_export
def export_torchscript(model, im, file, optimize, prefix=colorstr('TorchScript:')):
    # YOLOv5 TorchScript model export
    LOGGER.info(f'\n{prefix} starting export with torch {torch.__version__}...')
    f = file.with_suffix('.torchscript')

    ts = torch.jit.trace(model, im, strict=False)
    d = {"shape": im.shape, "stride": int(max(model.stride)), "names": model.names}
    extra_files = {'config.txt': json.dumps(d)}  # torch._C.ExtraFilesMap()
    if optimize:  # https://pytorch.org/tutorials/recipes/mobile_interpreter.html
        optimize_for_mobile(ts)._save_for_lite_interpreter(str(f), _extra_files=extra_files)
    else:
        ts.save(str(f), _extra_files=extra_files)
    return f, None


@try_export
def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr('ONNX:')):
    # YOLOv5 ONNX export
    check_requirements('onnx>=1.12.0')
    import onnx

    LOGGER.info(f'\n{prefix} starting export with onnx {onnx.__version__}...')
    f = file.with_suffix('.onnx')

    output_names = ['output0', 'output1'] if isinstance(model, SegmentationModel) else ['output0']
    if dynamic:
        dynamic = {'images': {0: 'batch', 2: 'height', 3: 'width'}}  # shape(1,3,640,640)
        if isinstance(model, SegmentationModel):
            dynamic['output0'] = {0: 'batch', 1: 'anchors'}  # shape(1,25200,85)
            dynamic['output1'] = {0: 'batch', 2: 'mask_height', 3: 'mask_width'}  # shape(1,32,160,160)
        elif isinstance(model, DetectionModel):
            dynamic['output0'] = {0: 'batch', 1: 'anchors'}  # shape(1,25200,85)

    torch.onnx.export(
        model.cpu() if dynamic else model,  # --dynamic only compatible with cpu
        im.cpu() if dynamic else im,
        f,
        verbose=False,
        opset_version=opset,
        do_constant_folding=True,  # WARNING: DNN inference with torch>=1.12 may require do_constant_folding=False
        input_names=['images'],
        output_names=output_names,
        dynamic_axes=dynamic or None)

    # Checks
    model_onnx = onnx.load(f)  # load onnx model
    onnx.checker.check_model(model_onnx)  # check onnx model

    # Metadata
    d = {'stride': int(max(model.stride)), 'names': model.names}
    for k, v in d.items():
        meta = model_onnx.metadata_props.add()
        meta.key, meta.value = k, str(v)
    onnx.save(model_onnx, f)

    # Simplify
    if simplify:
        try:
            cuda = torch.cuda.is_available()
            check_requirements(('onnxruntime-gpu' if cuda else 'onnxruntime', 'onnx-simplifier>=0.4.1'))
            import onnxsim

            LOGGER.info(f'{prefix} simplifying with onnx-simplifier {onnxsim.__version__}...')
            model_simp, check = onnxsim.simplify(f, check=True)
            assert check, 'assert check failed'
            onnx.save(model_simp, f)
        except Exception as e:
            LOGGER.info(f'{prefix} simplifier failure {e}')
    return f, None

export.py是一个用于将YOLOv5 PyTorch模型导出为其他格式的程序文件。它支持导出的格式包括PyTorch、TorchScript、ONNX、OpenVINO、TensorRT、CoreML、TensorFlow SavedModel、TensorFlow GraphDef、TensorFlow Lite、TensorFlow Edge TPU、TensorFlow.js和PaddlePaddle。该文件还包含了导出所需的依赖库和用法示例。

在文件中定义了一些辅助函数和装饰器,用于导出不同格式的模型。例如,export_torchscript函数用于导出TorchScript模型,export_onnx函数用于导出ONNX模型。这些函数会根据导出结果的成功与否,输出相应的日志信息。

文件还定义了export_formats函数,用于返回支持的导出格式的信息。

整个文件的逻辑是先加载模型和相关参数,然后根据命令行参数选择要导出的格式,并调用相应的导出函数进行导出。导出过程中会输出相应的日志信息,包括导出的结果和所花费的时间。

最后,文件还包含了一些用于导出的辅助函数和装饰器,以及一些用于检查依赖库和环境的函数。

5.2 ui.py


class YOLOv5:
    def __init__(self, weights='./best.pt', data=ROOT / 'data/coco128.yaml', device='', half=False, dnn=False):
        self.weights = weights
        self.data = data
        self.device = device
        self.half = half
        self.dnn = dnn
        self.model, self.stride, self.names, self.pt = self.load_model()

    def load_model(self):
        device = select_device(self.device)
        model = DetectMultiBackend(self.weights, device=device, dnn=self.dnn, data=self.data, fp16=self.half)
        stride, names, pt = model.stride, model.names, model.pt
        return model, stride, names, pt

    def run(self, img, imgsz=(640, 640), conf_thres=0.35, iou_thres=0.15, max_det=1000, classes=None, agnostic_nms=False,
            augment=False, retina_masks=True):
        imgsz = check_img_size(imgsz, s=self.stride)
        self.model.warmup(imgsz=(1 if self.pt else 1, 3, *imgsz))

        cal_detect = []
        device = select_device(self.device)
        names = self.model.module.names if hasattr(self.model, 'module') else self.model.names

        im = letterbox(img, imgsz, self.stride, self.pt)[0]
        im = im.transpose((2, 0, 1))[::-1]
        im = np.ascontiguousarray(im)

        im = torch.from_numpy(im).to(device)
        im = im.half() if self.half else im.float()
        im /= 255
        if len(im.shape) == 3:
            im = im[None]

        pred, proto = self.model(im, augment=augment)[:2]

        pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det, nm=32)
        for i, det in enumerate(pred):
            annotator = Annotator(img, line_width=1, example=str(names))
            if len(det):
                det[:, :4] = scale_boxes(im.shape[2:], det[:, :4], img.shape).round()
                masks = process_mask_native(proto[i], det[:, 6:], det[:, :4], img.shape[:2])
                segments = [
                    scale_segments(img.shape if retina_masks else im.shape[2:], x, img.shape, normalize=True)
                    for x in reversed(masks2segments(masks))]

                id_list = []
                for id in range(len(det[:, :6])):
                    class_name = names[int(det[:, :6][id][5])]
                cal_detect.append([label, xyxy, float(conf), contours])
        return cal_detect

    def detect(self, info1):
        try:
            image = cv2.imread(info1)
            results = self.run(self.model, image, self.stride, self.pt)
            for i in results:
                box = i[1]
                p1, p2 = (int(box[0]), int(box[1])), (int(box[2]), int(box[3]))
                contours = []
                for j in i[3]:
                    contours.append([int(j[0] * image.shape[1]), int(j[1] * image.shape[0])])
                if i[0] == 'D':
                    color = [0, 0, 255]
                    cnt = np.array(contours)
                    (x, y), radius = cv2.minEnclosingCircle(cnt)
                    center = (int(x), int(y))
                    radius = int(radius)
                    cv2.circle(image, center, radius, color, 2)
                    cv2.putText(image, 'R =' + str(radius), (int(box[0]), int(box[1]) - 10),
                                cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2)
                else:
                    color = [255, 0, 0]
                    cnt = np.array(contours)
                    (x, y), radius = cv2.minEnclosingCircle(cnt)
                    center = (int(x), int(y))
                    radius = int(radius)
                    cv2.circle(image, center, radius, color, 2)
                    cv2.putText(image, 'r =' + str(radius), (int(box[0]), int(box[1]) - 10),
                                cv2.FONT_HERSHEY_SIMPLEX, 0.75, color, 2)
            cv2.imwrite('./result/' + info1.split('/')[-1], image)
            ui.showimg(image)
        except:
            cap = cv2.VideoCapture(0)

这是一个使用PyQt5和OpenCV实现的图像识别程序。程序主要包括以下几个部分:

  1. 导入所需的模块和库:包括PyQt5的QtCore、QtWidgets和QtGui模块,以及os、sys、pathlib、numpy等库。

  2. 加载模型:通过load_model函数加载模型,包括模型权重文件路径、数据集配置文件路径、设备、是否使用FP16半精度推断等参数。

  3. 运行模型:通过run函数运行模型进行图像识别,包括输入图像、推断时输入图像的大小、置信度阈值、NMS IOU阈值等参数。

  4. 图像处理和绘制:根据模型的识别结果,对图像进行处理和绘制,包括绘制识别框、绘制最小外接圆等。

  5. 保存和显示结果:将处理后的图像保存到指定路径,并在UI界面上显示。

  6. 异常处理:如果出现异常,程序将尝试使用摄像头进行实时识别。

以上是对程序文件ui.py的概述。

5.3 val.py



def save_one_txt(predn, save_conf, shape, file):
    # Save one txt result
    gn = torch.tensor(shape)[[1, 0, 1, 0]]  # normalization gain whwh
    for *xyxy, conf, cls in predn.tolist():
        xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist()  # normalized xywh
        line = (cls, *xywh, conf) if save_conf else (cls, *xywh)  # label format
        with open(file, 'a') as f:
            f.write(('%g ' * len(line)).rstrip() % line + '\n')


def save_one_json(predn, jdict, path, class_map):
    # Save one JSON result {"image_id": 42, "category_id": 18, "bbox": [258.15, 41.29, 348.26, 243.78], "score": 0.236}
    image_id = int(path.stem) if path.stem.isnumeric() else path.stem
    box = xyxy2xywh(predn[:, :4])  # xywh
    box[:, :2] -= box[:, 2:] / 2  # xy center to top-left corner
    for p, b in zip(predn.tolist(), box.tolist()):
        jdict.append({
            'image_id': image_id,
            'category_id': class_map[int(p[5])],
            'bbox': [round(x, 3) for x in b],
            'score': round(p[4], 5)})


def process_batch(detections, labels, iouv):
    """
    Return correct prediction matrix
    Arguments:
        detections (array[N, 6]), x1, y1, x2, y2, conf, class
        labels (array[M, 5]), class, x1, y1, x2, y2
    Returns:
        correct (array[N, 10]), for 10 IoU levels
    """
    correct = np.zeros((detections.shape[0], iouv.shape[0])).astype(bool)
    iou = box_iou(labels[:, 1:], detections[:, :4])
    correct_class = labels[:, 0:1] == detections[:, 5]
    for i in range(len(iouv)):
        x = torch.where((iou >= iouv[i]) & correct_class)  # IoU > threshold and classes match
        if x[0].shape[0]:
            matches = torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1).cpu().numpy()  # [label, detect, iou]
            if x[0].shape[0] > 1:
                matches = matches[matches[:, 2].argsort()[::-1]]
                matches = matches[np.unique(matches[:, 1], return_index=True)[1]]
                # matches = matches[matches[:, 2].argsort()[::-1]]
                matches = matches[np.unique(matches[:, 0], return_index=True)[1]]
            correct[matches[:, 1].astype(int), i] = True
    return torch.tensor(correct, dtype=torch.bool, device=iouv.device)


@smart_inference_mode()
def run(
        data,
        weights=None,  # model.pt path(s)
        batch_size=32,  # batch size
        imgsz=640,  # inference size (pixels)
        conf_thres=0.001,  # confidence threshold
        iou_thres=0.6,  # NMS IoU threshold
        max_det=300,  # maximum detections per image
        task='val',  # train, val, test, speed or study
        device='',  # cuda device, i.e. 0 or 0,1,2,3 or cpu
        workers=8,  # max dataloader workers (per RANK in DDP mode)
        single_cls=False,  # treat as single-class dataset
        augment=False,  # augmented inference
        verbose=False,  # verbose output
        save_txt=False,  # save results to *.txt
        save_hybrid=False,  # save label+prediction hybrid results to *.txt
        save_conf=False,  # save confidences in --save-txt labels
        save_json=False,  # save a COCO-JSON results file
        project=ROOT / 'runs/val',  # save to project/name
        name='exp',  # save to project/name
        exist_ok=False,  # existing project/name ok, do not increment
        half=True,  # use FP16 half-precision inference
        dnn=False,  # use OpenCV DNN for ONNX inference
        model=None,
        dataloader=None,
        save_dir=Path(''),
        plots=True,
        callbacks=Callbacks(),
        compute_loss=None,
):
    # Initialize/load model and set device
    training = model is not None
    if training:  # called by train.py
       

这是一个用于在检测数据集上验证训练好的YOLOv5检测模型的程序文件。它可以加载训练好的模型并在验证集上进行推理。它还可以计算模型的性能指标,如准确率、召回率和mAP。程序文件可以通过命令行参数来指定模型文件、数据集文件、推理图像大小等。它还支持将结果保存为文本文件或JSON文件。

5.4 classify\predict.py


class YOLOv5Classifier:
    def __init__(self, weights, source, data, imgsz, device, view_img, save_txt, nosave, augment, visualize, update,
                 project, name, exist_ok, half, dnn, vid_stride):
        self.weights = weights
        self.source = source
        self.data = data
        self.imgsz = imgsz
        self.device = device
        self.view_img = view_img
        self.save_txt = save_txt
        self.nosave = nosave
        self.augment = augment
        self.visualize = visualize
        self.update = update
        self.project = project
        self.name = name
        self.exist_ok = exist_ok
        self.half = half
        self.dnn = dnn
        self.vid_stride = vid_stride

    def run(self):
        source = str(self.source)
        save_img = not self.nosave and not source.endswith('.txt')  # save inference images
        is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS)
        is_url = source.lower().startswith(('rtsp://', 'rtmp://', 'http://', 'https://'))
        webcam = source.isnumeric() or source.endswith('.streams') or (is_url and not is_file)
        screenshot = source.lower().startswith('screen')
        if is_url and is_file:
            source = check_file(source)  # download

        # Directories
        save_dir = increment_path(Path(self.project) / self.name, exist_ok=self.exist_ok)  # increment run
        (save_dir / 'labels' if self.save_txt else save_dir).mkdir(parents=True, exist_ok=True)  # make dir

        # Load model
        device = select_device(self.device)
        model = DetectMultiBackend(self.weights, device=device, dnn=self.dnn, data=self.data, fp16=self.half)
        stride, names, pt = model.stride, model.names, model.pt
        imgsz = check_img_size(self.imgsz, s=stride)  # check image size

        # Dataloader
        bs = 1  # batch_size
        if webcam:
            view_img = check_imshow(warn=True)
            dataset = LoadStreams(source, img_size=imgsz, transforms=classify_transforms(imgsz[0]),
                                  vid_stride=self.vid_stride)
            bs = len(dataset)
        elif screenshot:
            dataset = LoadScreenshots(source, img_size=imgsz, stride=stride, auto=pt)
        else:
            dataset = LoadImages(source, img_size=imgsz, transforms=classify_transforms(imgsz[0]),
                                 vid_stride=self.vid_stride)
        vid_path, vid_writer = [None] * bs, [None] * bs

        # Run inference
        model.warmup(imgsz=(1 if pt else bs, 3, *imgsz))  # warmup
        seen, windows, dt = 0, [], (Profile(), Profile(), Profile())
        for path, im, im0s, vid_cap, s in dataset:
            with dt[0]:
                im = torch.Tensor(im).to(model.device)
                im = im.half() if model.fp16 else im.float()  # uint8 to fp16/32
                if len(im.shape) == 3:
                    im = im[None]  # expand for batch dim

            # Inference
            with dt[1]:
                results = model(im)

            # Post-process
            with dt[2]:
                pred = F.softmax(results, dim=1)  # probabilities

            # Process predictions
            for i, prob in enumerate(pred):  # per image
                seen += 1
                if webcam:  # batch_size >= 1
                    p, im0, frame = path[i], im0s[i].copy(), dataset.count
                    s += f'{i}: '
                else:
                    p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0)

                p = Path(p)  # to Path
                save_path = str(save_dir / p.name)  # im.jpg
                txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}')  # im.txt

                s += '%gx%g ' % im.shape[2:]  # print string
                annotator = Annotator(im0, example=str(names), pil=True)

                # Print results
                top5i = prob.argsort(0, descending=True)[:5].tolist()  # top 5 indices
                s += f"{', '.join(f'{names[j]} {prob[j]:.2f}' for j in top5i)}, "

                # Write results
                text = '\n'.join(f'{prob[j]:.2f} {names[j]

这个程序文件是一个用于YOLOv5分类推理的脚本。它可以在图像、视频、目录、URL、摄像头等来源上运行YOLOv5分类推理。

程序的主要功能包括:

  • 加载模型和数据集
  • 运行推理过程
  • 对推理结果进行后处理
  • 显示结果图像
  • 保存结果图像和文本文件

程序提供了多种命令行参数来配置推理过程,包括模型路径、数据源、推理尺寸、设备选择、结果保存等。

该程序文件还包含了一些辅助函数和模块,用于处理图像、视频、模型加载、结果保存等操作。

请注意,该程序文件依赖于YOLOv5的其他模块和库,需要确保这些依赖项已经安装和配置正确。

6.系统整体结构

整体功能和构架概述:
该项目是一个基于卷积神经网络和OpenCV的圆柱类零件内外径测量系统。它包含了多个程序文件,用于模型的训练、验证、推理和导出,以及UI界面的展示和交互。

以下是每个文件的功能概述:

文件路径功能概述
export.py将YOLOv5模型导出为其他格式的工具文件
ui.py实现图像识别的UI界面
val.py在检测数据集上验证训练好的YOLOv5检测模型
classify/predict.py运行YOLOv5分类推理的脚本
classify/train.py训练一个基于YOLOv5的分类器模型
classify/val.py验证训练好的YOLOv5分类模型在一个分类数据集上的表现
models/common.py包含YOLOv5模型的一些通用函数和类
models/experimental.py包含YOLOv5模型的一些实验性函数和类
models/tf.py包含YOLOv5模型的TensorFlow实现
models/yolo.py包含YOLOv5模型的主要实现
models/init.py模型初始化文件
segment/predict.py运行分割模型的推理脚本
segment/train.py训练一个分割模型
segment/val.py在分割数据集上验证训练好的分割模型
utils/activations.py包含一些激活函数的实现
utils/augmentations.py包含一些数据增强的实现
utils/autoanchor.py包含自动锚框生成的实现
utils/autobatch.py包含自动批处理大小调整的实现
utils/callbacks.py包含一些回调函数的实现
utils/dataloaders.py包含数据加载器的实现
utils/downloads.py包含一些下载功能的实现
utils/general.py包含一些通用功能的实现
utils/loss.py包含一些损失函数的实现
utils/metrics.py包含一些评估指标的实现
utils/plots.py包含一些绘图功能的实现
utils/torch_utils.py包含一些PyTorch工具函数的实现
utils/triton.py包含与Triton Inference Server交互的实现
utils/init.py工具函数初始化文件
utils/aws/resume.py包含AWS训练恢复功能的实现
utils/aws/init.pyAWS初始化文件
utils/flask_rest_api/example_request.py包含Flask REST API示例请求的实现
utils/flask_rest_api/restapi.py包含Flask REST API的实现
utils/loggers/init.py日志记录器初始化文件
utils/loggers/clearml/clearml_utils.py包含ClearML日志记录器的实现
utils/loggers/clearml/hpo.py包含ClearML超参数优化的实现
utils/loggers/clearml/init.pyClearML日志记录器初始化文件
utils/loggers/comet/comet_utils.py包含Comet日志记录器的实现
utils/loggers/comet/hpo.py包含Comet超参数优化的实现
utils/loggers/comet/init.pyComet日志记录器初始化文件
utils/loggers/wandb/log_dataset.py包含WandB日志记录器的数据集记录的实现
utils/loggers/wandb/sweep.py包含WandB超参数优化的实现
utils/loggers/wandb/wandb_utils.py包含WandB日志记录器的实现
utils/loggers/wandb/init.pyWandB日志记录器初始化文件
utils/segment/augmentations.py包含分割模型的数据增强实现
utils/segment/dataloaders.py包含分割模型的数据加载器实现
utils/segment/general.py包含分割模型的通用功能实现
utils/segment/loss.py包含分割模型的损失函数实现
utils/segment/metrics.py包含分割模型的评估指标实现
utils/segment/plots.py包含分割模型的绘图功能实现
utils/segment/init.py分割模型初始化文件

以上是每个文件的功能概述。请注意,由于文件数量较多,某些文件的功能可能不在上述列表中,但这些文件通常是为了支持其他文件的功能而存在的。

7.图像的获取与预处理

根据2.3节中所搭建的轴套二维尺寸测量环境,获取待测轴套的彩色图像。为了便于后续的边缘提取工作,需要对轴套的数字图像进行预处理。轴套图像的预处理流程如图所示。
在这里插入图片描述

其中,在轴套的滤波与二值化环节,分别采用不同的算法,设计对比实验,从而得到效果更好或效率更高的算法。

轴套数字图像的灰度化

对于轴套的二维尺寸测量,图像中的色彩信息对测量的结果没有影响。图像的灰度化可以去除不必要的色彩信息,从而简化图像信息,提高轴套的检测效率。
为了使三原色按其分量的大小融合为灰度值,采用加权平均的方式,其中由于人眼睛的敏感程度不同,不同颜色的加权系数也有一定差别。
采用加权平均法对轴套图像进行灰度化处理,其结果如图所示。
在这里插入图片描述

轴套灰度图像的滤波去噪

由于环境的干扰,或者相机镜头等设备的误差,往往会导致图像存在噪声,需要对其进行滤除。常用的图像滤波有以下几种方法:
a)中值滤波。这是一种可以保留图像边缘信息的图像处理方法,具体处理流程如下:采用一个含有中心的窗口对灰度图进行扫描,之后求解窗口中所有像素点灰度值的中位数,并将该中位数替换原有窗口中间的灰度值。其原理示意图如图所示。
在这里插入图片描述
b)均值滤波。这是一种线性滤波算法,处理流程与中值滤波相像,同样使用一个具有中心点的空窗,沿着灰度图像进行扫描,对其中的所有像素点的平均灰度,并替换中心像素原有灰度。由于在求平均值时会对图像的边缘信息进行破坏,因此对于高精度的视觉测量系统,该方法并不适用。
c)高斯滤波。不同于均值滤波,高斯滤波不是简单的求解图像的平均灰度值,而是根据中心点与其他像素点的距离分配权重,加权平均计算中心点新的灰度值。简单来说,与高斯函数的特性相近,距离中心像素越近其权重也越大,为了实现二维图像的高斯卷积滤波,需要将二元的高斯函数离散化,并创建卷积核,之后与中值滤波、均值滤波类似,将卷积得到的值作为处理结果来代替初始的灰度值。其中,二维的高斯函数如下式:
在这里插入图片描述

8.轴套灰度图像的阈值分割

阈值分割可以极大的压缩数据量,进一步简化运算,简化分析和处理步骤。其主要原理为,在数字图像的灰度分布图中找到两个灰度值分布峰值之间的特征灰度T,将背景和目标分开,也就是图像二值化的过程。其中,选取恰当的特征灰度是最重要的部分。迭代法和Otsu法是常用的计算图像特征值的方法。
迭代法对图像进行分割的流程如图所示。
在这里插入图片描述

9.分割的头部神经网络

改进的Yolov5是一个端到端的全卷积实时实例分割模型,该模型在MS COCO数据集上达到了29.8的mAP,并且能够做到33.5fps的实时帧率。并且,在边缘平台上也已经提出了高达133FPS的YolactEdge算法(即通过TensorRT加速+关键帧处理)的边缘计算设备加速算法。具有很强的可拓展性。
改进的Yolov5将实例分割分成了两个并行的子任务,即生成一组原型掩码(prototype masks)和每一个实例的掩码系数(mask coefficients)。之后将原型与掩码系数进行结合生成分割实例(segment mask)。
除此之外,该模型还提出了Fast-NMS来进一步提升推理速度。产生prototype masks和预测mask coefficients: prototype masks 卷积层:在提取空间相关信息上效果显著。mask coefficients全连接层:在获取语义向量上效果显著。
利用矩阵计算对NMS进行加速。
在这里插入图片描述

改进的Yolov5网络结构

由ResNet101+FPN结构组成,之后,一路分支使用“FCN”来生成prototype masks,此时,分割的masks不区分任何实例。之后,第二个分支使用检测头去预测每一个锚框的掩码系数向量,即Mask Coefficents,并利用NMS对锚框进行处理。最后,对于每一个NMS的结果与原掩码结合进行裁剪和阈值过滤,得到最终的预测结果。Feature Backbone此模块主要是利用卷积神经网络做特征提取,然后将提取到的特征输入到特征金字塔网络中。

10.训练结果可视化分析

评价指标

Epochs:数据集记录多个训练时期的值,指示学习算法在整个训练数据集中工作的次数。

训练损失:包括train/box_loss、、、和。损失对于评估模型的性能至关重要,值越低表明模型性能越好。每种类型的损失都有特定的作用:train/seg_losstrain/obj_losstrain/cls_loss

Box Loss:与边界框预测的准确性有关。
Segmentation Loss:衡量图像分割的性能。
Object Loss:评估模型检测物体的能力。
Classification Loss:反映对对象进行分类的准确性。
验证损失:与训练损失类似,这些 ( val/box_loss, val/seg_loss, val/obj_loss, val/cls_loss) 是在训练中未使用的一组单独数据上计算的,用于评估模型的泛化能力。

指标:包括 和 类别在不同 IoU(并集交集)阈值下的精度、召回率和平均精度 (mAP B) M。精度和召回率值越高,表明模型性能越好,mAP 提供了对象检测质量的综合衡量标准。

学习率:数据集记录x/lr0、x/lr1、 和x/lr2,表示训练期间使用的不同学习率值。学习率是训练神经网络的关键超参数。

训练结果可视化

为了进行深入分析,我们将可视化这些数据点,以了解各个时期的趋势和表现。这包括绘制训练和验证损失、精度、召回率和 mAP 分数,以及观察学习率调整。让我们从可视化开始,然后进行详细分析。​

import matplotlib.pyplot as plt

# Preparing data for plots
epochs = data['epoch']
training_losses = data[['train/box_loss', 'train/seg_loss', 'train/obj_loss', 'train/cls_loss']]
validation_losses = data[['val/box_loss', 'val/seg_loss', 'val/obj_loss', 'val/cls_loss']]
metrics_B = data[['metrics/precision(B)', 'metrics/recall(B)', 'metrics/mAP_0.5(B)', 'metrics/mAP_0.5:0.95(B)']]
metrics_M = data[['metrics/precision(M)', 'metrics/recall(M)', 'metrics/mAP_0.5(M)', 'metrics/mAP_0.5:0.95(M)']]
learning_rates = data[['x/lr0', 'x/lr1', 'x/lr2']]

# Plot settings
plt.figure(figsize=(18, 12))

# Plotting Training Losses
plt.subplot(2, 3, 1)
plt.plot(epochs, training_losses, linewidth=2)
plt.title('Training Losses')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend(training_losses.columns)

# Plotting Validation Losses
plt.subplot(2, 3, 2)
plt.plot(epochs, validation_losses, linewidth=2)
plt.title('Validation Losses')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend(validation_losses.columns)

# Plotting Metrics for B
plt.subplot(2, 3, 3)
plt.plot(epochs, metrics_B, linewidth=2)
plt.title('Metrics for B')
plt.xlabel('Epoch')
plt.ylabel('Metric Value')
plt.legend(metrics_B.columns)

# Plotting Metrics for M
plt.subplot(2, 3, 4)
plt.plot(epochs, metrics_M, linewidth=2)
plt.title('Metrics for M')
plt.xlabel('Epoch')
plt.ylabel('Metric Value')
plt.legend(metrics_M.columns)

# Plotting Learning Rates
plt.subplot(2, 3, 5)
plt.plot(epochs, learning_rates, linewidth=2)
plt.title('Learning Rates')
plt.xlabel('Epoch')
plt.ylabel('Learning Rate')
plt.legend(learning_rates.columns)

# Adjusting layout
plt.tight_layout()

# Show the plots
plt.show()

在这里插入图片描述

可视化结果分析

可视化提供了实验结果的全面概述。让我们详细分析这些结果:

训练损失:该图显示了训练阶段不同类型损失(框、分割、对象和分类)的进展。一般来说,损失值的稳步下降表明模型正在有效地学习。损失值的任何波动或增加都可能表明学习过程中的过度拟合或不稳定。

验证损失:与训练损失类似,这些损失是在单独的数据集上评估的。理想情况下,验证损失也应该随着时间的推移而减少,反映训练损失。训练和验证损失之间的显着差异可能表明过度拟合。

B 和 M 类别的指标:指标包括两个类别(表示为 B 和 M)的精度、召回率和平均精度 (mAP)。

精度衡量积极预测的准确性。
召回率评估模型检测所有相关实例的能力。
mAP提供对象检测的总体有效性得分。较高的 mAP 值,特别是 mAP_0.5:0.95,表明模型更稳健。
学习率:学习率图显示了学习率在历元内的调整。学习率是训练神经网络的关键因素,影响学习的速度和质量。

主要观察和分析:
损失趋势:寻找趋势,例如持续下降、稳定或峰值。平稳状态可能表明需要调整学习率,而峰值可能表明数据问题或模型不稳定。
性能指标:评估精确度、召回率和 mAP 是否随着时间的推移而提高。精确率和召回率之间的平衡对于全面的模型至关重要。
学习率调整:观察学习率的变化如何与损失和指标性能相关。理想情况下,学习率的调整应有助于稳定和改进模型的学习过程。
为了进一步分析这些结果,可以对指标进行统计分析,将它们与基线或预期值进行比较,或者检查模型表现不佳或表现优异的个别情况。此外,考虑到圆柱形零件测量系统的背景,有必要了解这些指标如何转化为现实世界的测量精度和可靠性。

对于详细的书面分析,我将深入研究每个方面,讨论趋势、观察到的行为的可能原因,以及为了更好的模型性能而进行的潜在改进或调整。分析的最后将对模型的实际应用准备情况进行评估,并为未来的实验或改进提出建议。

样本预测:模型对一批数据进行预测的可视化示例可以定性地了解模型的执行情况。
在这里插入图片描述

其他结果分析

混淆矩阵:混淆矩阵是评估分类模型准确性的关键工具。它显示真实分类与预测分类,并帮助确定模型混淆不同类别的频率。
在这里插入图片描述

散点图和相关图:这些可视化可以显示不同预测变量之间的关系,例如检测到的零件的位置和大小。它们还可以显示不同类别的预测的密度和分布。
在这里插入图片描述

精确率-召回率曲线:这些曲线展示了不同置信度阈值下精确率和召回率之间的权衡。它们对于了解模型在不同确定性级别的预测中的表现非常有用。
在这里插入图片描述

F1 分数曲线:F1 分数是精确率和召回率的调和平均值,是测试准确性的衡量标准。该曲线显示不同置信度阈值的 F1 分数。
在这里插入图片描述

11.系统整合

下图完整源码&数据集&环境部署视频教程&自定义UI界面
在这里插入图片描述

参考博客《基于卷积神经网络和OpenCV的轴套零件内外径测量系统》

12.参考文献


[1]毕超,盛波,郑学著,等.叶型孔视觉测量系统的搭建与实现[J].航天制造技术.2021,(2).DOI:10.3969/j.issn.1674-5108.2021.02.002 .

[2]张宗华,刘巍,刘国栋,等.三维视觉测量技术及应用进展[J].中国图象图形学报.2021,(6).

[3]曹诚诚.基于机器视觉的工业机器人定位系统研究[J].科技与创新.2020,(14).DOI:10.15913/j.cnki.kjycx.2020.14.025 .

[4]黄涛.基于机器视觉的产品检测技术研究[J].信息记录材料.2020,(7).

[5]顾高霏,赵军,孔明,等.基于光场相机层析法的颗粒三维位置测量[J].光子学报.2020,(8).DOI:10.3788/gzxb20204908.0812002 .

[6]刘佳斌,刘今越,任东城,等.基于面结构光投影法的刀具轮廓尺寸非接触测量技术研究[J].机床与液压.2018,(1).DOI:10.3969/j.issn.1001-3881.2018.01.016 .

[7]杨晓京,王思琪.基于显微机器视觉的微纳米级构件的精密检测[J].计算机工程与应用.2017,(5).DOI:10.3778/j.issn.1002-8331.1507-0158 .

[8]刘斌,沈康,魏兆超,等.基于线结构光视觉技术的微小直径高精度测量系统[J].仪器仪表学报.2014,(z2).

[9]姜宏志,赵慧洁,李旭东,等.用于强反射表面形貌测量的投影栅相位法[J].光学精密工程.2010,(9).DOI:10.3788/OPE.20101809.2002 .

[10]马睿,曾理,卢艳平.改进的基于Facet模型的亚像素边缘检测[J].应用基础与工程科学学报.2009,(2).DOI:10.3969/j.issn.1005-0930.2009.02.016 .

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值