iT邦幫忙

0

Flask偵測到物品後渲染網頁

  • 分享至 

  • xImage

一開始是偵測到相關物品會用打開連結方式去呈現此物品資料,辨識到的物品跟要打開的連結都是正確的。現在是想改成自己用個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>
看更多先前的討論...收起先前的討論...
froce iT邦大師 1 級 ‧ 2023-05-19 08:33:43 檢舉
你要的是1. 類似POS機的用法,單人使用?還是2. 在網頁上開起相機偵測,架設伺服器,供多人使用?
你這架構根本不對,如果是:
1. 那你偵測和網頁伺服器應該分兩隻程式,偵測完傳送指令開網頁就好。
2. 架構會比你這個複雜很多很多。
目前是以單人使用去做構想,一開始是想說讓它感覺比較像一整個系統的概念,想說是可以同頁面去做不同html的渲染。
froce iT邦大師 1 級 ‧ 2023-05-19 09:32:02 檢舉
如果以後預定就是單人使用,請你把偵測和網頁分開。
如果要走成在網頁中接收串流的系統,那你要補的知識可就太多了,光前端你就會用到抓取相機相關的api,後端也不可能是這樣寫,偵測和網頁邏輯都沒錯,但逗在一起你目前寫的可就錯的太多了。
我了解了,感謝指教!!!
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友回答

立即登入回答