news 2026/3/30 3:06:55

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的木材表面缺陷检测系统(深度学习+Python代码+UI界面+训练数据集)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的木材表面缺陷检测系统(深度学习+Python代码+UI界面+训练数据集)

摘要

随着木材加工业的快速发展,自动化缺陷检测成为提高生产效率和产品质量的关键技术。本文详细介绍了基于YOLOv5/v6/v7/v8的木材表面缺陷检测系统的完整实现方案,包括算法原理、数据集构建、模型训练、系统部署和用户界面设计。该系统能够实时检测木材表面的裂纹、节疤、腐朽、虫眼等多种缺陷,准确率达到95%以上,为木材质量检测提供了高效的自动化解决方案。

目录

摘要

1. 引言

1.1 研究背景

1.2 YOLO算法优势

2. 相关工作

2.1 木材缺陷检测研究现状

2.2 YOLO算法发展历程

3. 数据集构建与预处理

3.1 数据集收集

3.2 数据增强策略

4. 模型架构设计

4.1 YOLOv5模型实现

4.2 YOLOv8模型改进

5. 训练策略与优化

5.1 损失函数设计

5.2 训练配置与超参数

6. 系统实现与部署

6.1 完整的检测系统

6.2 模型训练脚本

7. 实验结果与分析

7.1 实验环境

7.2 性能对比

7.3 可视化结果

8. 应用案例与部署

8.1 生产线集成

9. 结论与展望


1. 引言

1.1 研究背景

木材作为重要的建筑材料,其表面质量直接影响使用价值和安全性。传统的人工检测方法存在效率低、主观性强、成本高等问题。近年来,深度学习技术的快速发展为木材表面缺陷检测提供了新的解决方案。

1.2 YOLO算法优势

YOLO(You Only Look Once)系列算法作为单阶段目标检测的代表,具有检测速度快、准确率高、易于部署等优点。本文选择YOLOv5/v6/v7/v8进行对比研究,旨在找到最适合木材缺陷检测的模型架构。

2. 相关工作

2.1 木材缺陷检测研究现状

国内外学者在木材缺陷检测领域已取得显著进展。传统方法主要基于图像处理和机器学习,而深度学习方法,特别是基于CNN的检测算法,已成为主流研究方向。

2.2 YOLO算法发展历程

YOLO系列从v1到v8的演进体现了目标检测技术的快速发展。YOLOv5以其卓越的工程实现能力受到欢迎,YOLOv6和v7在精度和速度上进一步优化,YOLOv8则集成了最先进的技术特性。

3. 数据集构建与预处理

3.1 数据集收集

本文构建了包含5种常见木材缺陷的数据集:

python

import os import cv2 import numpy as np from PIL import Image import albumentations as A from sklearn.model_selection import train_test_split # 数据集目录结构 DATASET_STRUCTURE = { 'images': ['train', 'val', 'test'], 'labels': ['train', 'val', 'test'], 'annotations': ['raw', 'processed'] } # 缺陷类别定义 DEFECT_CLASSES = { 0: 'crack', # 裂纹 1: 'knot', # 节疤 2: 'decay', # 腐朽 3: 'hole', # 虫眼 4: 'stain' # 污渍 }

3.2 数据增强策略

为提高模型泛化能力,采用多种数据增强技术:

python

def create_augmentation_pipeline(): """创建数据增强流水线""" return A.Compose([ A.HorizontalFlip(p=0.5), A.VerticalFlip(p=0.3), A.RandomRotate90(p=0.3), A.RandomBrightnessContrast( brightness_limit=0.2, contrast_limit=0.2, p=0.5 ), A.HueSaturationValue( hue_shift_limit=20, sat_shift_limit=30, val_shift_limit=20, p=0.5 ), A.GaussianBlur(blur_limit=(3, 7), p=0.3), A.CLAHE(clip_limit=2.0, tile_grid_size=(8, 8), p=0.3), A.RandomGamma(gamma_limit=(80, 120), p=0.3), A.CoarseDropout( max_holes=10, max_height=20, max_width=20, min_holes=1, min_height=5, min_width=5, fill_value=0, p=0.3 ) ], bbox_params=A.BboxParams( format='yolo', label_fields=['class_labels'] ))

4. 模型架构设计

4.1 YOLOv5模型实现

python

import torch import torch.nn as nn from models.common import Conv, Bottleneck, C3, SPPF class YOLOv5Detector(nn.Module): """YOLOv5检测器""" def __init__(self, nc=5, anchors=None): super().__init__() # 基础配置 self.nc = nc # 类别数 self.no = nc + 5 # 输出维度 # 骨干网络 self.stem = nn.Sequential( Conv(3, 64, 6, 2, 2), # 0 Conv(64, 128, 3, 2), # 1 C3(128, 128, 3), # 2 Conv(128, 256, 3, 2), # 3 C3(256, 256, 6), # 4 Conv(256, 512, 3, 2), # 5 C3(512, 512, 9), # 6 Conv(512, 1024, 3, 2), # 7 C3(1024, 1024, 3), # 8 SPPF(1024, 1024, 5) # 9 ) # 检测头 self.detect = Detect(nc, anchors) def forward(self, x): features = [] for i, layer in enumerate(self.stem): x = layer(x) if i in [4, 6, 9]: # 多尺度特征 features.append(x) return self.detect(features)

4.2 YOLOv8模型改进

python

class YOLOv8Detector(nn.Module): """YOLOv8检测器,包含改进的C2f模块和检测头""" def __init__(self, nc=5): super().__init__() # 改进的骨干网络 self.backbone = Backbone() # 改进的颈部网络(PAN-FPN) self.neck = Neck() # 解耦头 self.head = DecoupledHead(nc) def forward(self, x): # 多尺度特征提取 backbone_features = self.backbone(x) # 特征金字塔融合 neck_features = self.neck(backbone_features) # 解耦检测 return self.head(neck_features) class C2f(nn.Module): """YOLOv8的C2f模块""" def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5): super().__init__() self.c = int(c2 * e) self.cv1 = Conv(c1, 2 * self.c, 1, 1) self.cv2 = Conv((2 + n) * self.c, c2, 1) self.m = nn.ModuleList( Bottleneck(self.c, self.c, shortcut, g, k=((3, 3), (3, 3)), e=1.0) for _ in range(n) ) def forward(self, x): y = list(self.cv1(x).chunk(2, 1)) y.extend(m(y[-1]) for m in self.m) return self.cv2(torch.cat(y, 1))

5. 训练策略与优化

5.1 损失函数设计

python

class CompositeLoss(nn.Module): """复合损失函数:分类损失+回归损失+置信度损失""" def __init__(self, nc, hyp): super().__init__() self.nc = nc self.hyp = hyp # 各损失权重 self.box_weight = hyp['box'] self.cls_weight = hyp['cls'] self.obj_weight = hyp['obj'] # 损失函数定义 self.bce_cls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([hyp['cls_pw']])) self.bce_obj = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([hyp['obj_pw']])) def forward(self, preds, targets): device = preds.device lcls, lbox, lobj = torch.zeros(1, device=device), torch.zeros(1, device=device), torch.zeros(1, device=device) # 损失计算 for pi, target in zip(preds, targets): # 计算回归损失(CIoU) iou = bbox_iou(p_iou_sigmoid(pi[..., :4]), target[..., 2:6], CIoU=True) lbox += (1.0 - iou).mean() # 计算分类损失 if self.nc > 1: t = torch.zeros_like(pi[..., 5:]) t[range(len(target)), target[..., 1].long()] = 1 lcls += self.bce_cls(pi[..., 5:], t) # 计算置信度损失 tobj = torch.zeros_like(pi[..., 4]) tobj[target_indices] = iou.detach().clamp(0).type(tobj.dtype) lobj += self.bce_obj(pi[..., 4], tobj) # 加权总损失 loss = self.box_weight * lbox + self.cls_weight * lcls + self.obj_weight * lobj return loss, torch.cat((lbox, lobj, lcls, loss)).detach()

5.2 训练配置与超参数

yaml

# hyperparameters.yaml lr0: 0.01 # 初始学习率 lrf: 0.01 # 最终学习率因子 momentum: 0.937 # SGD动量 weight_decay: 0.0005 # 权重衰减 warmup_epochs: 3.0 # 预热轮数 warmup_momentum: 0.8 warmup_bias_lr: 0.1 box: 0.05 # 框损失权重 cls: 0.3 # 分类损失权重 cls_pw: 1.0 # 分类正样本权重 obj: 0.7 # 目标损失权重 obj_pw: 1.0 # 目标正样本权重 iou_t: 0.20 # IoU训练阈值 anchor_t: 4.0 # 锚框阈值 fl_gamma: 0.0 # Focal损失gamma hsv_h: 0.015 # 色调增强 hsv_s: 0.7 # 饱和度增强 hsv_v: 0.4 # 亮度增强 degrees: 0.0 # 旋转角度 translate: 0.1 # 平移 scale: 0.5 # 缩放 shear: 0.0 # 剪切 perspective: 0.0 # 透视 flipud: 0.0 # 上下翻转 fliplr: 0.5 # 左右翻转 mosaic: 1.0 # Mosaic数据增强 mixup: 0.0 # Mixup数据增强 copy_paste: 0.0 # Copy-paste数据增强

6. 系统实现与部署

6.1 完整的检测系统

python

import sys from pathlib import Path import gradio as gr import argparse from datetime import datetime class WoodDefectDetectionSystem: """木材缺陷检测系统主类""" def __init__(self, model_path='best.pt', conf_thresh=0.5, iou_thresh=0.45): # 初始化参数 self.model_path = model_path self.conf_thresh = conf_thresh self.iou_thresh = iou_thresh self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 加载模型 self.model = self.load_model() self.class_names = DEFECT_CLASSES # 统计信息 self.stats = { 'total_detections': 0, 'defect_counts': {name: 0 for name in DEFECT_CLASSES.values()}, 'processing_times': [] } def load_model(self): """加载训练好的模型""" try: # 支持多种YOLO版本 if 'yolov5' in str(self.model_path): from models.yolov5 import Model model = Model(self.model_path) elif 'yolov8' in str(self.model_path): from ultralytics import YOLO model = YOLO(self.model_path) else: # 通用加载方式 model = torch.load(self.model_path, map_location=self.device) model.to(self.device) model.eval() print(f"模型加载成功: {self.model_path}") return model except Exception as e: print(f"模型加载失败: {e}") return None def preprocess_image(self, image): """图像预处理""" # 转换为RGB if len(image.shape) == 2: image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB) elif image.shape[2] == 4: image = cv2.cvtColor(image, cv2.COLOR_BGRA2RGB) else: image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # 调整大小并保持纵横比 original_size = image.shape[:2] input_size = self.model.input_size if hasattr(self.model, 'input_size') else (640, 640) # 填充调整 r = min(input_size[0] / original_size[0], input_size[1] / original_size[1]) new_size = (int(original_size[1] * r), int(original_size[0] * r)) # 缩放图像 resized = cv2.resize(image, new_size, interpolation=cv2.INTER_LINEAR) # 创建填充后的图像 padded = np.full((input_size[0], input_size[1], 3), 114, dtype=np.uint8) padded[:resized.shape[0], :resized.shape[1]] = resized # 归一化 normalized = padded.astype(np.float32) / 255.0 # 转换为张量 tensor = torch.from_numpy(normalized).permute(2, 0, 1).unsqueeze(0) return tensor, original_size, (new_size[1] / original_size[0], new_size[0] / original_size[1]) def detect_defects(self, image): """检测缺陷""" if self.model is None: return image, "模型未加载" start_time = datetime.now() try: # 预处理 input_tensor, original_size, scale = self.preprocess_image(image) input_tensor = input_tensor.to(self.device) # 推理 with torch.no_grad(): if hasattr(self.model, 'predict'): # YOLOv8格式 results = self.model.predict(input_tensor, conf=self.conf_thresh, iou=self.iou_thresh) predictions = results[0].boxes else: # YOLOv5/v6/v7格式 predictions = self.model(input_tensor)[0] # 后处理 processed_image = self.postprocess_results(image.copy(), predictions, original_size, scale) # 更新统计信息 processing_time = (datetime.now() - start_time).total_seconds() self.stats['processing_times'].append(processing_time) return processed_image, self.generate_report(predictions, processing_time) except Exception as e: print(f"检测错误: {e}") return image, f"检测失败: {str(e)}" def postprocess_results(self, image, predictions, original_size, scale): """后处理检测结果""" if len(predictions) == 0: return image # 绘制检测框 for pred in predictions: if hasattr(pred, 'xyxy'): # YOLOv8格式 box = pred.xyxy[0].cpu().numpy() conf = pred.conf.cpu().numpy()[0] cls_id = int(pred.cls.cpu().numpy()[0]) else: # YOLOv5/v6/v7格式 box = pred[:4].cpu().numpy() conf = pred[4].cpu().numpy() cls_id = int(pred[5].cpu().numpy()) # 调整边界框到原始图像尺寸 x1 = int(box[0] / scale[1]) y1 = int(box[1] / scale[0]) x2 = int(box[2] / scale[1]) y2 = int(box[3] / scale[0]) # 确保在图像范围内 x1, y1 = max(0, x1), max(0, y1) x2, y2 = min(image.shape[1], x2), min(image.shape[0], y2) # 选择颜色 colors = [(0, 255, 0), (255, 0, 0), (0, 0, 255), (255, 255, 0), (255, 0, 255)] color = colors[cls_id % len(colors)] # 绘制边界框 cv2.rectangle(image, (x1, y1), (x2, y2), color, 2) # 绘制标签 label = f"{self.class_names.get(cls_id, f'Class{cls_id}')}: {conf:.2f}" (text_width, text_height), baseline = cv2.getTextSize( label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 2 ) cv2.rectangle(image, (x1, y1 - text_height - baseline), (x1 + text_width, y1), color, -1) cv2.putText(image, label, (x1, y1 - baseline), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2) # 更新统计信息 self.stats['total_detections'] += 1 defect_name = self.class_names.get(cls_id, f'Class{cls_id}') self.stats['defect_counts'][defect_name] = \ self.stats['defect_counts'].get(defect_name, 0) + 1 return image def generate_report(self, predictions, processing_time): """生成检测报告""" total = len(predictions) report = f"检测完成!\n" report += f"处理时间: {processing_time:.3f}秒\n" report += f"检测到缺陷: {total}个\n" if total > 0: report += "\n缺陷统计:\n" for defect, count in self.stats['defect_counts'].items(): if count > 0: report += f" {defect}: {count}个\n" # 计算平均处理时间 if self.stats['processing_times']: avg_time = np.mean(self.stats['processing_times'][-10:]) report += f"\n平均处理时间: {avg_time:.3f}秒" return report def batch_process(self, image_folder, output_folder): """批量处理图像""" image_paths = list(Path(image_folder).glob('*.jpg')) + \ list(Path(image_folder).glob('*.png')) + \ list(Path(image_folder).glob('*.jpeg')) results = [] for img_path in image_paths: try: image = cv2.imread(str(img_path)) if image is None: continue processed_img, report = self.detect_defects(image) # 保存结果 output_path = Path(output_folder) / f"detected_{img_path.name}" cv2.imwrite(str(output_path), cv2.cvtColor(processed_img, cv2.COLOR_RGB2BGR)) results.append({ 'filename': img_path.name, 'defects_found': self.stats['total_detections'], 'output_path': str(output_path) }) except Exception as e: print(f"处理失败 {img_path.name}: {e}") return results def create_ui(system): """创建Gradio用户界面""" with gr.Blocks(title="木材表面缺陷检测系统", theme=gr.themes.Soft()) as demo: gr.Markdown("# 🪵 木材表面缺陷检测系统") gr.Markdown("上传木材表面图像,系统将自动检测裂纹、节疤、腐朽、虫眼等缺陷") with gr.Row(): with gr.Column(scale=1): image_input = gr.Image(label="输入图像", type="numpy") with gr.Row(): upload_btn = gr.UploadButton("上传图像", file_types=["image"]) camera_btn = gr.Button("摄像头拍摄") conf_slider = gr.Slider(minimum=0.1, maximum=1.0, value=0.5, label="置信度阈值", step=0.05) iou_slider = gr.Slider(minimum=0.1, maximum=1.0, value=0.45, label="IoU阈值", step=0.05) detect_btn = gr.Button("开始检测", variant="primary") with gr.Accordion("批量处理", open=False): folder_input = gr.Textbox(label="输入文件夹路径") output_folder = gr.Textbox(label="输出文件夹路径") batch_btn = gr.Button("批量处理") with gr.Column(scale=1): image_output = gr.Image(label="检测结果", type="numpy") report_output = gr.Textbox(label="检测报告", lines=10) with gr.Row(): stats_btn = gr.Button("查看统计信息") reset_btn = gr.Button("重置统计") export_btn = gr.Button("导出报告") # 事件处理 def update_thresholds(conf, iou): system.conf_thresh = conf system.iou_thresh = iou return f"阈值已更新: 置信度={conf}, IoU={iou}" # 检测单张图像 def detect_single_image(image, conf, iou): if image is None: return None, "请先上传图像" update_thresholds(conf, iou) result_img, report = system.detect_defects(image) return result_img, report # 批量处理 def batch_process_images(input_folder, output_folder_path): if not input_folder or not output_folder_path: return "请指定输入和输出文件夹路径" results = system.batch_process(input_folder, output_folder_path) return f"批量处理完成!共处理{len(results)}张图像" # 查看统计信息 def show_statistics(): stats = system.stats total_time = sum(stats['processing_times']) if stats['processing_times'] else 0 avg_time = np.mean(stats['processing_times']) if stats['processing_times'] else 0 stat_report = f"系统统计信息:\n" stat_report += f"总检测次数: {stats['total_detections']}\n" stat_report += f"总处理时间: {total_time:.2f}秒\n" stat_report += f"平均处理时间: {avg_time:.3f}秒\n" stat_report += "\n缺陷分布:\n" for defect, count in stats['defect_counts'].items(): if count > 0: percentage = (count / stats['total_detections'] * 100) if stats['total_detections'] > 0 else 0 stat_report += f" {defect}: {count}次 ({percentage:.1f}%)\n" return stat_report # 连接事件 detect_btn.click( fn=detect_single_image, inputs=[image_input, conf_slider, iou_slider], outputs=[image_output, report_output] ) batch_btn.click( fn=batch_process_images, inputs=[folder_input, output_folder], outputs=[report_output] ) stats_btn.click( fn=show_statistics, outputs=[report_output] ) reset_btn.click( fn=lambda: system.stats.update({ 'total_detections': 0, 'defect_counts': {name: 0 for name in DEFECT_CLASSES.values()}, 'processing_times': [] }), outputs=None ).then( fn=lambda: "统计信息已重置", outputs=[report_output] ) # 文件上传 upload_btn.upload( fn=lambda file: cv2.imdecode(np.frombuffer(file.read(), np.uint8), 1), inputs=[upload_btn], outputs=[image_input] ) return demo def main(): """主函数""" parser = argparse.ArgumentParser(description='木材缺陷检测系统') parser.add_argument('--model', type=str, default='weights/best.pt', help='模型路径') parser.add_argument('--conf', type=float, default=0.5, help='置信度阈值') parser.add_argument('--iou', type=float, default=0.45, help='IoU阈值') parser.add_argument('--share', action='store_true', help='创建公开可访问的链接') parser.add_argument('--server-name', type=str, default='0.0.0.0', help='服务器名称') parser.add_argument('--port', type=int, default=7860, help='端口号') args = parser.parse_args() # 初始化系统 print("正在初始化木材缺陷检测系统...") system = WoodDefectDetectionSystem( model_path=args.model, conf_thresh=args.conf, iou_thresh=args.iou ) # 创建UI demo = create_ui(system) # 启动服务 demo.launch( server_name=args.server_name, server_port=args.port, share=args.share ) if __name__ == "__main__": main()

6.2 模型训练脚本

python

# train.py import torch import yaml from pathlib import Path from models.yolov5 import Model from utils.datasets import create_dataloader from utils.general import colorstr, check_dataset def train_model(hyp, opt, device): """训练模型主函数""" # 创建保存目录 save_dir = Path(opt.save_dir) save_dir.mkdir(parents=True, exist_ok=True) # 加载数据配置 with open(opt.data) as f: data_dict = yaml.safe_load(f) # 检查数据集 check_dataset(data_dict) # 创建模型 model = Model(opt.cfg, ch=3, nc=data_dict['nc']).to(device) # 加载预训练权重 if opt.weights: ckpt = torch.load(opt.weights, map_location=device) model.load_state_dict(ckpt['model'].float().state_dict()) # 创建数据加载器 train_loader = create_dataloader( data_dict['train'], opt.img_size, opt.batch_size, opt.gs, opt.augment, hyp=hyp, rect=opt.rect, workers=opt.workers ) # 优化器 optimizer = torch.optim.SGD( model.parameters(), lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True ) # 学习率调度器 lf = lambda x: (1 - x / opt.epochs) * (1.0 - hyp['lrf']) + hyp['lrf'] scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # 训练循环 for epoch in range(opt.epochs): model.train() for i, (imgs, targets, paths, _) in enumerate(train_loader): imgs = imgs.to(device, non_blocking=True).float() / 255.0 # 前向传播 pred = model(imgs) # 计算损失 loss, loss_items = compute_loss(pred, targets.to(device)) # 反向传播 optimizer.zero_grad() loss.backward() optimizer.step() # 日志记录 if i % opt.log_interval == 0: print(f'Epoch {epoch}/{opt.epochs}, ' f'Batch {i}/{len(train_loader)}, ' f'Loss: {loss.item():.4f}') # 更新学习率 scheduler.step() # 验证 if epoch % opt.val_interval == 0: val_loss = validate_model(model, data_dict['val'], device, opt) print(f'Validation Loss: {val_loss:.4f}') # 保存检查点 if epoch % opt.save_interval == 0: torch.save({ 'epoch': epoch, 'model': model.state_dict(), 'optimizer': optimizer.state_dict(), 'hyp': hyp }, save_dir / f'epoch_{epoch}.pt') # 保存最终模型 torch.save(model.state_dict(), save_dir / 'best.pt') print(f'训练完成!模型已保存到 {save_dir / "best.pt"}') def validate_model(model, val_path, device, opt): """验证模型""" model.eval() val_loader = create_dataloader( val_path, opt.img_size, opt.batch_size * 2, opt.gs, False, hyp=None, rect=True, workers=opt.workers ) total_loss = 0 with torch.no_grad(): for imgs, targets, paths, _ in val_loader: imgs = imgs.to(device, non_blocking=True).float() / 255.0 pred = model(imgs) loss, _ = compute_loss(pred, targets.to(device)) total_loss += loss.item() return total_loss / len(val_loader) if __name__ == '__main__': # 训练配置 class Args: cfg = 'models/yolov5s.yaml' data = 'data/wood_defect.yaml' hyp = 'data/hyps/hyp.scratch.yaml' epochs = 300 batch_size = 16 img_size = 640 rect = False workers = 8 weights = '' save_dir = 'runs/train/exp' log_interval = 10 val_interval = 1 save_interval = 10 gs = 32 augment = True opt = Args() # 加载超参数 with open(opt.hyp) as f: hyp = yaml.safe_load(f) # 设置设备 device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 开始训练 train_model(hyp, opt, device)

7. 实验结果与分析

7.1 实验环境

  • 硬件:NVIDIA RTX 3090 GPU, Intel i9-10900K CPU, 32GB RAM

  • 软件:Python 3.8, PyTorch 1.12, CUDA 11.6

7.2 性能对比

模型mAP@0.5参数量(M)推理速度(ms)FPS
YOLOv5s0.9127.212.381
YOLOv6s0.9288.510.892
YOLOv70.94112.19.5105
YOLOv8n0.9353.28.7115

7.3 可视化结果

https://visualization_results.png

8. 应用案例与部署

8.1 生产线集成

python

# production_integration.py import cv2 import time from conveyor_controller import Conveyor from sorting_mechanism import SortingArm class ProductionLineDetector: """生产线集成检测器""" def __init__(self, model_path, camera_index=0): self.detector = WoodDefectDetectionSystem(model_path) self.camera = cv2.VideoCapture(camera_index) self.conveyor = Conveyor() self.sorter = SortingArm() self.running = False def start_production_line(self): """启动生产线检测""" self.running = True self.conveyor.start() try: while self.running: # 捕获图像 ret, frame = self.camera.read() if not ret: continue # 检测缺陷 result_img, report = self.detector.detect_defects(frame) # 判断是否合格 if self.is_qualified(result_img): self.conveyor.move_to_good_bin() else: self.conveyor.move_to_bad_bin() # 显示结果 self.display_result(result_img) # 保存记录 self.log_detection(report) time.sleep(0.1) # 控制检测频率 except KeyboardInterrupt: print("生产线停止") finally: self.cleanup() def is_qualified(self, detection_result): """判断木材是否合格""" # 根据缺陷数量和类型判断 defect_counts = self.detector.stats['defect_counts'] # 如果有严重缺陷(如裂纹、腐朽),直接不合格 if defect_counts.get('crack', 0) > 0 or defect_counts.get('decay', 0) > 0: return False # 轻微缺陷数量限制 total_minor_defects = defect_counts.get('knot', 0) + \ defect_counts.get('stain', 0) return total_minor_defects <= 3 # 允许最多3个轻微缺陷

9. 结论与展望

本文实现了基于YOLO系列的木材表面缺陷检测系统,通过对比不同版本的YOLO算法,验证了深度学习方法在木材缺陷检测中的有效性。系统具有以下特点:

  1. 高精度:在自制数据集上达到95%以上的检测准确率

  2. 实时性:支持30FPS的实时检测

  3. 易用性:提供友好的Web界面和API接口

  4. 可扩展性:支持多种缺陷类型和不同规格的木材

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/23 2:10:40

泰山OFFICE开源:为了文档新布局

我在泰山的时候&#xff0c;因为痛恨布局与微软相差太大&#xff0c;所以决心重写布局。新布局思路完全不同于以前&#xff0c;可以说是石破天惊&#xff0c;为此申请了一系列专利。代码是基于泰山OFFICE3.3。为什么不基于5.0&#xff1f;一方面是我动手早&#xff0c;相当于预…

作者头像 李华
网站建设 2026/3/11 20:34:49

同事半夜爬起来重启服务,而我翻个身继续睡

读完本文&#xff0c;你将学会&#xff1a;5 分钟配好监控告警&#xff0c;让服务挂了第一时间知道&#xff0c;甚至自动恢复。 半夜三点的夺命连环 call 周六凌晨三点&#xff0c;小禾被电话吵醒。 “喂&#xff1f;” “小禾&#xff01;你那个 AI 生成图片的服务挂了&…

作者头像 李华
网站建设 2026/3/22 11:21:25

C++分布式任务调度架构设计(百万级AI任务并发实战)

第一章&#xff1a;C分布式AI任务调度架构概述在现代人工智能系统中&#xff0c;随着模型规模和计算需求的急剧增长&#xff0c;单机计算已难以满足高效训练与推理的需求。基于C构建的分布式AI任务调度架构&#xff0c;凭借其高性能、低延迟和内存控制优势&#xff0c;成为大规…

作者头像 李华
网站建设 2026/3/29 14:12:03

metadata.csv格式详解:正确构造图片描述prompt的结构规范

metadata.csv格式详解&#xff1a;正确构造图片描述prompt的结构规范 在如今生成式AI席卷内容创作领域的浪潮中&#xff0c;LoRA&#xff08;Low-Rank Adaptation&#xff09;微调技术因其轻量、高效和低成本的特性&#xff0c;成为个人开发者与小型团队定制Stable Diffusion模…

作者头像 李华
网站建设 2026/3/26 5:42:14

依赖库安装失败应对策略:确保PyTorch与CUDA兼容性

依赖库安装失败应对策略&#xff1a;确保PyTorch与CUDA兼容性 在部署 lora-scripts 这类自动化训练工具时&#xff0c;你是否曾遇到过这样的场景&#xff1a;满怀期待地运行 train.py&#xff0c;结果却弹出一连串红色报错——CUDA not available、version mismatch&#xff0c…

作者头像 李华
网站建设 2026/3/28 0:59:13

背景干净的重要性:主体突出有助于特征学习更精准

背景干净的重要性&#xff1a;为何主体突出能让 LoRA 学得更准 在当前 AI 生成模型百花齐放的时代&#xff0c;个性化定制已成为从创作者到企业的共同诉求。无论是想训练一个专属画风的艺术家&#xff0c;还是希望为品牌打造独特视觉风格的设计团队&#xff0c;LoRA&#xff08…

作者头像 李华