yolov5使用flask部署至前端,实现照片\视频识别

代码与CPython 2024-07-18 17:03:02 阅读 81

初学yolo flask时,需要此功能,Csdn、Github、B站找到许多代码,效果并不满意。
近期,再度尝试,实现简单功能。

实现功能:

上传图片并识别,可以点击图片放大查看

上传视频并识别

识别后的文件下载功能

效果图如上

文件结构如下:

project/

  static/

  空

  templates/

    index.html

    

  app.py

 

相关代码:

app.py

<code>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')code>

# 路由处理图片检测请求

@app.route('/predict_image', methods=['POST'])

def predict_image():

global model

# 获取图像文件

file = request.files['image']

# 读取图像数据并转换为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]

# 将图像转换为 base64 编码的字符串

_, buffer = cv2.imencode('.png', image)

image_str = base64.b64encode(buffer).decode('utf-8')

# 获取当前时间,并将其格式化为字符串

current_time = datetime.now().strftime('%Y%m%d%H%M%S')

# 构建保存路径

save_dir = 'static'

if not os.path.exists(save_dir):

os.makedirs(save_dir)

filename, extension = os.path.splitext(file.filename) # 获取上传文件的文件名和扩展名

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})

# 函数用于在视频帧上绘制检测结果

def detect_objects(frame, model):

results = model(frame)

detections = results.xyxy[0].cpu().numpy() # 获取检测结果

# 在帧上绘制检测结果

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)

# 在帧上绘制类别和置信度

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

# 路由处理视频检测请求

@app.route("/predict_video", methods=["POST"])

def predict_video():

global model

# 从请求中获取视频文件

video_file = request.files["video"]

# 保存视频到临时文件

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))

# 视频写入对象

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))

# 逐帧处理视频并进行目标检测

while True:

ret, frame = video.read()

if not ret:

break

# 进行目标检测

detection_result = detect_objects(frame, model)

# 将处理后的帧写入输出视频

out_video.write(detection_result)

# 释放视频对象

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">code>

<head>

<meta charset="UTF-8">code>

<meta name="viewport" content="width=device-width, initial-scale=1.0">code>

<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"] {code>

margin-bottom: 10px;

}

.media-container {

display: flex;

max-width: 100%;

margin-bottom: 20px;

}

.media-container:first-child {

margin-right: 20px; /* 在第一个容器的右侧添加间隔 */

}

.media-container img,

.media-container video {

max-width: 100%;

height: auto;

}

.original {

width: 400px;

overflow: hidden;

}

.processed {

flex: 2; /* 右边容器占据剩余空间 */

}

button {

padding: 10px 20px;

background-color: #007bff;

color: #fff;

border: none;

border-radius: 5px;

cursor: pointer;

margin-bottom: 10px;

}

/* 新增样式:模态框 */

.modal {

display: none; /* 默认隐藏 */

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;

}

/* 新增样式:响应式图片 */

.modal-content img,

.modal-content video {

max-width: 100%;

height: auto;

}

</style>

</head>

<body>

<!-- 新增模态框 -->

<div id="myModal" class="modal" onclick="closeModal()">code>

<div class="modal-content" id="modalContent" onclick="stopPropagation(event)">code>

<!-- 放大后的图片或视频将在这里显示 -->

<span class="close" onclick="closeModal()">&times;</span>code>

</div>

</div>

<div id="content">code>

<h1>照片/视频检测</h1>

<!-- 上传图片 -->

<h2>上传图片</h2>

<input type="file" id="imageFile" accept="image/*" onchange="displaySelectedImage()">code>

<button onclick="uploadImage()">上传</button>code>

<button id="downloadImageButton" onclick="downloadProcessedImage()">下载</button>code>

<br>

<div class="media-container">code>

<div class="original media-container" onclick="enlargeImage()">code>

<img id="uploadedImage" src="#" alt="Uploaded Image" style="display:none;">code>

<button id="zoomInButton" style="display:none;">Zoom In</button>code>

</div>

<div class="processed media-container" onclick="enlargeImage2()">code>

<img id="processedImage" src="#" alt="Processed Image" style="display:none;">code>

</div>

</div>

<br>

<!-- 上传视频 -->

<h2>上传视频</h2>

<input type="file" id="videoFile" accept="video/mp4,video/x-m4v,video/*" onchange="displaySelectedVideo()">code>

<button onclick="uploadVideo()">上传</button>code>

<button id="downloadButton" onclick="downloadProcessedVideo()">下载</button>code>

<br>

<div class="media-container">code>

<div class="original media-container" >code>

<video id="uploadedVideo" src="#" controls style="display:none;"></video>code>

</div>

<div class="processed media-container">code>

<video id="processedVideo" controls style="display:none;"></video>code>

</div>

</div>

<br>

</div>

<script>

// 显示选择的权重文件

// 显示选择的图片并添加点击放大功能

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';

}

// 显示模态框并放大图片

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 + '">';code>

}

// 显示模态框并放大图片

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 + '">';code>

}

// 显示选择的视频并添加点击放大功能

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';

}

// 上传图片并向后端发送请求

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);

}

// 上传视频并向后端发送请求

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;code>

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);

}

// 关闭模态框

function closeModal() {

var modal = document.getElementById('myModal');

modal.style.display = 'none';

}

</script>

</body>

</html>

使用说明:

index.html放入templates文件夹中

运行app.py

注:此处加载模型路径更改为自己的

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

如果模型读取不到,显示

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

去yolov5官网,下载yolov5-master到项目文件夹

并将yolov5s.pt文件复制到yolov5-master文件夹中,修改model路径

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

如有问题,可联系作者。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。