HSG金属表面缺陷检测

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 osdef 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:0if 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 pathlibsource_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 Trueelse:print(path + ' 目录已存在')return Falsedef 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 // 2w1_half = img_w // 2img_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 // hpw1_half = img_w // wpwh_sum = wp * hpprint(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 modelmodel = YOLO("./best.pt")def load_image(image_path):"""加载图像:return: 图像"""print(image_path)if not os.path.exists(image_path):returnelse: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_namecv2.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_pathdef load_image_random(images_path):"""功能:在文件夹中随机加载一张图像:param image_path: 文件夹路径:return:"""pathname = random.choices(images_path)[0]image = load_image(pathname)return imagedef load_image_order(images_path):"""功能:在文件夹中按照先后顺序加载图片:param image_path: 文件夹路径:return:"""for pathname in images_path:image = load_image(pathname)yield imagedef 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 = 819segment_height = 750stride_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.boxesnames = result.namesnum = 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 = 15x1 = xyxy[0] + x - offsety1 = xyxy[1] + y - offsetx2 = xyxy[2] + x + offsety2 = xyxy[3] + y + offsetcv2.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.mzph.cn/bicheng/42987.shtml

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

相关文章

Qt json和xml操作

学习目标&#xff1a; 认识json和xml读写操作 前置环境 运行环境:qt creator 4.12 学习内容 XML XML&#xff08;Extensible Markup Language&#xff09;是一种标记语言,是一种用于描述数据结构的语言。它非常适合用于存储和传输数据。 XML 的主要特点如下: 可扩展性:XM…

数组算法(二):交替子数组计数

1. 官方描述 给你一个二进制数组nums 。如果一个子数组中 不存在 两个 相邻 元素的值 相同 的情况&#xff0c;我们称这样的子数组为 交替子数组 。 返回数组 nums 中交替子数组的数量。 示例 1&#xff1a; 输入&#xff1a; nums [0,1,1,1] 输出&#xff1a; 5 解释&#…

项目一单机安装基于LNMP结构的WordPress网站 web与数据库服务分离

网站的类型&#xff1a; Jave:LNMT PHP:LNMP Python: LNMU 项目部署&#xff1a; 1.项目的类型&#xff08;项目的开发语言&#xff09; 2.项目运营平台的技术选择 3.尽快让项目运行起来 all in one部署 4. 架构的优化 配置ansible管理环境 配置nginx 配置数据库服务…

leetcode:编程基础0到1

文章目录 交替合并字符串str.length();StringBuilder类型 ,toString()append() &#xff0c;chatAt()题目描述 交替合并字符串 str.length(); 输出字符串str的长度 StringBuilder类型 ,toString() append() &#xff0c;chatAt() 题目描述 class Solution {public String …

python获取文件列表按照文件修改时间进行排序,默认按照文件名时间戳排序

python获取文件列表按照文件修改时间进行排序,默认按照文件名时间戳排序 1、流程 1、获取文件绝对路径下的所有文件 2、通过os.path.getmtime获取每个文件的修改时间,并与文件组成元组,方便后续排序 3、默认按照时间戳降序,否则按照按修改时间排序文件列表(从最晚到最早)…

开个技术外挂|用技术轻松实现GPU显卡冷却风扇噪声控制

GPU显卡冷却风扇噪声分析 游戏玩家可能有这样的体验&#xff1a;当显卡卖力工作的时候&#xff0c;明显感觉到从机箱传来的噪声变大了。这是因为系统监测到芯片有过热风险&#xff0c;从而自动提升了冷却风扇的转速。 如下图所示&#xff0c;当GPU显卡处于 20C 时&#xff0c;风…

212.贪心算法:跳跃游戏(力扣)

代码解决 class Solution { public:bool canJump(vector<int>& nums) {int cover 0; // 初始化覆盖范围if (nums.size() 1) return true; // 如果数组长度为1&#xff0c;直接返回 true// 遍历数组&#xff0c;直到当前覆盖范围for (int i 0; i < cover; i…

【易捷海购-注册安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

【活动行】参与上海两场线下活动,教育生态行业赛总决赛活动和WAIC人工智能大会活动 - 上海活动总结

目录 背景决赛最后一公里领域范围 决赛作品AI智教相机辅导老师Copilot辅导老师Copilot雅思写作竞技场 优秀作品总结 背景 决赛 百度发起的千帆杯教育生态行业赛于2024年7月4日进行线下决赛&#xff0c;博主虽然没能进入决赛&#xff0c;但也非常荣幸能够以嘉宾身份到现场给进…

【VUE基础】VUE3第四节—核心语法之computed、watch、watcheffect

computed 接受一个 getter 函数&#xff0c;返回一个只读的响应式 ref 对象。该 ref 通过 .value 暴露 getter 函数的返回值。它也可以接受一个带有 get 和 set 函数的对象来创建一个可写的 ref 对象。 创建一个只读的计算属性 ref&#xff1a; <template><div cl…

<PLC><汇川><串口485>汇川Eazy521系列PLC与特域水冷机进行485通讯的设置

前言 本系列是关于PLC相关的博文,包括PLC编程、PLC与上位机通讯、PLC与下位驱动、仪器仪表等通讯、PLC指令解析等相关内容。 PLC品牌包括但不限于西门子、三菱等国外品牌,汇川、信捷等国内品牌。 除了PLC为主要内容外,PLC相关元器件如触摸屏(HMI)、交换机等工控产品,如…

【前端界面分享】

实现效果&#xff1a;html源码来自b站up主&#xff1a;【CSSJS】甲方&#xff1a;啊&#xff1f;没叫你做那么超前啊_哔哩哔哩_bilibili 本人仅实现了将html格式改为vue3 html版&#xff1a; 对于前端连入门可能都没摸到&#xff0c;学了半天也就改成vue3了&#xff0c;对于输…

【ARM系列】1 of N SPI

1 of N模式 SPI 概述配置流程 概述 GIC-600AE支持1 of N模式SPI。在此模式下可以将SPI target到多个core&#xff0c;并且GIC-600AE可以选择哪些内核接收SPI。 GIC-600AE只向处于powered up 并且使能中断组的core发送SPI。 GIC-600AE会优先考虑那些被认为是active的核&#xf…

SQL注入基础入门

文章目录 前言SQL注入基本操作SQL注入类型分类数字型字符型搜索型xx型Json型数据类型提交的方式 SQL注入的位置分类报错注入报错注入实战案例 SQL注入语句分类insert注入update注入delete注入 编码Tips&#xff1a;Mysql版本区别information_schema数据库详解 其他注入手段宽字…

面试官:Java线程可以无限创建吗?

1. 面试连环call Java线程可以无限创建吗? Java线程和操作系统线程有什么关联? 操作系统为什么要区分内核态和用户态? ⏩要想解答这些问题&#xff0c;我们要先从操作系统线程开始说起&#xff0c;让我们开始吧&#x1f389;&#x1f389;&#x1f389; 2. 操作系统线程…

为什么要学习Go

本文旨在探讨为什么Go语言值得学习,以及它如何能够提升您的编程技能和职业发展。我们将深入分析Go语言的核心优势,包括其简洁的语法、强大的并发支持、卓越的性能表现,以及在云计算、微服务和系统编程等领域的广泛应用 GO logo的核心理念&#xff0c;即简单胜于复杂。使用现代…

Redis-Redis可视化工具Redis Insight下载及安装

下载 1、博主已经上传资源&#xff0c;点此下载 2、点此进入官方下载 2.1 点击Installing Redis Insight 2.2 点击Install on desktop 2.3 选择Install on desktop&#xff0c;点击Redis Insight is available for download for free from this web site从网站下载 2.4 下载…

Python 可视化 web 神器:streamlit、Gradio、dash、nicegui;低代码 Python Web 框架:PyWebIO

官网&#xff1a;https://streamlit.io/ github&#xff1a;https://github.com/streamlit/streamlit API 参考&#xff1a;https://docs.streamlit.io/library/api-reference 最全 Streamlit 教程&#xff1a;https://juejin.cn/column/7265946243196436520 Streamlit-中文文档…

MYSQL 四、mysql进阶 7(性能分析工具的使用)

一、数据库服务器的优化步骤 数据库调优流程图: 整个流程划分成了 观察&#xff08;Show status&#xff09; 和 行动&#xff08;Action&#xff09; 两个部分。字母 S 的部分代表观察&#xff08;会使 用相应的分析工具&#xff09;&#xff0c;字母 A 代表的部分是行…

算法012:将x减到0的最小操作数

将x减到0的最小操作数. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/ 这个题使用到的是滑动窗口。 乍一看&#xff0c…