YOLO12与Vue.js结合构建可视化目标检测平台
YOLO12与Vue.js结合构建可视化目标检测平台最近在做一个智能安防项目需要把YOLO12目标检测的结果实时展示在网页上。一开始我们用的是传统的后端渲染每次检测完都要刷新页面体验特别差。后来尝试了前后端分离的方案用Vue.js做前端YOLO12做后端推理效果一下子就上来了。整个平台搭建起来后不仅检测结果能实时更新还能在网页上直接上传图片、调整检测参数、查看历史记录用户体验提升了好几个档次。今天我就把这个方案分享出来如果你也需要在Web应用中展示目标检测结果这个架构应该能帮到你。1. 为什么选择Vue.js YOLO12这个组合先说说为什么选这两个技术。YOLO12是YOLO系列的最新版本最大的特点是引入了注意力机制检测精度比之前的版本更高。虽然速度上可能比YOLO11慢一点但对于很多Web应用来说精度更重要一些。Vue.js则是目前最流行的前端框架之一它的响应式数据绑定特别适合做这种实时更新的应用。检测结果一出来页面上的标注框、标签、置信度分数都能自动更新不需要手动操作DOM。还有一个很重要的点Vue的生态很丰富。像Element Plus、Ant Design Vue这些UI组件库能让我们快速搭建出漂亮的界面。Vue Router做页面路由Pinia做状态管理整个应用的结构会很清晰。2. 整体架构设计整个平台采用前后端分离的架构前端用Vue.js后端用Python的FastAPI框架YOLO12负责目标检测。下面是具体的架构图┌─────────────────┐ HTTP请求 ┌─────────────────┐ Python调用 ┌─────────────────┐ │ │ ─────────── │ │ ─────────── │ │ │ Vue.js前端 │ │ FastAPI后端 │ │ YOLO12模型 │ │ │ ─────────── │ │ ─────────── │ │ │ (浏览器) │ JSON响应 │ (Python) │ 检测结果 │ (PyTorch) │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ │ │ │ ▼ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ 用户界面组件 │ │ RESTful API │ │ 模型推理引擎 │ │ - 图片上传 │ │ - 图片接收 │ │ - 加载模型 │ │ - 实时显示 │ │ - 调用YOLO12 │ │ - 预处理 │ │ - 参数调整 │ │ - 返回结果 │ │ - 推理 │ │ - 历史记录 │ │ │ │ - 后处理 │ └─────────────────┘ └─────────────────┘ └─────────────────┘这个架构有几个好处。首先前后端完全分离前端可以独立开发和部署后端也可以专注于算法和性能优化。其次RESTful API的设计让接口很清晰前端只需要调用几个简单的接口就能完成所有功能。最后这种架构扩展性很好以后如果想换别的检测模型或者增加新的功能改动起来都很方便。3. 前端Vue.js实现细节前端的核心是图片上传、实时显示和参数调整这三个功能。我用Vue 3的组合式API来写代码结构会更清晰。3.1 图片上传组件图片上传用的是原生的input typefile配合一个拖拽区域用户体验会更好。上传的图片会先在前端预览然后再发送到后端。template div classupload-area dragover.prevent drophandleDrop input typefile reffileInput changehandleFileChange acceptimage/* hidden div v-if!previewImage classupload-placeholder i classupload-icon/i p拖拽图片到这里或点击选择文件/p button clicktriggerFileInput选择图片/button /div div v-else classpreview-container img :srcpreviewImage alt预览图片 div classpreview-actions button clickdetectImage开始检测/button button clickclearImage重新选择/button /div /div /div /template script setup import { ref } from vue import { useDetectionStore } from /stores/detection const fileInput ref(null) const previewImage ref() const detectionStore useDetectionStore() // 触发文件选择 const triggerFileInput () { fileInput.value.click() } // 处理文件选择 const handleFileChange (event) { const file event.target.files[0] if (file) { const reader new FileReader() reader.onload (e) { previewImage.value e.target.result detectionStore.setOriginalImage(e.target.result) } reader.readAsDataURL(file) } } // 处理拖拽 const handleDrop (event) { event.preventDefault() const file event.dataTransfer.files[0] if (file file.type.startsWith(image/)) { const reader new FileReader() reader.onload (e) { previewImage.value e.target.result detectionStore.setOriginalImage(e.target.result) } reader.readAsDataURL(file) } } // 开始检测 const detectImage async () { if (previewImage.value) { await detectionStore.detectImage(previewImage.value) } } // 清除图片 const clearImage () { previewImage.value detectionStore.clearImage() fileInput.value.value } /script3.2 检测结果显示组件检测结果的显示是核心功能。我们需要在图片上画出检测框显示类别标签和置信度分数。这里用Canvas来实现因为Canvas画图性能比较好而且能实时更新。template div classresult-container div classcanvas-wrapper canvas refcanvasRef :widthcanvasWidth :heightcanvasHeight/canvas img v-iforiginalImage :srcoriginalImage alt原图 refimageRef loaddrawDetections /div div classdetection-list h3检测结果 ({{ detections.length }}个对象)/h3 div classdetection-item v-for(det, index) in detections :keyindex span classclass-label :style{ backgroundColor: getColor(det.class) } {{ det.class }} /span span classconfidence{{ (det.confidence * 100).toFixed(1) }}%/span span classbbox[{{ det.bbox.join(, ) }}]/span /div /div /div /template script setup import { ref, watch, onMounted } from vue import { useDetectionStore } from /stores/detection const canvasRef ref(null) const imageRef ref(null) const canvasWidth ref(800) const canvasHeight ref(600) const detectionStore useDetectionStore() const originalImage detectionStore.originalImage const detections detectionStore.detections // 颜色映射不同类别用不同颜色 const colorMap { person: #FF6B6B, car: #4ECDC4, dog: #FFD166, cat: #06D6A0, bicycle: #118AB2 } const getColor (className) { return colorMap[className] || #888888 } // 在Canvas上绘制检测框 const drawDetections () { if (!canvasRef.value || !imageRef.value) return const canvas canvasRef.value const ctx canvas.getContext(2d) const img imageRef.value // 清空Canvas ctx.clearRect(0, 0, canvas.width, canvas.height) // 绘制图片 ctx.drawImage(img, 0, 0, canvas.width, canvas.height) // 绘制每个检测框 detections.forEach(det { const [x1, y1, x2, y2] det.bbox const color getColor(det.class) // 画框 ctx.strokeStyle color ctx.lineWidth 2 ctx.strokeRect(x1, y1, x2 - x1, y2 - y1) // 画标签背景 ctx.fillStyle color const label ${det.class} ${(det.confidence * 100).toFixed(1)}% const textWidth ctx.measureText(label).width ctx.fillRect(x1, y1 - 20, textWidth 10, 20) // 画标签文字 ctx.fillStyle #FFFFFF ctx.font 14px Arial ctx.fillText(label, x1 5, y1 - 5) }) } // 监听检测结果变化重新绘制 watch(detections, () { drawDetections() }, { deep: true }) // 图片加载完成后绘制 watch(originalImage, () { if (originalImage imageRef.value) { imageRef.value.onload drawDetections } }) onMounted(() { drawDetections() }) /script3.3 参数调整面板不同的应用场景可能需要不同的检测参数。比如安防监控需要高召回率宁可误报也不能漏报而内容审核可能需要高精度确保每个检测都准确。template div classparameter-panel h3检测参数/h3 div classparameter-item label置信度阈值/label div classslider-container input typerange min0 max100 v-modelconfidenceThreshold changeupdateParameters span{{ (confidenceThreshold / 100).toFixed(2) }}/span /div /div div classparameter-item labelNMS阈值/label div classslider-container input typerange min0 max100 v-modelnmsThreshold changeupdateParameters span{{ (nmsThreshold / 100).toFixed(2) }}/span /div /div div classparameter-item label模型尺寸/label select v-modelmodelSize changeupdateParameters option valuenNano (最快)/option option valuesSmall/option option valuemMedium/option option valuelLarge/option option valuexXLarge (最准)/option /select /div div classparameter-item label检测类别过滤/label div classcategory-filters label v-forcategory in availableCategories :keycategory input typecheckbox v-modelselectedCategories :valuecategory changeupdateParameters {{ category }} /label /div /div button clickapplyParameters classapply-btn应用参数并重新检测/button /div /template script setup import { ref } from vue import { useDetectionStore } from /stores/detection const detectionStore useDetectionStore() const confidenceThreshold ref(25) // 默认0.25 const nmsThreshold ref(45) // 默认0.45 const modelSize ref(m) const selectedCategories ref([person, car, dog, cat]) const availableCategories [ person, bicycle, car, motorcycle, airplane, bus, train, truck, boat, traffic light, fire hydrant, stop sign, parking meter, bench, bird, cat, dog, horse, sheep, cow ] const updateParameters () { detectionStore.updateParameters({ confidence: confidenceThreshold.value / 100, iou: nmsThreshold.value / 100, model_size: modelSize.value, classes: selectedCategories.value }) } const applyParameters async () { updateParameters() if (detectionStore.originalImage) { await detectionStore.detectImage(detectionStore.originalImage) } } /script4. 后端FastAPI与YOLO12集成后端的主要工作是接收前端传来的图片调用YOLO12进行检测然后把结果返回给前端。我用FastAPI是因为它简单易用性能也不错。4.1 后端主程序from fastapi import FastAPI, File, UploadFile, HTTPException from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse import cv2 import numpy as np from ultralytics import YOLO import json from typing import List, Dict, Any import time app FastAPI(titleYOLO12 Detection API) # 配置CORS允许前端访问 app.add_middleware( CORSMiddleware, allow_origins[http://localhost:5173], # Vue开发服务器地址 allow_credentialsTrue, allow_methods[*], allow_headers[*], ) # 加载YOLO12模型 model_cache {} def get_model(model_size: str m): 获取指定尺寸的YOLO12模型 model_key fyolo12{model_size} if model_key not in model_cache: try: # 加载预训练模型 model YOLO(fyolo12{model_size}.pt) model_cache[model_key] model print(fLoaded model: {model_key}) except Exception as e: print(fError loading model {model_key}: {e}) # 如果指定尺寸的模型不存在使用默认模型 model YOLO(yolo12m.pt) model_cache[model_key] model return model_cache[model_key] app.post(/api/detect) async def detect_objects( file: UploadFile File(...), confidence: float 0.25, iou: float 0.45, model_size: str m, classes: List[str] None ): 目标检测接口 try: start_time time.time() # 读取图片 contents await file.read() nparr np.frombuffer(contents, np.uint8) image cv2.imdecode(nparr, cv2.IMREAD_COLOR) if image is None: raise HTTPException(status_code400, detail无法读取图片) # 获取模型 model get_model(model_size) # 准备检测参数 kwargs { conf: confidence, iou: iou, verbose: False } # 如果有指定类别转换为类别ID if classes and len(classes) 0: # 这里需要根据你的类别名称映射到YOLO的类别ID class_names model.names class_ids [] for class_name in classes: for idx, name in class_names.items(): if name class_name: class_ids.append(idx) break if class_ids: kwargs[classes] class_ids # 运行检测 results model(image, **kwargs) # 解析检测结果 detections [] for result in results: boxes result.boxes if boxes is not None: for box in boxes: # 获取边界框坐标 x1, y1, x2, y2 box.xyxy[0].tolist() # 获取类别和置信度 class_id int(box.cls[0]) confidence_score float(box.conf[0]) class_name model.names[class_id] detections.append({ bbox: [x1, y1, x2, y2], class: class_name, confidence: confidence_score, class_id: class_id }) # 计算处理时间 processing_time time.time() - start_time # 返回结果 return JSONResponse({ success: True, detections: detections, image_size: { width: int(image.shape[1]), height: int(image.shape[0]) }, processing_time: processing_time, model_used: fyolo12{model_size} }) except Exception as e: print(fDetection error: {e}) raise HTTPException(status_code500, detailf检测失败: {str(e)}) app.get(/api/models) async def get_available_models(): 获取可用的模型列表 return { models: [ {id: n, name: YOLO12-Nano, description: 最快适合移动设备}, {id: s, name: YOLO12-Small, description: 平衡速度和精度}, {id: m, name: YOLO12-Medium, description: 推荐用于大多数应用}, {id: l, name: YOLO12-Large, description: 高精度速度稍慢}, {id: x, name: YOLO12-XLarge, description: 最高精度适合专业应用} ] } app.get(/api/classes) async def get_available_classes(): 获取可检测的类别列表 try: model get_model(m) class_names model.names return { classes: [ {id: idx, name: name} for idx, name in class_names.items() ] } except Exception as e: return {classes: [], error: str(e)} if __name__ __main__: import uvicorn uvicorn.run(app, host0.0.0.0, port8000)4.2 前端状态管理前端用Pinia来管理状态把图片、检测结果、参数这些都放在store里这样各个组件都能访问到。// stores/detection.js import { defineStore } from pinia import { ref } from vue import axios from axios export const useDetectionStore defineStore(detection, () { const originalImage ref() const detections ref([]) const isLoading ref(false) const error ref(null) const processingTime ref(0) // 检测参数 const parameters ref({ confidence: 0.25, iou: 0.45, model_size: m, classes: [person, car, dog, cat] }) // 设置原始图片 const setOriginalImage (imageData) { originalImage.value imageData } // 清除图片和结果 const clearImage () { originalImage.value detections.value [] error.value null } // 更新参数 const updateParameters (newParams) { parameters.value { ...parameters.value, ...newParams } } // 执行检测 const detectImage async (imageData) { if (!imageData) return isLoading.value true error.value null try { // 将base64图片转换为Blob const base64Data imageData.split(,)[1] const byteCharacters atob(base64Data) const byteNumbers new Array(byteCharacters.length) for (let i 0; i byteCharacters.length; i) { byteNumbers[i] byteCharacters.charCodeAt(i) } const byteArray new Uint8Array(byteNumbers) const blob new Blob([byteArray], { type: image/jpeg }) // 创建FormData const formData new FormData() formData.append(file, blob, image.jpg) formData.append(confidence, parameters.value.confidence) formData.append(iou, parameters.value.iou) formData.append(model_size, parameters.value.model_size) // 添加类别参数 parameters.value.classes.forEach(cls { formData.append(classes, cls) }) // 发送请求 const response await axios.post(http://localhost:8000/api/detect, formData, { headers: { Content-Type: multipart/form-data } }) if (response.data.success) { detections.value response.data.detections processingTime.value response.data.processing_time } else { throw new Error(检测失败) } } catch (err) { error.value err.response?.data?.detail || err.message console.error(Detection error:, err) } finally { isLoading.value false } } return { originalImage, detections, isLoading, error, processingTime, parameters, setOriginalImage, clearImage, updateParameters, detectImage } })5. 实际应用效果这个平台搭建好后我们在几个实际场景中测试了一下效果挺不错的。5.1 智能安防监控在安防监控场景中我们接入了摄像头的实时流。前端用WebSocket接收后端推送的检测结果每秒能处理10-15帧对于人、车这些主要目标的检测准确率能达到90%以上。界面上除了实时视频还有报警记录、统计图表等功能。5.2 工业质检在工业生产线质检中我们用了YOLO12的XLarge模型虽然速度慢一点但精度很高。能检测出产品表面的微小瑕疵比如划痕、气泡、颜色不均等。前端界面做了优化把检测结果按严重程度分类方便质检员快速处理。5.3 智慧零售在零售店的人流统计和热区分析中这个平台也发挥了作用。能实时统计店内人数分析顾客在哪些区域停留时间最长哪些商品被关注最多。这些数据用图表展示在前端店主可以很直观地了解店铺运营情况。6. 遇到的问题和解决方案在实际开发中也遇到了一些问题这里分享一下解决方案。问题1大图片上传慢有些用户上传的图片很大有10MB以上上传和检测都很慢。我们的解决方案是在前端先压缩图片用Canvas的drawImage方法把图片缩放到合适尺寸然后再上传。这样既减少了上传时间也减轻了后端压力。问题2实时视频流卡顿刚开始做实时视频检测时画面经常卡顿。后来我们优化了几个地方一是降低视频流的分辨率二是后端用多线程处理三是前端用Web Worker来解码视频。优化后流畅度提升了很多。问题3不同浏览器兼容性Chrome上运行好好的到了Safari或Firefox就有问题。主要是Canvas的某些API和CSS特性支持不一样。我们用了autoprefixer来处理CSS前缀用babel转译ES6语法还做了详细的浏览器测试。问题4模型加载慢YOLO12的Large和XLarge模型文件比较大第一次加载要几十秒。我们做了模型缓存第一次加载后就把模型保存在内存中。还提供了模型切换功能用户可以根据需要选择不同大小的模型。7. 总结用Vue.js和YOLO12搭建可视化目标检测平台这个方案在实际项目中验证过效果确实不错。Vue的响应式特性和丰富的生态让前端开发很高效YOLO12的高精度检测能满足大多数应用需求。整个平台的核心思路就是前后端分离前端负责展示和交互后端负责算法推理。这种架构让两个部分可以独立开发和优化也方便以后扩展新功能。如果你也想做类似的项目建议先从简单的功能开始比如图片上传和检测结果展示。等这些基础功能跑通了再逐步添加实时视频、参数调整、历史记录这些高级功能。遇到性能问题不要怕一步步优化总能有解决方案的。这个平台的代码我已经整理好了包含前后端的完整实现。你可以根据自己的需求修改比如换用其他检测模型或者增加新的可视化功能。希望这个方案能给你带来启发做出更棒的目标检测应用。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。

相关新闻

通义千问3-VL-Reranker-8B在智能家居场景中的应用实践

通义千问3-VL-Reranker-8B在智能家居场景中的应用实践

通义千问3-VL-Reranker-8B在智能家居场景中的应用实践 1. 当语音指令遇上复杂设备,问题出在哪 你有没有遇到过这样的情况:对着智能音箱说“把客厅空调调到26度”,结果卧室的加湿器开始工作;或者喊“打开主卧灯光”,却…

2026/7/3 1:58:43 阅读更多 →
Qwen3-ASR-1.7B入门必看:Qwen3-ASR-1.7B与Qwen3-Chat模型协同工作流

Qwen3-ASR-1.7B入门必看:Qwen3-ASR-1.7B与Qwen3-Chat模型协同工作流

Qwen3-ASR-1.7B入门必看:Qwen3-ASR-1.7B与Qwen3-Chat模型协同工作流 1. 语音识别新标杆:Qwen3-ASR-1.7B介绍 Qwen3-ASR-1.7B是新一代高精度语音识别系统,相比前代0.6B版本有了质的飞跃。这个1.7B参数量的模型能够处理各种复杂语音场景&…

2026/5/17 3:45:39 阅读更多 →
QAnything开发环境搭建:VSCode配置C/C++扩展全攻略

QAnything开发环境搭建:VSCode配置C/C++扩展全攻略

QAnything开发环境搭建:VSCode配置C/C扩展全攻略 如果你正准备参与QAnything的C/C模块开发,或者想深入了解这个开源RAG系统的底层实现,那么一个顺手的开发环境就是你的第一道门槛。今天我就来手把手带你配置VSCode的C/C开发环境,…

2026/7/4 11:08:56 阅读更多 →

最新新闻

AI技术决策指南:从信息过载到可执行落地

AI技术决策指南:从信息过载到可执行落地

1. 项目概述:一份AI领域 Newsletter 的真实价值拆解“This AI newsletter is all you need #60”——看到这个标题,你第一反应可能是:又一份泛泛而谈的AI资讯合集?点开就看三行摘要、五个链接、一个ChatGPT新插件预告,…

2026/7/4 22:46:48 阅读更多 →
TC78H660FTG与PIC18F86J10的直流电机驱动优化方案

TC78H660FTG与PIC18F86J10的直流电机驱动优化方案

1. 项目背景与核心器件选型在工业自动化和消费电子领域,直流电机驱动系统的效率优化一直是工程师面临的关键挑战。TC78H660FTG作为东芝新一代H桥驱动器,与Microchip的PIC18F86J10微控制器组合,为解决这一问题提供了高性价比方案。TC78H660FTG…

2026/7/4 22:46:48 阅读更多 →
AntiDupl终极指南:三步快速清理重复照片,释放磁盘空间

AntiDupl终极指南:三步快速清理重复照片,释放磁盘空间

AntiDupl终极指南:三步快速清理重复照片,释放磁盘空间 【免费下载链接】AntiDupl A program to search similar and defect pictures on the disk 项目地址: https://gitcode.com/gh_mirrors/an/AntiDupl AntiDupl是一款专业的开源图片去重工具&a…

2026/7/4 22:42:44 阅读更多 →
基于STM32和MAX9744的高效D类音频放大器设计

基于STM32和MAX9744的高效D类音频放大器设计

1. 项目背景与核心器件选型在音频系统设计中,功率放大环节直接决定了最终的声音表现。传统AB类放大器虽然音质优秀,但效率普遍低于50%,导致发热严重、能耗高。而D类放大器采用PWM调制技术,理论效率可达90%以上,特别适合…

2026/7/4 22:40:42 阅读更多 →
Java毕设选题推荐:景观设计作品展示与项目管理系统的设计与实现 基于 SpringBoot 的园林素材资源管理系统【附源码、mysql、文档、调试+代码讲解+全bao等】

Java毕设选题推荐:景观设计作品展示与项目管理系统的设计与实现 基于 SpringBoot 的园林素材资源管理系统【附源码、mysql、文档、调试+代码讲解+全bao等】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/4 22:38:41 阅读更多 →
Halcon图像滤波实战:均值、中值与高斯滤波的噪声抑制与边缘保护权衡

Halcon图像滤波实战:均值、中值与高斯滤波的噪声抑制与边缘保护权衡

1. 工业视觉中的图像噪声挑战在工业视觉检测项目中,图像噪声就像不请自来的"第三者",总是干扰着我们对产品缺陷的准确判断。我处理过一个典型的案例:某汽车零部件生产线需要检测金属表面的微小划痕,但采集到的图像总是布…

2026/7/4 22:36:38 阅读更多 →

日新闻

Memcached 1.6.43 发布:关键安全修复版本,多项问题得到解决

Memcached 1.6.43 发布:关键安全修复版本,多项问题得到解决

Memcached 1.6.43 正式发布,这是一个关键的安全修复版本,修复了多个方面的问题,还对部分功能进行了优化。 安全修复亮点 此次发布在安全修复上表现突出。binprot 避免了项目引用计数溢出,mcmc 因安全问题提升了上游版本号&#xf…

2026/7/4 0:04:29 阅读更多 →
终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案

终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案

终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案 【免费下载链接】HMCL A Minecraft Launcher which is multi-functional, cross-platform and popular 项目地址: https://gitcode.com/gh_mirrors/hm/HMCL HMCL(Hello Minecraft! Lau…

2026/7/4 0:06:29 阅读更多 →
KMX63与PIC18F66K40在嵌入式HMI中的硬件协同与低功耗设计

KMX63与PIC18F66K40在嵌入式HMI中的硬件协同与低功耗设计

1. KMX63与PIC18F66K40的硬件协同架构解析KMX63作为一款三轴加速度计和磁力计组合传感器,与PIC18F66K40微控制器的搭配堪称嵌入式HMI开发的黄金组合。这套硬件组合的核心优势在于KMX63提供的高精度运动感知能力与PIC18F66K40强大的信号处理能力形成了完美互补。KMX6…

2026/7/4 0:06:29 阅读更多 →

周新闻

月新闻