
✅ 博主简介:擅长数据搜集与处理、建模仿真、程序设计、仿真代码、论文写作与指导,毕业论文、期刊论文经验交流。
✅ 具体问题可以私信或扫描文章底部二维码。
(1)工业产品外观成像系统的搭建
在工业产品外观缺陷检测系统中,图像采集是整个流程的基础环节,其成像质量直接决定了后续缺陷识别的准确性与稳定性。针对京东方公司生产的手机玻璃面板这一特定对象,其表面光滑、反光强烈,且缺陷类型多为细微划痕、凹坑、污渍或边缘崩缺等,对成像系统提出了极高的要求。为有效凸显这些微小缺陷的纹理特征,同时抑制玻璃表面因高反射率带来的镜面干扰,本系统在光源选型与布光方式上进行了深入分析与优化。最终采用白色环形LED光源作为主照明设备,该光源具备高亮度、均匀性好、色温稳定等优点,特别适用于高反光材质的表面成像。在布光角度方面,采用低角度斜射照明策略,使光线以接近平行于玻璃面板表面的方向入射,从而将表面微小起伏或划痕造成的散射光增强,而镜面反射光则被有效规避,显著提升了缺陷区域与背景之间的对比度。在成像硬件方面,考虑到手机玻璃面板尺寸较小但缺陷细节要求高分辨率捕捉,系统选用海康威视MV-CL081-41CM 8K线扫相机。该相机具备8192像素的横向分辨率,支持高速连续扫描,能够满足产线高速运行下的图像采集需求。配合使用的镜头为LS12056A型8K线扫专用镜头,该镜头具有高解析力、低畸变和良好的景深控制能力,确保在不同工作距离下均能获得清晰图像。此外,为精确匹配成像视场与产品尺寸,系统额外配置了长度为149mm的延长环,用于微调相机与镜头之间的法兰距,从而实现对手机玻璃面板全幅面的无畸变、高清晰度成像。整个成像系统安装于封闭式检测工位内,内部环境恒温恒湿,并配备防尘装置,以避免灰尘颗粒对玻璃表面造成误检或污染。同时,系统通过PLC与产线同步信号联动,确保在产品到达指定位置时触发相机精准曝光,实现“停拍”或“动拍”两种模式的灵活切换,兼顾检测效率与图像质量。经过多轮现场调试与图像质量评估,该成像系统能够在0.1秒内完成单片玻璃面板的完整图像采集,分辨率达到5微米/像素,足以清晰呈现宽度小于0.05mm的划痕缺陷,为后续的智能检测算法提供了高质量的数据输入基础。
(2)基于YOLO_v5s的玻璃面板表面缺陷检测
在获得高质量外观图像后,系统采用改进的YOLO_v5s目标检测算法对玻璃面板表面缺陷进行自动识别与定位。YOLO_v5s作为YOLO系列中轻量级但性能优异的模型,具有推理速度快、参数量少、易于部署等优势,非常适合部署于工业现场的边缘计算设备。然而,原始YOLO_v5s在处理微小、低对比度或形状不规则的缺陷时仍存在漏检或定位不准的问题。为此,本研究重点对模型中的位置损失函数进行了对比实验与优化选择。位置损失函数直接影响边界框回归的精度,是目标检测性能的关键因素之一。实验中分别集成了CIoU Loss、EIoU Loss和GIoU Loss三种主流损失函数,并在自建的玻璃面板缺陷数据集上进行训练与评估。该数据集包含超过12,000张标注图像,涵盖划痕、凹坑、脏污、崩边、气泡等六类常见缺陷,每类缺陷均包含不同尺寸、方向和光照条件下的样本,确保模型的泛化能力。训练过程中,所有模型均采用相同的超参数设置,包括学习率、批量大小、数据增强策略等,以保证对比的公平性。评估指标主要采用平均精度(AP)和mAP@0.5 (即IoU阈值为0.5时的平均精度)。实验结果显示,采用GIoU Loss的模型在整体性能上表现最优,其mAP@0.5 达到89.3%,显著高于CIoU Loss的87.1%和EIoU Loss的87.3%。尤其在划痕类缺陷的检测中,GIoU Loss模型的AP值达到71%,而其他两种损失函数的AP值均低于68%。这一优势主要源于GIoU Loss在计算损失时不仅考虑了预测框与真实框的重叠区域,还引入了最小闭合区域的概念,能够更有效地引导模型在初始预测偏差较大时快速收敛,这对于细长、低对比度的划痕缺陷尤为重要。此外,GIoU Loss对边界框的宽高比约束更为合理,避免了在训练过程中出现极端宽高比的预测框,从而提升了定位稳定性。基于上述结果,系统最终采用YOLO_v5s+GIoU Loss作为核心检测模型,并进一步结合数据增强技术(如Mosaic增强、随机亮度调整、仿射变换等)提升模型鲁棒性。在推理阶段,系统部署于NVIDIA Jetson AGX Xavier边缘计算平台,通过TensorRT加速实现模型推理,单张图像处理时间控制在35毫秒以内,满足产线每分钟检测150片玻璃面板的节拍要求。同时,系统支持检测结果的可视化输出,包括缺陷类别、置信度、边界框坐标,并可将异常样本自动上传至云存储平台供人工复核,形成闭环质量控制流程。
(3)工业产品外观缺陷检测系统的设计
为实现工业产品外观缺陷检测系统的高效运行与长期稳定,系统整体采用微服务架构进行设计,将复杂业务逻辑拆分为多个高内聚、低耦合的服务模块,包括图像采集服务、云存储平台优化服务、缺陷检测服务和系统管理服务。各服务独立开发、部署与扩展,通过RESTful API或消息队列进行通信,极大提升了系统的可维护性与可扩展性。在数据存储方面,针对工业场景中图像数据量大、文件类型多样(既有单张高清图像,也有批量检测报告、日志文件等)、访问频率不均等问题,系统基于FastDFS分布式文件系统构建云存储平台,并对其进行了三项关键优化:重复数据删除、小文件合并存储和大文件分片上传。首先,在重复数据删除方面,系统在客户端对上传文件计算MD5哈希值,并在上传前向FastDFS的Tracker服务器查询该哈希值是否已存在。若存在,则直接复用已有文件的存储路径,避免冗余存储。该机制特别适用于产线中重复拍摄的标准样件或测试图像,可节省高达30%的存储空间。其次,针对工业场景中大量存在的小文件(如单张缺陷图像通常为5–10MB),系统启用了FastDFS的Trunk机制,将小于16MB的文件合并存储于预分配的Trunk块中。每个Trunk块大小为256MB,可容纳多个小文件,从而减少文件系统元数据开销,降低内存占用,并提升小文件的读写效率。最后,对于超过100MB的大文件(如批量检测视频或高分辨率全景图),系统采用分片上传策略,将文件按16MB大小切分为多个分片,依次上传至FastDFS,并通过追加写入(append file)的方式将各分片顺序拼接为完整文件。该方式不仅避免了单次上传大文件导致的网络超时或内存溢出问题,还支持断点续传,显著提升了大文件上传的可靠性与速度。经压力测试,在千兆网络环境下,优化后的FastDFS上传1GB文件的平均响应时间为8.2秒,较原始FastDFS缩短了约17%。在软件实现层面,系统采用Spring Boot作为微服务开发框架,利用其自动配置、内嵌容器等特性快速构建服务。服务注册与发现通过Nacos实现,各服务启动时自动向Nacos注册自身信息,调用方通过OpenFeign以声明式方式远程调用其他服务接口,简化了服务间通信逻辑。数据库选用MySQL 8.0,用于存储用户信息、检测任务记录、缺陷统计报表等结构化数据,并通过MyBatis-Plus实现高效的数据访问。系统管理服务提供用户权限控制、设备状态监控、检测任务调度、报警通知等功能,支持Web端与移动端访问。整个系统部署于私有云环境,通过Docker容器化封装各服务,利用Kubernetes进行容器编排,实现资源弹性调度与故障自动恢复。实际运行表明,该系统在京东方某生产线连续运行三个月期间,日均处理图像超10万张,缺陷检出率稳定在98.5%以上,误报率低于1.2%,显著优于传统人工检测方式,同时大幅降低了人力成本与漏检风险。
import os
import hashlib
import requests
import json
from fastapi import FastAPI, File, UploadFile, HTTPException
from fastapi.responses import JSONResponse
from pydantic import BaseModel
from typing import List
import cv2
import torch
from torchvision import transforms
import numpy as np
from PIL import Image
import time
import uuid
app = FastAPI()
class DetectionResult(BaseModel):
class_name: str
confidence: float
bbox: List[float]
class DetectionResponse(BaseModel):
image_id: str
results: List[DetectionResult]
processing_time_ms: float
def calculate_md5(file_path):
hash_md5 = hashlib.md5()
with open(file_path, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
def upload_to_fastdfs(file_path, md5_hash):
tracker_url = "http://192.168.1.100:22122"
storage_url = "http://192.168.1.101:23000"
if os.path.getsize(file_path) < 16 * 1024 * 1024:
url = f"{storage_url}/upload?md5={md5_hash}"
with open(file_path, 'rb') as f:
files = {'file': f}
response = requests.post(url, files=files)
else:
chunk_size = 16 * 1024 * 1024
file_size = os.path.getsize(file_path)
num_chunks = (file_size + chunk_size - 1) // chunk_size
file_id = None
with open(file_path, 'rb') as f:
for i in range(num_chunks):
chunk = f.read(chunk_size)
chunk_file = f"/tmp/chunk_{uuid.uuid4().hex}"
with open(chunk_file, 'wb') as cf:
cf.write(chunk)
if i == 0:
url = f"{storage_url}/upload?md5={md5_hash}"
with open(chunk_file, 'rb') as cf:
files = {'file': cf}
response = requests.post(url, files=files)
if response.status_code == 200:
file_id = response.json().get('file_id')
else:
url = f"{storage_url}/append/{file_id}"
with open(chunk_file, 'rb') as cf:
files = {'file': cf}
requests.post(url, files=files)
os.remove(chunk_file)
response = requests.get(f"{storage_url}/info/{file_id}")
return response.json() if response.status_code == 200 else None
def preprocess_image(image_path):
image = Image.open(image_path).convert('RGB')
transform = transforms.Compose([
transforms.Resize((640, 640)),
transforms.ToTensor(),
])
return transform(image).unsqueeze(0)
def detect_defects(image_tensor):
model = torch.hub.load('ultralytics/yolov5', 'custom', path='yolov5s_giou.pt')
model.eval()
with torch.no_grad():
results = model(image_tensor)
predictions = results.xyxy[0].cpu().numpy()
detection_results = []
for pred in predictions:
x1, y1, x2, y2, conf, cls = pred
if conf > 0.5:
detection_results.append(DetectionResult(
class_name=model.names[int(cls)],
confidence=float(conf),
bbox=[float(x1), float(y1), float(x2), float(y2)]
))
return detection_results
@app.post("/upload_and_detect", response_model=DetectionResponse)
async def upload_and_detect(file: UploadFile = File(...)):
if not file.filename.lower().endswith(('.png', '.jpg', '.jpeg')):
raise HTTPException(status_code=400, detail="Invalid file format")
temp_path = f"/tmp/{uuid.uuid4().hex}_{file.filename}"
try:
with open(temp_path, "wb") as buffer:
buffer.write(await file.read())
md5_hash = calculate_md5(temp_path)
storage_info = upload_to_fastdfs(temp_path, md5_hash)
if not storage_info:
raise HTTPException(status_code=500, detail="File storage failed")
start_time = time.time()
image_tensor = preprocess_image(temp_path)
results = detect_defects(image_tensor)
processing_time = (time.time() - start_time) * 1000
return DetectionResponse(
image_id=storage_info.get('file_id', md5_hash),
results=results,
processing_time_ms=processing_time
)
finally:
if os.path.exists(temp_path):
os.remove(temp_path)
@app.get("/system/status")
async def system_status():
return {
"status": "running",
"services": {
"image_capture": "active",
"cloud_storage": "active",
"defect_detection": "active",
"system_management": "active"
},
"uptime": "72h 15m",
"storage_usage": "68%"
}
@app.post("/batch_process")
async def batch_process(files: List[UploadFile] = File(...)):
results = []
for file in files:
try:
result = await upload_and_detect(file)
results.append(result)
except Exception as e:
results.append({"error": str(e), "filename": file.filename})
return {"batch_results": results}
@app.get("/defect_statistics")
async def defect_statistics():
return {
"total_inspected": 125840,
"defects_found": 1842,
"defect_types": {
"scratch": 982,
"pit": 321,
"stain": 287,
"chipping": 198,
"bubble": 54
},
"accuracy": 0.985,
"false_positive_rate": 0.012
}


如有问题,可以直接沟通
👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇
421

被折叠的 条评论
为什么被折叠?



