HSG金属表面缺陷检测

news2024/11/16 0:23:30

HSG金属表面缺陷检测

  • 1. 项目背景
    • 1.1 项目简述
    • 1.2 项目目标
  • 2. 解决方案
  • 3. 数据集
    • 3.1 收集各种缺陷的图片
    • 3.2 利用有限图片创造更多可能
    • 3.3 分割图像
    • 3.4 打标签
  • 4. 部分代码
    • 4.1 数据集划分
    • 4.2图像分割
    • 4.3 训练模型
    • 4.4 预测
  • 5. 预测结果

1. 项目背景

1.1 项目简述

  • iPad HSG 的材质是带有磨砂质感的金属框,在生产或搬运过程中,会产生一些缺陷。比如:长度不等的黑线,面积不定的亮印,亮度不同的吐酸酸蚀,以及HSG在搬运过程中经常出现的刮伤或磕伤。
  • 常见的4种缺陷类型:
    • 划伤
      在这里插入图片描述

    • 吐酸
      在这里插入图片描述

    • 黑线
      在这里插入图片描述

    • 亮印
      在这里插入图片描述

1.2 项目目标

  • 使用多组相机对HSG进行拍照取像,通过对图像的分析,完成以上四种缺陷的检测。
  • 技术要求:明显缺陷要求 100% 检出,不明显缺陷检出率超过 95%。

2. 解决方案

  • 该项目遇到的问题属于检测类问题,最终选择使用 YOLOv8 Detect 模块完成。

3. 数据集

3.1 收集各种缺陷的图片

  • 自动化领域的缺陷样品收集起来并不容易,因为带有缺陷的样品往往当天或者第二天就会被返工或做报废处理,工程师到达现场时只能拿到当天的一小部分缺陷样品。在打样阶段产品本来就少,这给我们的工作带来不少麻烦。

3.2 利用有限图片创造更多可能

  • 能拿到的样品少,就只能在实验室制造更多可能了。
  • 改变拍摄的位置和角度,光源亮度,拍摄更多的图片。
  • 也可以通过图像处理(旋转、翻转等)生成更多的图片。

3.3 分割图像

  • 项目使用的是 1200W 彩色相机,缺陷相较于整张图像来说比较小,所以采取了图像分割的方法。将原有的大图像分割为小图,再进行标注。
  • 这里采用 5 × 4 分割。

3.4 打标签

  • 标注工具使用的是 lableImg
  • calsses
    • acid
    • bright
    • black
    • scratch

4. 部分代码

4.1 数据集划分

import cv2
import matplotlib.pyplot as plt
import numpy as np
import random
from tqdm import tqdm
import shutil
import os

def CollateDataset(image_dir,label_dir):
    """
    功能:数据集划分(训练集、验证集、测试集)
    :param image_dir: 图片路径
    :param label_dir: 标签路径
    :return:
    """
    # 创建一个空列表来存储有效图片的路径
    valid_images = []
    # 创建一个空列表来存储有效 label 的路径
    valid_labels = []
    # 遍历 images 文件夹下的所有图片
    for image_name in os.listdir(image_dir):
        # 获取图片的完整路径
        image_path = os.path.join(image_dir, image_name)
        # 获取图片文件的扩展名
        ext = os.path.splitext(image_name)[-1]
        # 根据扩展名替换成对应的 label 文件名
        label_name = image_name.replace(ext, ".txt")
        # 获取对应 label 的完整路径
        label_path = os.path.join(label_dir, label_name)
        # 判断 label 是否存在
        if not os.path.exists(label_path):
            # # 删除图片
            # os.remove(image_path)
            print("there is no:", label_path)
        else:
            # 将图片路径添加到列表中
            valid_images.append(image_path)
            # 将 label 路径添加到列表中
            valid_labels.append(label_path)
    # 遍历每个有效图片路径
    for i in tqdm(range(len(valid_images))):
        image_path = valid_images[i]
        label_path = valid_labels[i]
        # 随机生成一个概率
        r = random.random()
        # 判断图片应该移动到哪个文件夹
        # train:valid:test = 8:2:0
        if r < 0.0:
            # 移动到 test 文件夹
            destination = "./dataset/test"
        elif r < 0.2:
            # 移动到 valid 文件夹
            destination = "./dataset/valid"
        else:
            # 移动到 train 文件夹
            destination = "./dataset/train"
        # 创建目标文件夹中 images 和 labels 子文件夹
        os.makedirs(os.path.join(destination, "images"), exist_ok=True)
        os.makedirs(os.path.join(destination, "labels"), exist_ok=True)
        # 生成目标文件夹中图片的新路径
        image_destination_path = os.path.join(destination, "images", os.path.basename(image_path))
        # 移动图片到目标文件夹
        shutil.copy(image_path, image_destination_path)
        # 生成目标文件夹中 label 的新路径
        label_destination_path = os.path.join(destination, "labels", os.path.basename(label_path))
        # 移动 label 到目标文件夹
        shutil.copy(label_path, label_destination_path)

if __name__ == '__main__':
    CollateDataset("./images","./labels")

4.2图像分割

import cv2
import os
import pathlib

source_path = "D:/images"
target_path = "D:/images_split"

def mkdir(path):
    path = path.strip()
    path = path.rstrip("\\")

    isExists = os.path.exists(path)
    if not isExists:
        os.makedirs(path)
        print(path + ' 创建成功')
        return True
    else:
        print(path + ' 目录已存在')
        return False


def split_img2(img_file):
    img = cv2.imread(img_file)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    img_h = img.shape[0]  # 高度
    img_w = img.shape[1]  # 宽度
    # h1_half = int(img_h / 2)
    # w1_half = int(img_w / 2)

    h1_half = img_h // 2
    w1_half = img_w // 2

    img_name = os.path.basename(img_file)
    for i in range(4):
        img1 = img[int(i / 2) * h1_half: h1_half * (int(i / 2) + 1), int(i % 2) * w1_half: (int(i % 2) + 1) * w1_half]

        img1_path = os.path.join(target_path, f"{img_name[:-4]}_{i}.jpg")
        print("spilt img:", img1_path)
        cv2.imwrite(img1_path, img1)

def split_img(img_file,wp = 2, hp = 2):
    img = cv2.imread(img_file)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    img_h = img.shape[0]  # 高度
    img_w = img.shape[1]  # 宽度
    # h1_half = int(img_h / 2)
    # w1_half = int(img_w / 2)

    h1_half = img_h // hp
    w1_half = img_w // wp
    wh_sum = wp * hp

    print(wh_sum)

    img_name = os.path.basename(img_file)
    for i in range(wh_sum):
        img1 = img[int(i / wp) * h1_half: h1_half * (int(i / wp) + 1), int(i % hp) * w1_half: (int(i % hp) + 1) * w1_half]

        img1_path = os.path.join(target_path, f"{img_name[:-wh_sum]}_{i}.jpg")
        print("spilt img:", img1_path)
        cv2.imwrite(img1_path, img1)

if __name__ == '__main__':
    mkdir(target_path)
    for file in pathlib.Path(source_path).glob('**/*'):
        str = pathlib.Path(source_path)
        print(str)
        split_img(os.path.join(source_path, file),5,4)

4.3 训练模型

def train():
    """
        训练模型
    :return:
    """
    # model = YOLO("./ultralytics/cfg/models/v8/mtyolov8.yaml")
    model = YOLO("./yolov8n.pt")
    model.train(data="./ultralytics/cfg/datasets/coco8_HSG.yaml", epochs=400)
    result = model.val()

4.4 预测

import random
import time
from tqdm import tqdm
from ultralytics import YOLO
import torch
import cv2
import matplotlib.pyplot as plt
import os
import numpy as np
os.environ['KMP_DUPLICATE_LIB_OK'] = 'True'

def load_train_model():
    """
        加载训练好的模型
    :return:
    """
    global model
    model = YOLO("./best.pt")

def load_image(image_path):
    """
        加载图像
    :return: 图像
    """
    print(image_path)
    if not os.path.exists(image_path):
        return
    else:
        return cv2.imread(image_path)

def save_image(image):
    """
        保存图像
    :return:
    """
    # 创建目标文件夹中 images 和 labels 子文件夹
    os.makedirs(os.path.join("./", "predict_result"), exist_ok=True)
    # 移动图片到目标文件夹
    image_name = time.strftime('%Y-%m-%d-%H-%M-%S',time.localtime(time.time())) + ".jpg"
    image_path = "./predict_result/" + image_name
    cv2.imwrite(image_path, image)

def get_images_path(image_path):
    """
        获得文件加下所有图片的路径
    :return: 列表
    """
    # 创建一个空列表来存储有效图片的路径
    images_path = []
    # 遍历 images 文件夹下的所有图片
    for image_name in os.listdir(image_path):
        # 获取图片的完整路径
        path = os.path.join(image_path, image_name)
        # 将图片路径添加到列表中
        images_path.append(path)
    return images_path

def load_image_random(images_path):
    """
    功能:在文件夹中随机加载一张图像
    :param image_path: 文件夹路径
    :return:
    """
    pathname = random.choices(images_path)[0]
    image = load_image(pathname)
    return image

def load_image_order(images_path):
    """
    功能:在文件夹中按照先后顺序加载图片
    :param image_path: 文件夹路径
    :return:
    """
    for pathname in images_path:
        image = load_image(pathname)
        yield image

def train():
    """
        训练模型
    :return:
    """
    # model = YOLO("./ultralytics/cfg/models/v8/mtyolov8.yaml")
    model = YOLO("./yolov8n.pt")
    model.train(data="./ultralytics/cfg/datasets/coco8_HSG.yaml", epochs=400)
    result = model.val()

def predict(pre_image):
    # 定义分割参数
    segment_width = 819
    segment_height = 750
    stride_w = 820  # w步长
    stride_h = 750  # h步长
    color_map = {
        'bright': (255, 0, 0),
        'acid': (0, 255, 0)
        # 其他类别的颜色可以根据需要添加
    }

    for y in range(0, pre_image.shape[0], stride_h):
        for x in range(0, pre_image.shape[1], stride_w):
            # 提取分割区域
            segment = pre_image[y:y + segment_height, x:x + segment_width]
            # 对分割区域进行目标检测
            results = model.predict(segment,conf=0.3)
            for result in results:
                boxes = result.boxes
                names = result.names
                num = len(boxes.cls.cpu().numpy().astype(int))
                if num >= 1:
                    for i in range(num):
                        xyxy = boxes.xyxy.cpu().numpy().astype(int)[i]
                        cls = boxes.cls.cpu().numpy().astype(int)[i]
                        conf = boxes.conf.cpu().numpy()[i]
                        color = color_map.get(names.get(cls), (0, 255, 0))  # 默认绿色
                        # 将RGB格式的颜色转换为BGR格式
                        color = (color[2], color[1], color[0])
                        offset = 15
                        x1 = xyxy[0] + x - offset
                        y1 = xyxy[1] + y - offset
                        x2 = xyxy[2] + x + offset
                        y2 = xyxy[3] + y + offset
                        cv2.rectangle(pre_image, (x1, y1), (x2, y2), color, 4)
                        cv2.putText(pre_image, f"{names.get(cls)} {conf:.2f}", (x1, y1 - 15),
                                    cv2.FONT_HERSHEY_SIMPLEX, 1.5, color, 4)
    #cv2.imwrite("./result1.jpg",pre_image)
    #plt.title('Pre')
    #plt.imshow(cv2.cvtColor(pre_image, cv2.COLOR_BGR2RGB))
    #plt.show()
    return pre_image

5. 预测结果

  • 测试集中明显缺陷已经可以检出,不明显的缺陷还需要继续优化。随着项目的推进,会有更多的缺陷图像补充进来,这样会极大提高模型的检测精度。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1910627.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【运维】磁盘满了怎么办?如何快速找到占用空间的文件和腾出空间

机器用久了&#xff0c;很容易生成很多临时或者无用的文件&#xff0c;占用大量空间造成磁盘不够用。尤其是服务器&#xff0c;当磁盘不够用时&#xff0c;系统会出现莫名其妙的问题&#xff0c;数据库可能会造成数据损坏。此时快速定位可以删除的大文件并及时释放空间&#xf…

Linux内核网络性能问题的追踪(工具篇)

在现代计算环境中&#xff0c;网络性能对于系统的整体性能至关重要。网络瓶颈不仅会影响数据传输速度&#xff0c;还会影响应用程序的响应时间&#xff0c;最终影响用户体验。为了有效地解决网络性能问题&#xff0c;了解和使用各种追踪工具至关重要。另外一方面&#xff0c;造…

SQLServer用户们,你们摊上大事了!

最近一段时间&#xff0c;我们经常会收到了许多用户的咨询&#xff0c;问我们何时能纳管SQLServer&#xff1f;耐不住小伙伴们的猛烈催促及热切期待&#xff0c;本不想纳管SQLServer的研发团队也抓紧将这项需求提上日程。并在DBdoctor v3.2.2版本中成功实现了对SQLServer的纳管…

VS2019运行报错 应输入预处理器指令

根据错误提示&#xff0c;找到对应行&#xff0c;然后删除多余的#字符即可

小程序渗透测试的两种方法——burpsuite、yakit

首先呢主要是配置proxifier&#xff0c;找到小程序的流量&#xff0c;然后使用burpsuite或者yakit去抓包。 一、使用burpsuiteproxifier的抓包测试 1、先配置proxifier&#xff0c;开启http流量转发 勾选确定 2、配置burp对应代理端口&#xff0c;选择profile&#xff0c;点…

软件工具网站推荐

1.菜鸟工具 菜鸟工具 - 不止于工具菜鸟工具&#xff0c;为开发设计人员提供在线工具&#xff0c;网址导航&#xff0c;提供在线PHP、Python、 CSS、JS 调试&#xff0c;中文简繁体转换&#xff0c;进制转换等工具。致力于打造国内专业WEB开发工具&#xff0c;集成开发环境&…

手把手和你一起从0搭建一个vite+Vue3+element-plus的后台管理系统!

首选需要node环境。你可以参考&#xff1a;如何创建一个vue的新项目&#xff0c;用命令行的方式创建.下载node.js-CSDN博客 所需要的内容官网&#xff1a; https://vitejs.dev/ 安装 | Element Plus Vue Router | Vue.js 的官方路由 axios中文网|axios API 中文文档 | axio…

在国内允许交易伦敦金吗?有没有好的伦敦金交易策略

伦敦金&#xff0c;作为全球金融市场上的一种重要投资品种&#xff0c;以其独特的交易机制和价值稳定性吸引了无数投资者的目光。然而&#xff0c;对于国内投资者而言&#xff0c;是否可以合法参与伦敦金的交易&#xff0c;以及如何制定有效的交易策略&#xff0c;是他们普遍关…

主动算法交易!减持回购/套利/大单拆分/篮子交易/预埋单神器工具!

主动算法致力于服务机构投资者&#xff0c;为其提供以成交为目的的自动化交易执行。 在有限容量内&#xff0c;充分追求客户个性化需求&#xff0c;保证执行效率、降低冲击成本、减少人力成本、保护交易意图、 捕捉交易机会、 符合监管要求和获取交易环节的ALpha收益。 能够帮…

初阶C++(二)

初阶C&#xff08;二&#xff09; 1. 重载函数&#xff08;一&#xff09;对于重载函数的理解&#xff08;二&#xff09;重载函数分类2.引用&#xff08;一&#xff09; 引⽤的概念和定义&#xff08;二&#xff09;引用的使用&#xff08;三&#xff09;const引用 1. 重载函数…

EI期刊目录为何还没更新?预警、On Hold、镇压多重bug,神仙难救Top能逃此劫吗?

本周投稿推荐 SCI • 能源科学类&#xff0c;1.5-2.0&#xff08;25天来稿即录&#xff09; • CCF推荐&#xff0c;4.5-5.0&#xff08;2天见刊&#xff09; • 生物医学制药类&#xff08;2天逢投必中&#xff09; EI • 各领域沾边均可&#xff08;2天录用&#xff09…

*AI大模型热潮下的冷静思考:谁在守护模型安全?

随着2023年4月的到来&#xff0c;AI大模型领域仿佛迎来了春天&#xff0c;各类产品如雨后春笋般涌现&#xff0c;成为科技界乃至社会各界的热议焦点。从阿里巴巴的“通义千问”到华为的“盘古大模型”&#xff0c;再到商汤科技的“商量SenseChat”&#xff0c;以及即将亮相的“…

一文清晰了解CSS

一、基本概念 1.定义 CSS&#xff08;Cascading Style Sheets&#xff0c;层叠样式表&#xff09;&#xff0c;前面说了CSS是一种用于描述网页内容外观和样式的标记语言。 具体地&#xff0c;它通过选择器将样式规则应用到HTML元素上&#xff0c;控制网页的布局、颜色、字体等…

linux中top、htop监控工具命令详解

文章目录 top 命令概述如何使用 top 命令top 命令输出解释各部分解释系统信息任务信息CPU 使用信息内存使用信息进程信息 top 命令的常用交互操作top 命令的常用选项查看每个CPU使用情况示例说明默认视图按下 1 键后的视图 如何使用 htop和top之间比较用户界面和可用性功能和特…

服务器信息获取工具

功能介绍 SSH连接到远程服务器&#xff1a; 用户可以输入目标服务器的IP地址、用户名、密码以及SSH端口&#xff08;默认22&#xff09;。 工具会尝试连接到远程服务器&#xff0c;并在连接失败时显示错误信息。 运行命令并返回输出&#xff1a; 工具可以在远程服务器上运…

游戏AI的创造思路-技术基础-决策树(1)

决策树&#xff0c;是每个游戏人必须要掌握的游戏AI构建技术&#xff0c;难度小&#xff0c;速度快&#xff0c;结果直观&#xff0c;本篇将对决策树进行小小解读~~~~ 目录 1. 定义 2. 发展历史 3. 决策树的算法公式和函数 3.1. 信息增益&#xff08;Information Gain&…

枚举对象序列化规则(将Java枚举转换为JSON字符串的步骤)

文章目录 引言I 案例分析1.1 接口签名计算1.2 请求对象1.3 枚举对象序列化II 在JSON中以枚举的code值来表示枚举的实现方式2.1 自定义toString方法返回code引言 在Java中,每个对象都有一个toString方法,用于返回该对象的字符串表示。默认情况下,Enum类的toString方法返回的…

dbeaver连接postgresql报错��������: �û� “root“ Password ��֤ʧ��

文章目录 问题描述解决办法 问题描述 新安装完成的postgresql通过dbeaver连接访问报错&#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;: &#xfffd;&#xfffd; “root” Password &#xfffd;&#xfffd;֤ʧ&#…

绝区柒--LLM简史

这是一系列LLM介绍的可成&#xff0c;分以下五个不分 序言&#xff1a;大型语言模型LLM简史第一部分&#xff1a;代币化——完整指南第 2 部分&#xff1a;使用 Python 中的 Scratch 从零开始使用 word2vec 进行词嵌入第 3 部分&#xff1a;用代码解释自注意力机制第 4 部分&a…

揭秘“消费即赚”的循环购模式

大家好&#xff0c;我是吴军&#xff0c;今天我将带您深入探索一种颠覆传统的新型商业模式——循环购模式。在这个模式中&#xff0c;消费者不仅能享受到购物的乐趣&#xff0c;还能通过消费获得实实在在的回报&#xff0c;甚至实现“边消费边赚钱”的奇妙体验。您是否好奇&…