一開始是偵測到相關物品會用打開連結方式去呈現此物品資料,辨識到的物品跟要打開的連結都是正確的。現在是想改成自己用個html去渲染成我自己要的商品頁面,可是不知道為什麼現在偵測到obj_class == 0之後,偵測的畫面就直接卡住然後沒有成功渲染,也沒有出現錯誤的訊息。目前自己覺得在邏輯上應該是沒有問題,但也有查過其他渲染的方式也無解,再麻煩各位了。
我的app.py
from flask import Flask, render_template, Response, request, redirect, url_for
import cv2
import numpy as np
import torch
import time
import webbrowser
app = Flask(__name__)
model = torch.hub.load('ultralytics/yolov5', 'custom', path='best.pt', force_reload=True)
cap = cv2.VideoCapture(0)
height, width, _ = cap.read()[1].shape
baseline = height // 2 + 100
# 存儲已跳轉過的網頁
opened_links = []
video_paused = False
detected_object_names = [] # 使用列表來存儲檢測到的物體名稱
def detect_objects():
with app.app_context(), app.test_request_context():
while cap.isOpened():
redirect_to_product_page = False
success, frame = cap.read()
if not success:
print("Ignoring empty camera frame.")
continue
frame = cv2.resize(frame, (800, 480))
if video_paused:
time.sleep(1) # 暂停一秒钟以降低CPU使用率
continue
results = model(frame)
detected_objects = results.xyxy[0]
cv2.line(frame, (0, baseline), (width, baseline), (0, 0, 255), thickness=2)
for obj in detected_objects:
obj_class = int(obj[-1])
if obj_class in [0, 1, 2]:
obj_center_x = (obj[0] + obj[2]) / 2 + 100
obj_center_y = (obj[1] + obj[3]) / 2 + 100
if obj_center_y > baseline:
link_url = ""
if obj_class == 0:
detected_object_name = "柚香"
detected_object_names.append(detected_object_name)
redirect_to_product_page = True
elif obj_class == 1:
link_url = "https://online.carrefour.com.tw/zh/%E7%A6%8F%E6%A8%82/1502200500124.html"
detected_object_name = "福樂"
elif obj_class == 2:
link_url = "https://ecshweb.pchome.com.tw/search/v3.3/?q=%E7%BE%8E%E7%A5%BF"
detected_object_name = "美祿"
if redirect_to_product_page is True:
return redirect(url_for('redirect_product_page'))
if link_url not in opened_links:
webbrowser.open(link_url)
opened_links.append(link_url)
detected_object_names.append(detected_object_name)
# 跳轉網頁後暫停 3 秒再繼續偵測
time.sleep(3)
break
img_bytes = cv2.imencode('.jpg', np.squeeze(results.render()))[1].tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + img_bytes + b'\r\n')
@app.route('/')
def index():
return render_template('home.html')
@app.route('/video_feed')
def video_feed():
return Response(detect_objects(), mimetype='multipart/x-mixed-replace; boundary=frame')
@app.route('/start_video', methods=['POST'])
def start_video():
global video_paused
video_paused = False
return '已啟動'
@app.route('/stop_video', methods=['POST'])
def stop_video():
global video_paused
video_paused = True
cap.release()
cv2.destroyAllWindows()
return '已停止'
@app.route('/pause_video', methods=['POST'])
def pause_video():
global video_paused
video_paused = True
return '已暂停'
@app.route('/resume_video', methods=['POST'])
def resume_video():
global video_paused
video_paused = False
return '已繼續'
@app.route('/other_page')
def other_page():
return render_template('other_page.html', object_names=detected_object_names)
@app.route('/product_page')
def product_page():
return render_template('product_page.html')
@app.route('/redirect_product_page', methods=['POST'])
def redirect_product_page():
return redirect(url_for('product_page'))
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
我的home.html
<!doctype html>
<html>
<head>
<title>哭哭</title>
<style>
.dialog-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
}
.dialog-content {
background-color: white;
padding: 20px;
border-radius: 5px;
max-width: 400px;
text-align: center;
}
.dialog-buttons {
margin-top: 20px;
}
</style>
</head>
<body>
<h1>人生好難</h1>
<button onclick="startDetection()" type="button">開始掃描</button>
<button onclick="pauseDetection()" type="button">暫停掃描</button>
<button onclick="resumeDetection()" type="button">繼續掃描</button>
<button onclick="openDialog()" type="button">掃描紀錄</button>
<img id="videoStream" width="800" height="480">
{% if obj_class == 0 %}
<form action="{{ url_for('redirect_product_page') }}" method="post">
</form>
{% endif %}
<div id="dialog" class="dialog-overlay" style="display: none;">
<div class="dialog-content">
<iframe id="dialogFrame" width="100%" height="100%"></iframe>
<button onclick="closeDialog()" type="button">關閉</button>
</div>
</div>
<script>
let videoStarted = false;
function startDetection() {
fetch('/start_video', {
method: 'POST'
})
.then(response => {
if (response.ok) {
console.log('已啟動');
videoStarted = true; // 设置videoStarted为true
document.getElementById('videoStream').src = "{{ url_for('video_feed') }}";
} else {
console.log('無法啟動');
}
})
.catch(error => console.log(error));
}
function stopDetection() {
fetch('/stop_video', {
method: 'POST'
})
.then(response => {
if (response.ok) {
console.log('已停止');
videoStarted = false; // 设置videoStarted为false
} else {
console.log('無法停止');
}
})
.catch(error => console.log(error));
}
function pauseDetection() {
fetch('/pause_video', {
method: 'POST'
})
.then(response => {
if (response.ok) {
console.log('已暫停');
videoStarted = false; // 设置videoStarted为false
} else {
console.log('無法暫停');
}
})
.catch(error => console.log(error));
}
function resumeDetection() {
fetch('/resume_video', {
method: 'POST'
})
.then(response => {
if (response.ok) {
console.log('已繼續');
videoStarted = true; // 设置videoStarted为true
} else {
console.log('無法繼續');
}
})
.catch(error => console.log(error));
}
function openDialog() {
document.getElementById('dialog').style.display = 'flex';
document.getElementById('dialogFrame').src = "/other_page";
}
function closeDialog() {
document.getElementById('dialog').style.display = 'none';
document.getElementById('dialogFrame').src = "";
}
window.addEventListener('beforeunload', function () {
if (videoStarted) {
stopDetection();
}
});
</script>
</body>
</html>