欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

yolov5使用flask部署至前端實(shí)現(xiàn)照片\視頻識(shí)別功能

 更新時(shí)間:2024年09月28日 09:36:28   作者:代碼與CPython  
初學(xué)者在使用YOLO和Flask構(gòu)建應(yīng)用時(shí),往往需要實(shí)現(xiàn)上傳圖片和視頻的識(shí)別功能,本文介紹了如何在Flask框架中實(shí)現(xiàn)這一功能,包括文件上傳、圖片放大查看、視頻識(shí)別以及識(shí)別后的文件下載,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

初學(xué)yolo flask時(shí),需要此功能,Csdn、Github、B站找到許多代碼,效果并不滿意。

近期,再度嘗試,實(shí)現(xiàn)簡(jiǎn)單功能。

實(shí)現(xiàn)功能:

上傳圖片并識(shí)別,可以點(diǎn)擊圖片放大查看

上傳視頻并識(shí)別

識(shí)別后的文件下載功能

效果圖如下

文件結(jié)構(gòu)如下:

project/
  static/

  空

  templates/
    index.html
    
  app.py

相關(guān)代碼:

app.py

import cv2
import numpy as np
import torch
from flask import Flask, request, jsonify, render_template
import base64
import os
from datetime import datetime

app = Flask(__name__)

# 全局變量:模型
model = None

# 提前加載模型
def load_model():
    global model
    model = torch.hub.load('', 'custom', path='yolov5s.pt', source='local')

# 路由處理圖片檢測(cè)請(qǐng)求
@app.route('/predict_image', methods=['POST'])
def predict_image():
    global model

    # 獲取圖像文件
    file = request.files['image']
    # 讀取圖像數(shù)據(jù)并轉(zhuǎn)換為RGB格式
    image_data = file.read()
    nparr = np.frombuffer(image_data, np.uint8)
    image = cv2.imdecode(nparr, cv2.IMREAD_UNCHANGED)

    results = model(image)

    image = results.render()[0]

    # 將圖像轉(zhuǎn)換為 base64 編碼的字符串
    _, buffer = cv2.imencode('.png', image)
    image_str = base64.b64encode(buffer).decode('utf-8')

    # 獲取當(dāng)前時(shí)間,并將其格式化為字符串
    current_time = datetime.now().strftime('%Y%m%d%H%M%S')
    # 構(gòu)建保存路徑
    save_dir = 'static'
    if not os.path.exists(save_dir):
        os.makedirs(save_dir)
    filename, extension = os.path.splitext(file.filename)  # 獲取上傳文件的文件名和擴(kuò)展名
    save_filename = f'{filename}_{current_time}{extension}'
    save_path = os.path.join(save_dir, save_filename)
    cv2.imwrite(save_path, image)

    return jsonify({'image': image_str})

# 函數(shù)用于在視頻幀上繪制檢測(cè)結(jié)果
def detect_objects(frame, model):
    results = model(frame)
    detections = results.xyxy[0].cpu().numpy()  # 獲取檢測(cè)結(jié)果

    # 在幀上繪制檢測(cè)結(jié)果
    for det in detections:
        # 獲取邊界框信息
        x1, y1, x2, y2, conf, class_id = det[:6]

        # 在幀上繪制邊界框
        cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)

        # 在幀上繪制類(lèi)別和置信度
        label = f'{model.names[int(class_id)]} {conf:.2f}'
        cv2.putText(frame, label, (int(x1), int(y1) - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
    return frame

# 路由處理視頻檢測(cè)請(qǐng)求

@app.route("/predict_video", methods=["POST"])
def predict_video():
    global model

    # 從請(qǐng)求中獲取視頻文件
    video_file = request.files["video"]
    # 保存視頻到臨時(shí)文件
    temp_video_path = "temp_video.mp4"
    video_file.save(temp_video_path)

    # 逐幀讀取視頻
    video = cv2.VideoCapture(temp_video_path)

    # 獲取視頻的幀率和尺寸
    fps = video.get(cv2.CAP_PROP_FPS)
    width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))

    # 視頻寫(xiě)入對(duì)象
    output_video_filename = f"output_video_{datetime.now().strftime('%Y%m%d%H%M%S')}.mp4"
    output_video_path = os.path.join("static", output_video_filename)
    fourcc = cv2.VideoWriter_fourcc(*"avc1")
    out_video = cv2.VideoWriter(output_video_path, fourcc, fps, (width, height))

    # 逐幀處理視頻并進(jìn)行目標(biāo)檢測(cè)
    while True:
        ret, frame = video.read()
        if not ret:
            break

        # 進(jìn)行目標(biāo)檢測(cè)
        detection_result = detect_objects(frame, model)

        # 將處理后的幀寫(xiě)入輸出視頻
        out_video.write(detection_result)

    # 釋放視頻對(duì)象
    video.release()
    out_video.release()

    return jsonify({"output_video_path": output_video_filename})

@app.route('/')
def index():
    return render_template('index.html')

# 初始加載模型
load_model()

if __name__ == '__main__':
    app.run(debug=True)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Object Detection</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
            background-color: #f3f3f3;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            flex-direction: column;
        }

        #content {
            text-align: center;
            max-width: 820px;
            margin-top: 20px;
        }

        h1 {
            color: #333;
        }

        h2 {
            color: #666;
        }

        input[type="file"] {
            margin-bottom: 10px;
        }

        .media-container {
            display: flex;
            max-width: 100%;
            margin-bottom: 20px;
        }

        .media-container:first-child {
            margin-right: 20px; /* 在第一個(gè)容器的右側(cè)添加間隔 */
        }

        .media-container img,
        .media-container video {
            max-width: 100%;
            height: auto;
        }

        .original {
            width: 400px;
            overflow: hidden;
        }

        .processed {
            flex: 2; /* 右邊容器占據(jù)剩余空間 */
        }

        button {
            padding: 10px 20px;
            background-color: #007bff;
            color: #fff;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            margin-bottom: 10px;
        }

        /* 新增樣式:模態(tài)框 */
        .modal {
            display: none; /* 默認(rèn)隱藏 */
            position: fixed;
            z-index: 1;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            overflow: auto;
            background-color: rgba(0, 0, 0, 0.9); /* 半透明黑色背景 */
        }

        .modal-content {
            margin: auto;
            display: block;
            width: 80%;
            max-width: 800px;
            position: absolute;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            text-align: center; /* 居中顯示圖片 */
        }

        .close {
            color: #ccc;
            font-size: 36px;
            font-weight: bold;
            cursor: pointer;
            position: absolute;
            top: 10px;
            right: 10px;
        }

        .close:hover,
        .close:focus {
            color: #fff;
            text-decoration: none;
        }
        #downloadButton {
           padding: 10px 20px;
            background-color: #007bff;
            color: #fff;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            margin-bottom: 10px;

        }

        /* 新增樣式:響應(yīng)式圖片 */
        .modal-content img,
        .modal-content video {
            max-width: 100%;
            height: auto;
        }

    </style>
</head>
<body>

    <!-- 新增模態(tài)框 -->
    <div id="myModal" class="modal" onclick="closeModal()">
        <div class="modal-content" id="modalContent" onclick="stopPropagation(event)">
            <!-- 放大后的圖片或視頻將在這里顯示 -->
            <span class="close" onclick="closeModal()">&times;</span>
        </div>
    </div>

    <div id="content">
        <h1>照片/視頻檢測(cè)</h1>

        <!-- 上傳圖片 -->
        <h2>上傳圖片</h2>
        <input type="file" id="imageFile" accept="image/*" onchange="displaySelectedImage()">
        <button onclick="uploadImage()">上傳</button>
        <button id="downloadImageButton"  onclick="downloadProcessedImage()">下載</button>
        <br>
        <div class="media-container">
            <div class="original media-container" onclick="enlargeImage()">
                <img id="uploadedImage" src="#" alt="Uploaded Image" style="display:none;">
                <button id="zoomInButton" style="display:none;">Zoom In</button>
            </div>
            <div class="processed media-container" onclick="enlargeImage2()">
                <img id="processedImage" src="#" alt="Processed Image" style="display:none;">

            </div>
        </div>
        <br>

        <!-- 上傳視頻 -->
        <h2>上傳視頻</h2>
        <input type="file" id="videoFile" accept="video/mp4,video/x-m4v,video/*" onchange="displaySelectedVideo()">
        <button onclick="uploadVideo()">上傳</button>
        <button id="downloadButton" onclick="downloadProcessedVideo()">下載</button>
        <br>
        <div class="media-container">
            <div class="original media-container" >
                <video id="uploadedVideo" src="#" controls style="display:none;"></video>
            </div>
            <div class="processed media-container">
                <video id="processedVideo" controls style="display:none;"></video>

            </div>
        </div>
        <br>

    </div>

    <script>
         // 顯示選擇的權(quán)重文件

        // 顯示選擇的圖片并添加點(diǎn)擊放大功能
        function displaySelectedImage() {
            var fileInput = document.getElementById('imageFile');
            var file = fileInput.files[0];
            var imageElement = document.getElementById('uploadedImage');
            imageElement.src = URL.createObjectURL(file);
            imageElement.style.display = 'inline';
            document.getElementById('zoomInButton').style.display = 'inline';
        }

        // 顯示模態(tài)框并放大圖片
        function enlargeImage() {
            var modal = document.getElementById('myModal');
            var modalImg = document.getElementById('modalContent');
            var img = document.getElementById('uploadedImage');
            modal.style.display = 'block';
            modalImg.innerHTML = '<img src="' + img.src + '">';
        }
        // 顯示模態(tài)框并放大圖片
        function enlargeImage2() {
            var modal = document.getElementById('myModal');
            var modalImg = document.getElementById('modalContent');
            var img = document.getElementById('processedImage');
            modal.style.display = 'block';
            modalImg.innerHTML = '<img src="' + img.src + '">';
        }


        // 顯示選擇的視頻并添加點(diǎn)擊放大功能
        function displaySelectedVideo() {
            var fileInput = document.getElementById('videoFile');
            var file = fileInput.files[0];
            var videoElement = document.getElementById('uploadedVideo');
            videoElement.src = URL.createObjectURL(file);
            videoElement.style.display = 'block';
        }


        // 上傳圖片并向后端發(fā)送請(qǐng)求
        function uploadImage() {
            var fileInput = document.getElementById('imageFile');
            var file = fileInput.files[0];
            var formData = new FormData();
            formData.append('image', file);

            fetch('/predict_image', {
                method: 'POST',
                body: formData
            })
            .then(response => response.json())
            .then(data => {
                var imageElement = document.getElementById('processedImage');
                imageElement.src = 'data:image/png;base64,' + data.image;
                imageElement.style.display = 'inline';
                document.getElementById('downloadImageButton').style.display = 'inline';
            })
            .catch(error => console.error('Error:', error));
        }

        // 下載處理后的圖片
        function downloadProcessedImage() {
            var imageElement = document.getElementById('processedImage');
            var url = imageElement.src;
            var a = document.createElement('a');
            a.href = url;
            a.download = 'processed_image.png';
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
        }

        // 上傳視頻并向后端發(fā)送請(qǐng)求
        function uploadVideo() {
            var fileInput = document.getElementById('videoFile');
            var file = fileInput.files[0];
            var formData = new FormData();
            formData.append('video', file);

            fetch('/predict_video', {
                method: 'POST',
                body: formData
            })
            .then(response => response.json())
            .then(data => {
                var videoElement = document.getElementById('processedVideo');
                // 修改路徑為正確的 Flask url_for 生成的路徑
                videoElement.src = '{{ url_for("static", filename="") }}' + data.output_video_path;
                videoElement.style.display = 'block';
                var downloadButton = document.getElementById('downloadButton');
                downloadButton.style.display = 'block';
            })
            .catch(error => console.error('Error:', error));
        }

        // 下載處理后的視頻
        function downloadProcessedVideo() {
            var videoElement = document.getElementById('processedVideo');
            var url = videoElement.src;
            var a = document.createElement('a');
            a.href = url;
            a.download = 'processed_video.mp4';
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
        }

        // 關(guān)閉模態(tài)框
        function closeModal() {
            var modal = document.getElementById('myModal');
            modal.style.display = 'none';
        }
    </script>
</body>
</html>

使用說(shuō)明:

index.html放入templates文件夾中

運(yùn)行app.py

注:此處加載模型路徑更改為自己的

model = torch.hub.load('', 'custom', path='yolov5s.pt', source='local')

如果模型讀取不到,顯示

FileNotFoundError: [Errno 2] No such file or directory: 'hubconf.py'

去yolov5官網(wǎng),下載yolov5-master到項(xiàng)目文件夾

并將yolov5s.pt文件復(fù)制到y(tǒng)olov5-master文件夾中,修改model路徑

model = torch.hub.load('yolov5-master', 'custom', path='yolov5s.pt', source='local')

總結(jié)

到此這篇關(guān)于yolov5使用flask部署至前端實(shí)現(xiàn)照片\視頻識(shí)別功能的文章就介紹到這了,更多相關(guān)yolov5 flask部署前端照片視頻識(shí)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python最長(zhǎng)回文子串問(wèn)題

    Python最長(zhǎng)回文子串問(wèn)題

    這篇文章主要介紹了Python最長(zhǎng)回文子串問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • python局域網(wǎng)ip掃描示例分享

    python局域網(wǎng)ip掃描示例分享

    這篇文章主要介紹了python局域網(wǎng)ip掃描示例,需要的朋友可以參考下
    2014-04-04
  • Python使用Beautiful?Soup(BS4)庫(kù)解析HTML和XML

    Python使用Beautiful?Soup(BS4)庫(kù)解析HTML和XML

    這篇文章介紹了Python使用Beautiful?Soup(BS4)庫(kù)解析HTML和XML的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • 10個(gè)Python自動(dòng)化辦公的腳本分享

    10個(gè)Python自動(dòng)化辦公的腳本分享

    在日常辦公中,我們常常會(huì)被繁瑣、重復(fù)的任務(wù)占據(jù)大量時(shí)間,本文為大家分享了10個(gè)實(shí)用的?Python?自動(dòng)化辦公案例及源碼,希望對(duì)大家有所幫助
    2025-02-02
  • Python連接SQLServer2000的方法詳解

    Python連接SQLServer2000的方法詳解

    這篇文章主要介紹了Python連接SQLServer2000的方法,結(jié)合實(shí)例形式分析了Python實(shí)現(xiàn)數(shù)據(jù)庫(kù)連接過(guò)程中所遇到的常見(jiàn)問(wèn)題與相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2017-04-04
  • 最小公倍數(shù)Python實(shí)現(xiàn)的方法例子

    最小公倍數(shù)Python實(shí)現(xiàn)的方法例子

    這篇文章介紹了兩種計(jì)算最小公倍數(shù)的方法:輾轉(zhuǎn)相除法(歐幾里德法)和相減法(更相減損法),這兩種方法分別基于求最大公約數(shù)的不同原理,需要的朋友可以參考下
    2024-11-11
  • matplotlib繪制折線圖的基本配置(萬(wàn)能模板案例)

    matplotlib繪制折線圖的基本配置(萬(wàn)能模板案例)

    折線圖可以很方便的看出數(shù)據(jù)的對(duì)比,本文主要介紹了matplotlib繪制折線圖的基本配置(萬(wàn)能模板案例),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • Python 迭代器與生成器實(shí)例詳解

    Python 迭代器與生成器實(shí)例詳解

    這篇文章主要介紹了Python 迭代器與生成器實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • python字典序問(wèn)題實(shí)例

    python字典序問(wèn)題實(shí)例

    這篇文章主要介紹了python字典序問(wèn)題,是字符串操作一個(gè)比較典型的應(yīng)用,需要的朋友可以參考下
    2014-09-09
  • NumPy中掩碼數(shù)組的操作

    NumPy中掩碼數(shù)組的操作

    本文主要介紹了NumPy中掩碼數(shù)組的操作,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03

最新評(píng)論