泰安网站制作服务松江php网站开发培训
泰安网站制作服务,松江php网站开发培训,wordpress 截取字符串,宝塔软件怎么做网站实时手机检测-通用模型与Vue3前端框架集成方案 将AI能力无缝融入Web应用#xff0c;让前端开发者也能轻松构建智能应用 1. 项目背景与价值
最近在做一个电商项目的商品审核功能#xff0c;需要自动检测用户上传的商品图片中是否包含手机。传统方案要么依赖人工审核效率低下 } .preview-area { margin-top: 20px; } .image-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 15px; margin: 15px 0; } .image-item { display: flex; flex-direction: column; align-items: center; border: 1px solid #eee; padding: 10px; border-radius: 4px; } .image-item img { width: 100%; height: 100px; object-fit: cover; margin-bottom: 8px; } .image-name { font-size: 12px; margin-bottom: 8px; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; max-width: 100%; } /style这个组件提供了良好的用户体验支持多选、预览、删除等操作为后续的检测流程打下基础。6. 检测结果展示组件检测完成后需要以直观的方式展示结果包括检测框、置信度、手机类型等信息template div classresult-container h3检测结果/h3 div v-ifloading classloading el-icon classis-loadingLoading //el-icon 正在检测中... /div div v-else-iferror classerror el-alert :titleerror typeerror / /div div v-else-ifresults.length classresults div v-for(result, index) in results :keyindex classresult-item div classresult-image img :srcresult.imageUrl alt检测结果 / div v-for(box, boxIndex) in result.detections :keyboxIndex classdetection-box :style{ left: ${box.bbox[0]}px, top: ${box.bbox[1]}px, width: ${box.bbox[2]}px, height: ${box.bbox[3]}px } span classconfidence{{ (box.confidence * 100).toFixed(1) }}%/span /div /div div classresult-info h4检测详情/h4 el-table :dataresult.detections sizesmall el-table-column proplabel label手机类型 / el-table-column label置信度 template #default{ row } {{ (row.confidence * 100).toFixed(1) }}% /template /el-table-column el-table-column label位置 template #default{ row } [{{ row.bbox[0] }}, {{ row.bbox[1] }}, {{ row.bbox[2] }}, {{ row.bbox[3] }}] /template /el-table-column /el-table /div /div /div div v-else classempty el-empty description暂无检测结果 / /div /div /template script setup import { ref, watch } from vue import { Loading } from element-plus/icons-vue const props defineProps({ results: { type: Array, default: () [] }, loading: { type: Boolean, default: false }, error: { type: String, default: } }) // 生成带检测框的图片预览 const resultsWithPreview ref([]) watch(() props.results, (newResults) { resultsWithPreview.value newResults.map(result ({ ...result, imageUrl: URL.createObjectURL(result.imageFile) })) }, { immediate: true }) /script style scoped .result-container { padding: 20px; } .loading { display: flex; align-items: center; justify-content: center; padding: 40px; color: #666; } .result-item { margin-bottom: 30px; border: 1px solid #eee; padding: 15px; border-radius: 8px; } .result-image { position: relative; display: inline-block; margin-right: 20px; } .result-image img { max-width: 400px; max-height: 300px; display: block; } .detection-box { position: absolute; border: 2px solid #409eff; background-color: rgba(64, 158, 255, 0.1); } .confidence { position: absolute; top: -25px; left: 0; background-color: #409eff; color: white; padding: 2px 6px; font-size: 12px; border-radius: 2px; } .result-info { display: inline-block; vertical-align: top; max-width: 400px; } /style这个组件不仅展示检测结果还用可视化方式标注出检测到的手机位置让结果一目了然。7. 实时检测功能实现对于需要实时处理的场景比如监控视频流我们实现WebSocket实时检测template div classrealtime-container h3实时手机检测/h3 div classvideo-area video refvideoRef autoplay playsinline classvideo-element/video canvas refcanvasRef classoverlay-canvas/canvas /div div classcontrols el-button :typeisStreaming ? danger : primary clicktoggleStreaming {{ isStreaming ? 停止检测 : 开始检测 }} /el-button el-select v-modelselectedDevice placeholder选择摄像头 el-option v-fordevice in videoDevices :keydevice.deviceId :labeldevice.label :valuedevice.deviceId / /el-select /div div classstats v-ifisStreaming el-tag检测频率: {{ fps }} FPS/el-tag el-tag延迟: {{ latency }}ms/el-tag el-tag检测到手机: {{ phoneCount }}部/el-tag /div /div /template script setup import { ref, onMounted, onUnmounted } from vue import { createRealtimeConnection } from ../api/detection const videoRef ref(null) const canvasRef ref(null) const isStreaming ref(false) const videoDevices ref([]) const selectedDevice ref() const fps ref(0) const latency ref(0) const phoneCount ref(0) let wsConnection null let frameInterval null let lastFrameTime 0 // 获取摄像头设备列表 const getVideoDevices async () { try { const devices await navigator.mediaDevices.enumerateDevices() videoDevices.value devices.filter(device device.kind videoinput) if (videoDevices.value.length 0) { selectedDevice.value videoDevices.value[0].deviceId } } catch (error) { console.error(获取设备列表失败:, error) } } // 初始化摄像头 const initCamera async () { try { const stream await navigator.mediaDevices.getUserMedia({ video: { deviceId: selectedDevice.value ? { exact: selectedDevice.value } : undefined, width: { ideal: 640 }, height: { ideal: 480 } } }) if (videoRef.value) { videoRef.value.srcObject stream } return stream } catch (error) { console.error(摄像头初始化失败:, error) throw error } } // 发送帧数据进行检测 const sendFrameForDetection () { if (!videoRef.value || !canvasRef.value || !wsConnection) return const video videoRef.value const canvas canvasRef.value const ctx canvas.getContext(2d) // 设置canvas尺寸与视频一致 if (canvas.width ! video.videoWidth || canvas.height ! video.videoHeight) { canvas.width video.videoWidth canvas.height video.videoHeight } // 绘制当前帧到canvas ctx.drawImage(video, 0, 0, canvas.width, canvas.height) // 转换为Blob发送 canvas.toBlob(async (blob) { const startTime Date.now() try { wsConnection.send(blob) // 计算FPS const now Date.now() if (lastFrameTime 0) { const currentFps 1000 / (now - lastFrameTime) fps.value Math.round(currentFps * 10) / 10 } lastFrameTime now } catch (error) { console.error(发送帧数据失败:, error) } }, image/jpeg, 0.8) } // 处理检测结果 const handleDetectionResult (data) { const processingTime Date.now() - data.timestamp latency.value processingTime phoneCount.value data.detections.length // 在canvas上绘制检测结果 drawDetections(data.detections) } // 绘制检测框 const drawDetections (detections) { const canvas canvasRef.value const ctx canvas.getContext(2d) // 清空之前的绘制 ctx.clearRect(0, 0, canvas.width, canvas.height) // 绘制新的检测框 detections.forEach(det { const [x, y, width, height] det.bbox // 绘制边界框 ctx.strokeStyle #409eff ctx.lineWidth 2 ctx.strokeRect(x, y, width, height) // 绘制标签背景 ctx.fillStyle #409eff const text ${det.label} (${(det.confidence * 100).toFixed(1)}%) const textWidth ctx.measureText(text).width ctx.fillRect(x, y - 20, textWidth 10, 20) // 绘制标签文字 ctx.fillStyle white ctx.font 12px Arial ctx.fillText(text, x 5, y - 5) }) } // 切换检测状态 const toggleStreaming async () { if (isStreaming.value) { // 停止检测 isStreaming.value false if (frameInterval) { clearInterval(frameInterval) frameInterval null } if (wsConnection) { wsConnection.close() wsConnection null } } else { // 开始检测 try { const stream await initCamera() isStreaming.value true // 创建WebSocket连接 wsConnection createRealtimeConnection( handleDetectionResult, (error) { console.error(WebSocket错误:, error) isStreaming.value false } ) // 每100毫秒发送一帧约10FPS frameInterval setInterval(sendFrameForDetection, 100) } catch (error) { console.error(启动检测失败:, error) isStreaming.value false } } } onMounted(() { getVideoDevices() }) onUnmounted(() { if (isStreaming.value) { if (frameInterval) clearInterval(frameInterval) if (wsConnection) wsConnection.close() } }) /script style scoped .realtime-container { padding: 20px; } .video-area { position: relative; width: 640px; height: 480px; margin-bottom: 20px; } .video-element, .overlay-canvas { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } .overlay-canvas { pointer-events: none; } .controls { margin-bottom: 20px; } .controls .el-select { margin-left: 10px; width: 200px; } .stats .el-tag { margin-right: 10px; } /style实时检测功能让用户可以直接使用摄像头进行手机检测适合安防监控、实时分析等场景。8. 性能优化建议在实际使用中我们总结了一些性能优化经验图片压缩处理在上传前对图片进行适当压缩减少传输数据量// 在utils/image.js中添加压缩函数 export const compressImage (file, maxWidth 1024, quality 0.8) { return new Promise((resolve) { const reader new FileReader() reader.onload (e) { const img new Image() img.onload () { const canvas document.createElement(canvas) let width img.width let height img.height if (width maxWidth) { height (height * maxWidth) / width width maxWidth } canvas.width width canvas.height height const ctx canvas.getContext(2d) ctx.drawImage(img, 0, 0, width, height) canvas.toBlob( (blob) resolve(new File([blob], file.name, { type: image/jpeg })), image/jpeg, quality ) } img.src e.target.result } reader.readAsDataURL(file) }) }请求队列管理对于批量检测实现请求队列控制并发数export const createRequestQueue (concurrency 3) { let running 0 const queue [] const runNext () { if (running concurrency || queue.length 0) return running const { task, resolve, reject } queue.shift() task() .then(resolve) .catch(reject) .finally(() { running-- runNext() }) } return { add: (task) { return new Promise((resolve, reject) { queue.push({ task, resolve, reject }) runNext() }) } } } // 使用示例 const detectionQueue createRequestQueue(2) // 最大并发2 const processBatch async (imageFiles) { const results [] for (const file of imageFiles) { const result await detectionQueue.add(() detectPhone(file)) results.push(result) } return results }缓存策略对相同的图片进行缓存避免重复检测const detectionCache new Map() export const detectWithCache async (imageFile) { // 生成文件指纹简单使用文件大小最后修改时间 const fingerprint ${imageFile.size}-${imageFile.lastModified} if (detectionCache.has(fingerprint)) { return detectionCache.get(fingerprint) } const result await detectPhone(imageFile) detectionCache.set(fingerprint, result) return result }9. 项目总结实际集成下来Vue3的响应式系统和组合式API让AI功能的集成变得非常顺畅。组件化的设计让代码结构清晰维护起来也方便。特别是基于TypeScript的类型支持让API调用更加安全可靠。性能方面前端的优化手段确实能明显提升用户体验。图片压缩减少了80%以上的传输数据量请求队列避免了服务器过载缓存策略更是大幅减少了重复检测的开销。这些优化让整个应用运行更加流畅稳定。从开发体验来看这种前后端分离的架构让团队协作更加高效。前端开发者可以专注于界面和交互后端开发者可以专注于模型优化和性能提升。双方通过清晰的API接口进行协作大大提升了开发效率。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。