關于前端頁面上傳圖片檢測

  1. 依賴于前文,linux系統上部署yolo識別圖片,遠程宿主機訪問docker全流程(https://blog.csdn.net/yanzhuang521967/article/details/148777650?spm=1001.2014.3001.5501)
    fastapi把端口暴露出來

  2. 后端代碼

from fastapi import FastAPI, UploadFile, File, HTTPException, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse, StreamingResponse, Response
from starlette.responses import RedirectResponse
from urllib.parse import urlparse
from ultralytics import YOLO
import os
import json
from pathlib import Path
from fastapi.staticfiles import StaticFiles
import logging
import io
from PIL import Image# 初始化應用
app = FastAPI()# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)# 靜態文件服務
app.mount("/output-predict", StaticFiles(directory="/usr/src/output/predict"), name="output-predict")
app.mount("/output-labels", StaticFiles(directory="/usr/src/output/predict/labels"), name="output-labels")# CORS配置
app.add_middleware(CORSMiddleware,allow_origins=["*"],allow_credentials=True,allow_methods=["*"],allow_headers=["*"],expose_headers=["*"]
)# 修復后的協議轉換中間件
@app.middleware("http")
async def protocol_converter(request: Request, call_next):try:# 處理HTTPS轉HTTP(如果需要)if request.url.scheme == "https":url = str(request.url).replace("https://", "http://", 1)logger.info(f"Converting HTTPS to HTTP: {url}")scope = request.scopescope["scheme"] = "http"headers = []for k, v in scope["headers"]:if k == b"referer":headers.append((k, v.replace(b"https://", b"http://")))else:headers.append((k, v))scope["headers"] = headersresponse = await call_next(request)# 不處理流式響應和重定向if isinstance(response, (StreamingResponse, RedirectResponse)):return response# 獲取響應體(兼容新舊版本)if hasattr(response, "body_iterator"):# 處理StreamingResponsebody = b"".join([chunk async for chunk in response.body_iterator])else:# 普通響應body = await response.body()# 替換內容中的HTTPS鏈接(如果需要)if body and b"https://" in body:body = body.replace(b"https://", b"http://")logger.debug("Replaced HTTPS links in response body")return Response(content=body,status_code=response.status_code,media_type=response.media_type,headers=dict(response.headers))except Exception as e:logger.error(f"Protocol converter error: {str(e)}", exc_info=True)raise HTTPException(status_code=500, detail="Internal server error")# 安全頭中間件
@app.middleware("http")
async def security_headers(request: Request, call_next):response = await call_next(request)response.headers.update({"Access-Control-Allow-Private-Network": "true","Cross-Origin-Resource-Policy": "cross-origin","X-Content-Type-Options": "nosniff"})return response# 初始化模型和目錄
model = YOLO("/ultralytics/yolo11n.pt")
output_base = Path("/usr/src/output")
predict_dir = output_base / "predict"
(predict_dir / "labels").mkdir(parents=True, exist_ok=True)# 輔助函數
async def save_upload_file(file: UploadFile) -> str:"""保存上傳文件到臨時位置"""temp_path = f"/tmp/{file.filename}"try:with open(temp_path, "wb") as f:content = await file.read()f.write(content)return temp_pathexcept Exception as e:logger.error(f"File save failed: {str(e)}")raise HTTPException(500, "File upload failed")# API端點
@app.post("/predict")
async def predict(request: Request, file: UploadFile = File(...)):temp_path = Nonetry:# 1. 保存文件temp_path = await save_upload_file(file)# 2. 運行預測results = model.predict(source=temp_path,project=str(predict_dir),name="",save=True,save_txt=True,save_conf=True,exist_ok=True)# 3. 準備結果(使用新的to_json()方法)file_stem = Path(file.filename).stembase_url = str(request.base_url).replace("https://", "http://")json_result = {"filename": file.filename,"detections": json.loads(results[0].to_json()),  # 使用to_json()替代tojson()"image_path": f"{base_url}output-predict/{file.filename}","label_path": f"{base_url}output-labels/{file_stem}.txt","speed": {"preprocess": results[0].speed["preprocess"],"inference": results[0].speed["inference"],"postprocess": results[0].speed["postprocess"]}}# 4. 保存JSONjson_path = predict_dir / "labels" / f"{file_stem}.json"with open(json_path, "w") as f:json.dump(json_result, f, indent=2)return JSONResponse({"status": "success","data": json_result,"debug": {"original_protocol": request.url.scheme,"processed_protocol": "http"}})except Exception as e:logger.error(f"Prediction failed: {str(e)}", exc_info=True)raise HTTPException(status_code=500, detail=str(e))finally:if temp_path and os.path.exists(temp_path):os.remove(temp_path)# 健康檢查端點
@app.get("/health")
async def health_check():return {"status": "healthy", "protocol": "http"}# 協議檢查端點
@app.get("/check-protocol")
async def check_protocol(request: Request):return {"client_protocol": request.url.scheme,"server_protocol": "http","headers": dict(request.headers)}
  1. 前端代碼
   <!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><!-- 在HTML的<head>中添加 --><title>YOLOv8 圖像檢測系統</title><style>body {font-family: Arial, sans-serif;max-width: 1200px;margin: 0 auto;padding: 20px;line-height: 1.6;}.upload-container {text-align: center;margin-bottom: 30px;}.upload-area {border: 2px dashed #ccc;border-radius: 8px;padding: 40px;margin: 20px 0;cursor: pointer;transition: all 0.3s;}.upload-area:hover {border-color: #4CAF50;background-color: #f9f9f9;}#fileInput {display: none;}button {background-color: #4CAF50;color: white;border: none;padding: 10px 20px;border-radius: 4px;cursor: pointer;font-size: 16px;transition: background 0.3s;}button:hover {background-color: #45a049;}button:disabled {background-color: #cccccc;cursor: not-allowed;}.status {margin: 20px 0;padding: 15px;border-radius: 4px;display: none;}.loading {background-color: #e8f5e9;color: #2e7d32;}.error {background-color: #ffebee;color: #f44336;}.image-container {display: flex;flex-wrap: wrap;gap: 20px;margin-top: 30px;}.image-box {flex: 1;min-width: 300px;margin-bottom: 20px;}.image-box img {max-width: 100%;border-radius: 4px;box-shadow: 0 2px 10px rgba(0,0,0,0.1);}.results-panel {margin-top: 30px;padding: 20px;background-color: #f5f5f5;border-radius: 8px;}pre {background-color: #eee;padding: 15px;border-radius: 4px;overflow-x: auto;}.spinner {border: 4px solid rgba(0,0,0,0.1);border-radius: 50%;border-top: 4px solid #4CAF50;width: 40px;height: 40px;animation: spin 1s linear infinite;margin: 20px auto;}@keyframes spin {0% { transform: rotate(0deg); }100% { transform: rotate(360deg); }}</style>
</head>
<body><div class="upload-container"><h1>YOLOv8 圖像檢測系統</h1><div class="upload-area" id="dropZone"><p>點擊或拖拽圖片到此處上傳</p><input type="file" id="fileInput" accept="image/*"></div><button id="detectBtn" disabled>開始檢測</button><div id="loadingStatus" class="status loading"><div class="spinner"></div><p>正在處理圖像,請稍候...</p></div><div id="errorStatus" class="status error"><h3>檢測失敗</h3><p id="errorMessage"></p></div></div><div class="image-container"><div class="image-box"><h3>原始圖片</h3><img id="preview" style="display: none;"></div><div class="image-box"><h3>檢測結果</h3><img id="result" style="display: none;"></div></div><div class="results-panel" id="resultsPanel" style="display: none;"><h3>檢測結果數據</h3><pre id="jsonData"></pre></div><script>// DOM元素const fileInput = document.getElementById('fileInput');const dropZone = document.getElementById('dropZone');const detectBtn = document.getElementById('detectBtn');const preview = document.getElementById('preview');const result = document.getElementById('result');const loadingStatus = document.getElementById('loadingStatus');const errorStatus = document.getElementById('errorStatus');const errorMessage = document.getElementById('errorMessage');const resultsPanel = document.getElementById('resultsPanel');const jsonData = document.getElementById('jsonData');// 當前處理的文件let currentFile = null;// 文件選擇處理fileInput.addEventListener('change', handleFileSelect);dropZone.addEventListener('click', () => fileInput.click());// 拖放功能dropZone.addEventListener('dragover', (e) => {e.preventDefault();dropZone.style.borderColor = '#4CAF50';dropZone.style.backgroundColor = '#f0fff0';});dropZone.addEventListener('dragleave', () => {dropZone.style.borderColor = '#ccc';dropZone.style.backgroundColor = '';});dropZone.addEventListener('drop', (e) => {e.preventDefault();dropZone.style.borderColor = '#ccc';dropZone.style.backgroundColor = '';if (e.dataTransfer.files.length) {fileInput.files = e.dataTransfer.files;handleFileSelect({ target: fileInput });}});// 檢測按鈕點擊detectBtn.addEventListener('click', startDetection);function handleFileSelect(event) {const file = event.target.files[0];if (file && file.type.match('image.*')) {currentFile = file;const reader = new FileReader();reader.onload = (e) => {preview.src = e.target.result;preview.style.display = 'block';detectBtn.disabled = false;// 重置狀態result.style.display = 'none';resultsPanel.style.display = 'none';errorStatus.style.display = 'none';};reader.readAsDataURL(file);}}async function startDetection() {if (!currentFile) return;// 顯示加載狀態loadingStatus.style.display = 'block';errorStatus.style.display = 'none';detectBtn.disabled = true;try {// 1. 上傳圖片進行預測const formData = new FormData();formData.append('file', currentFile);const response = await fetch('http://192.168.0.100:34567/predict', {method: 'POST',mode: 'cors', // 確保這是cors而不是no-corsbody: formData});if (!response.ok) {const error = await response.text();throw new Error(error || `服務器錯誤: ${response.status}`);}const resultData = await response.json();// 2. 顯示處理后的圖片const filename = currentFile.name.split('.')[0];result.src = `http://192.168.0.100:34567/output-predict/predict/${filename}.jpg?t=${Date.now()}`;result.style.display = 'block';// 3. 顯示JSON數據jsonData.textContent = JSON.stringify(resultData, null, 2);resultsPanel.style.display = 'block';} catch (error) {console.error('檢測失敗:', error);errorMessage.textContent = error.message;errorStatus.style.display = 'block';} finally {loadingStatus.style.display = 'none';detectBtn.disabled = false;}}</script>
</body>
</html>

在這里插入圖片描述
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/88969.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/88969.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/88969.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

第十三章---軟件工程過程管理

僅供參考 文章目錄 一、Gantt圖是做什么的。二、軟件配置的概念 一、Gantt圖是做什么的。 Gantt 圖&#xff08;甘特圖&#xff09;是軟件項目管理中用于進度安排和可視化管理的重要工具&#xff0c;主要用于展示任務的時間安排、進度狀態及任務之間的依賴關系 Gantt 圖是一種…

多模態大語言模型arxiv論文略讀(140)

SemiHVision: Enhancing Medical Multimodal Models with a Semi-Human Annotated Dataset and Fine-Tuned Instruction Generation ?? 論文標題&#xff1a;SemiHVision: Enhancing Medical Multimodal Models with a Semi-Human Annotated Dataset and Fine-Tuned Instruc…

模型預測控制專題:無差拍預測電流控制

前言&#xff1a; 為了進一步深入探索電機控制這個領域&#xff0c;找到了一些志同道合的同學一起來進行知識的分享。最近群里投票后續更新內容&#xff0c;票數最多的方向就是模型預測控制&#xff1b;無論這個方向目前是否還是很火&#xff0c;至少應大家需求&#xff0c;工…

Youtube雙塔模型

1. 引言 在大規模推薦系統中&#xff0c;如何從海量候選物品中高效檢索出用戶可能感興趣的物品是一個關鍵問題。傳統的矩陣分解方法在處理稀疏數據和長尾分布時面臨挑戰。本文介紹了一種基于雙塔神經網絡的建模框架&#xff0c;通過采樣偏差校正技術提升推薦質量&#xff0c;并…

.net8創建tcp服務接收數據通過websocket廣播

注冊TCP服務器 注冊WebSocket中間件 using System.Net; using System.Net.Sockets; using System.Text; using System.Text.Json; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.SignalR.Client; using Microsoft.AspNet…

閱讀服務使用示例(HarmonyOS Reader Kit)

閱讀服務使用示例&#xff08;HarmonyOS Reader Kit&#xff09; Reader Kit到底能干啥&#xff1f; 第一次搞電子書閱讀器&#xff0c;真以為就是“讀txt顯示出來”這么簡單&#xff0c;結果各種格式、排版、翻頁動效、目錄跳轉……全是坑。還好有Reader Kit&#xff0c;救了…

ASP.NET Core Web API 實現 JWT 身份驗證

在ASP.NET Core WebApi中使用標識框架&#xff08;Identity)-CSDN博客 因為一般需要和標識框架一起使用,建議先查看標識框架用法 一.為什么需要JWT 我們的系統需要實現認證,即服務端需要知道登錄進來的客戶端的身份,管理員有管理員的權限,普通用戶有普通用戶的權限. 但服務…

優化Cereal宏 一行聲明序列化函數

Cereal序列化庫中宏遞歸展開的優化方案及技術解析 未優化&#xff1a;參考nlohmann json設計Cereal宏 一行聲明序列化函數 宏實現 #include <cereal/cereal.hpp>// 強制二次展開 #define CEREAL_EXPAND( x ) x// 獲取宏參數的數量&#xff0c;對應的CEREAL_PASTEn宏NAME…

14-C#的彈出的窗口輸入與輸出

C#的彈出的窗口輸入與輸出 1.文件名輸入 string fileName Interaction.InputBox("輸入保存的文件名", "保存");2.彈窗信息輸出 MessageBox.Show("請選擇輪詢!", "Error", MessageBoxButtons.OK);catch (Exception ex){MessageBox.S…

多模態大語言模型arxiv論文略讀(141)

Mini-InternVL: A Flexible-Transfer Pocket Multimodal Model with 5% Parameters and 90% Performance ?? 論文標題&#xff1a;Mini-InternVL: A Flexible-Transfer Pocket Multimodal Model with 5% Parameters and 90% Performance ?? 論文作者&#xff1a;Zhangwei …

VScode使用usb轉網口遠程開發rk3588

我使用的是魯班貓的板&#xff0c;只有一個網口&#xff0c;需要接雷達&#xff0c;因此另外弄了一個usb轉網口來連接電腦開發。 在使用vscode或MobaXterm連接板子時&#xff0c;使用主機名與用戶名來連接&#xff1a; ssh catlubancat rk那邊就直接插入usb轉網口以及網線&a…

AUTOSAR圖解==>AUTOSAR_AP_EXP_SOVD

AUTOSAR服務導向車輛診斷詳解 面向現代化車輛架構的診斷方案 目錄 1. 引言 1.1 ASAM SOVD簡介1.2 SOVD產生的動機 2. SOVD參考架構 2.1 SOVD網關2.2 診斷管理器2.3 SOVD到UDS轉換2.4 后端連接 3. SOVD用例 3.1 SOVD和UDS的共同用例3.2 SOVD特定用例 3.2.1 訪問權限3.2.2 軟件更…

第八講:STL簡介

1. 什么是STL STL(standard template libaray-標準模板庫)&#xff1a;是C標準庫的重要組成部分&#xff0c;不僅是一個可復的 組件庫&#xff0c;而且是一個包羅數據結構與算法的軟件框架。 2. STL的版本 a. 原始版本 Alexander Stepanov、Meng Lee 在惠普實驗室完成的原始版本…

高彈性、高可靠!騰訊云 TDMQ RabbitMQ Serverless 版全新發布

導語 2025年6月起&#xff0c;騰訊云 TDMQ RabbitMQ 版正式推出 Serverless 版本&#xff0c;該版本基于自研的存算分離架構&#xff0c;兼容 AMQP 0-9-1 協議和開源 RabbitMQ 的各個組件與概念&#xff0c;且能夠規避開源版本固有的不抗消息堆積、腦裂等穩定性缺陷&#xff0…

Linux 內存調優之 BPF 分析用戶態小內存分配

寫在前面 博文內容為 使用 BPF 工具跟蹤 Linux 用戶態小內存分配(brk,sbrk)理解不足小伙伴幫忙指正 ??,生活加油我看遠山,遠山悲憫 持續分享技術干貨,感興趣小伙伴可以關注下 _ brk 內存分配簡單概述 一般來說,應用程序的數據存放于堆內存中,堆內存通過brk(2)系統調用進…

心理測評app心理測試系統框架設計

一、邏輯分析 用戶管理邏輯 新用戶注冊&#xff1a;需要收集用戶的基本信息&#xff0c;如用戶名、密碼、郵箱等&#xff0c;并且要對輸入信息進行合法性校驗&#xff0c;確保信息完整且符合格式要求。同時&#xff0c;為每個新用戶生成唯一的標識符&#xff0c;方便后續數據管…

配置有nvlink的H20A800使用pytorch報錯

背景 裝有nvlink的h20機器上配置好驅動和cuda之后使用pytorch報錯 A800機器同樣 (pytorch2.4) rootxx-dev-H20:~# python Python 3.12.0 | packaged by Anaconda, Inc. | (main, Oct 2 2023, 17:29:18) [GCC 11.2.0] on linux Type “help”, “copyright”, “credits” or …

sql的語句執行過程

第一步&#xff1a;客戶端把語句發給服務器端執行 當我們在客戶端執行SQL語句時&#xff0c;客戶端會把這條SQL語句發送給服務器端&#xff0c;讓服務器端的進程來處理這語句。也就是說&#xff0c;Oracle 客戶端是不會做任何的操作&#xff0c;他的主要任務就是把客戶端產生的…

深度學習-分類

深度學習-分類方式 &#xff08;重點&#xff09;一、按數據類型與處理邏輯分類1. 序列數據&#xff08;時序/順序相關&#xff09;2. 網格狀數據&#xff08;空間相關&#xff09;3. 圖結構數據&#xff08;非歐幾里得結構&#xff09;4. 其他特殊類型數據 &#xff08;重點&a…

C語言---常見的字符函數和字符串函數介紹

目錄 前言 1 字符分類函數 2 字符轉換函數 3 strlen的使用和模擬實現 3.1 strlen的模擬實現 4 strcpy的使用和模擬實現 4.1 strcpy的模擬實現 5 strcat的使用和模擬實現 5.1 strcat的模擬實現 6 strcmp的使用和模擬實現 6.1 strcmp的模擬實現 7 strncpy函數的使用…