
隨著攝像頭的不斷改進,實時物體檢測功能越來越受到人們的青睞。從自動駕駛汽車、智慧監控系統到增強現實應用,這項技術被廣泛應用於各種場合。
計算機視覺是利用攝像頭和計算機來執行上述操作的技術的高階術語,是一個龐大而複雜的領域。不過,你可能不知道,你可以在瀏覽器中輕鬆地開始實時物體檢測。
本文將介紹如何使用 React 構建實時物件檢測應用程式並將其部署到伺服器。實時物件檢測應用程式利用了使用者的網路攝像頭反饋。
準備
以下是本指南中使用的關鍵技術的細分:
- React:React 用於構建應用程式的使用者介面(UI)。React 擅長呈現動態內容,在瀏覽器中呈現網路攝像頭畫面和檢測到的物件時非常有用。
- TensorFlow.js:TensorFlow.js 是一個 JavaScript 庫,可將機器學習的強大功能帶入瀏覽器。它允許你載入預先訓練好的物體檢測模型,並直接在瀏覽器中執行,無需複雜的伺服器端處理。
- Coco SSD:該應用程式使用一種名為 Coco SSD 的預訓練物體檢測模型,這是一種輕量級模型,能夠實時識別大量日常物體。雖然 Coco SSD 是一個功能強大的工具,但需要注意的是,它是在一個通用的物體資料集上訓練出來的。如果您有特定的檢測需求,可以按照本指南使用 TensorFlow.js 訓練一個自定義模型。
建立新的 React 專案
- 建立一個新的 React 專案。請執行以下命令:
npm create vite@latest kinsta-object-detection --template react
這將使用 vite 為您搭建一個基線 React 專案。
- 接下來,在專案中執行以下命令安裝 TensorFlow 和 Coco SSD 庫:
npm i @tensorflow-models/coco-ssd @tensorflow/tfjs
現在,您可以開始開發應用程式了。
配置應用程式
在編寫物件檢測邏輯程式碼之前,讓我們先了解一下本指南中的開發內容。下面是應用程式的使用者介面:

應用程式的使用者介面設計
當使用者點選 “Start Webcam” 按鈕時,系統會提示使用者授予應用程式訪問網路攝像頭畫面的許可權。許可權授予後,應用程式開始顯示網路攝像頭畫面,並檢測畫面中的物體。然後,該程式會渲染一個方框,在實時畫面上顯示檢測到的物件,並新增一個標籤。
首先,在 App.jsx 檔案中貼上以下程式碼,建立應用程式的使用者介面:
import ObjectDetection from './ObjectDetection';
function App() {
return (
<div className="app">
<h1>Image Object Detection</h1>
<ObjectDetection />
</div>
);
}
export default App;
該程式碼段指定了頁面的頁首,並匯入了一個名為 ObjectDetection 的自定義元件。該元件包含捕捉網路攝像頭畫面和實時檢測物件的邏輯。
要建立該元件,請在 src 目錄中新建一個名為 ObjectDetection.jsx 的檔案,並貼上以下程式碼:
import { useEffect, useRef, useState } from 'react';
const ObjectDetection = () => {
const videoRef = useRef(null);
const [isWebcamStarted, setIsWebcamStarted] = useState(false)
const startWebcam = async () => {
// TODO
};
const stopWebcam = () => {
// TODO
};
return (
<div className="object-detection">
<div className="buttons">
<button onClick={isWebcamStarted ? stopWebcam : startWebcam}>{isWebcamStarted ? "Stop" : "Start"} Webcam</button>
</div>
<div className="feed">
{isWebcamStarted ? <video ref={videoRef} autoPlay muted /> : <div />}
</div>
</div>
);
};
export default ObjectDetection;
上面的程式碼定義了一個 HTML 結構,其中包含一個用於啟動和停止網路攝像頭饋送的按鈕和一個 <video> 元素,一旦網路攝像頭饋送啟用,該元素將用於向使用者顯示網路攝像頭饋送。狀態容器 isWebcamStarted 用於儲存網路攝像頭的狀態。startWebcam 和 stopWebcam 這兩個函式用於啟動和停止網路攝像頭饋送。讓我們來定義它們:
以下是 startWebcam 函式的程式碼:
const startWebcam = async () => {
try {
setIsWebcamStarted(true)
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
if (videoRef.current) {
videoRef.current.srcObject = stream;
}
} catch (error) {
setIsWebcamStarted(false)
console.error('Error accessing webcam:', error);
}
};
該函式負責請求使用者授予網路攝像頭訪問許可權,一旦授予許可權,它就會設定 <video> 以向使用者顯示實時網路攝像頭饋送。
如果程式碼無法訪問網路攝像頭(可能是由於當前裝置上沒有網路攝像頭或使用者被拒絕),函式將向控制檯列印一條資訊。您可以使用錯誤塊向使用者顯示失敗的原因。
接下來,用以下程式碼替換 stopWebcam 函式:
const stopWebcam = () => {
const video = videoRef.current;
if (video) {
const stream = video.srcObject;
const tracks = stream.getTracks();
tracks.forEach((track) => {
track.stop();
});
video.srcObject = null;
setPredictions([])
setIsWebcamStarted(false)
}
};
這段程式碼會檢查 <video> 物件訪問的正在執行的視訊流軌跡,並停止每個軌跡。最後,它會將 isWebcamStarted 狀態設定為 false。
此時,請嘗試執行應用程式,檢查是否可以訪問和檢視網路攝像頭畫面。
確保將以下程式碼貼上到 index.css 檔案中,以確保應用程式的外觀與您之前看到的預覽效果相同:
#root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
min-width: 100vw;
min-height: 100vh;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 100vw;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}
.app {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.object-detection {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.buttons {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: row;
button {
margin: 2px;
}
}
div {
margin: 4px;
}
}
此外,請刪除 App.css 檔案,以免弄亂元件的樣式。現在,您可以編寫在應用程式中整合實時物件檢測的邏輯了。
設定實時物件檢測
- 首先,在 ObjectDetection.jsx 的頂部新增 Tensorflow 和 Coco SSD 的匯入項:
import * as cocoSsd from '@tensorflow-models/coco-ssd'; import '@tensorflow/tfjs';
- 接下來,在
ObjectDetection元件中建立一個狀態,用於儲存 Coco SSD 模型生成的預測陣列:const [predictions, setPredictions] = useState([]);
- 接下來,建立一個函式來載入 Coco SSD 模型、收集視訊源並生成預測結果:
const predictObject = async () => { const model = await cocoSsd.load(); model.detect(videoRef.current).then((predictions) => { setPredictions(predictions); }) .catch(err => { console.error(err) }); };該函式使用視訊源,對視訊源中出現的物體進行預測。它將為您提供一個預測物件陣列,每個物件都包含一個標籤、一個置信度百分比和一組顯示該物件在視訊幀中位置的座標。
您需要不斷呼叫該函式來處理不斷出現的視訊幀,然後使用儲存在
predictions狀態中的預測結果在實時視訊畫面中為每個已識別的物件顯示方框和標籤。 - 接下來,使用
setInterval函式連續呼叫該函式。您還必須在使用者停止網路攝像頭饋送後停止呼叫該函式。為此,請使用 JavaScript 中的clearInterval函式。在ObjectDetection元件中新增以下狀態容器和useEffect鉤子,以設定在啟用網路攝像頭時持續呼叫predictObject函式,並在禁用網路攝像頭時移除該函式:const [detectionInterval, setDetectionInterval] = useState() useEffect(() => { if (isWebcamStarted) { setDetectionInterval(setInterval(predictObject, 500)) } else { if (detectionInterval) { clearInterval(detectionInterval) setDetectionInterval(null) } } }, [isWebcamStarted])這將使應用程式每 500 毫秒檢測網路攝像頭前的物體。您可以根據自己對物體檢測速度的要求來改變這個值,但要注意,如果檢測頻率過高,可能會導致應用程式佔用瀏覽器的大量記憶體。
- 現在,您已經在
prediction狀態容器中獲得了預測資料,可以用它在實時視訊源中的物件周圍顯示標籤和方框。為此,請更新ObjectDetection的return語句,使其返回如下內容:return ( <div className="object-detection"> <div className="buttons"> <button onClick={isWebcamStarted ? stopWebcam : startWebcam}>{isWebcamStarted ? "Stop" : "Start"} Webcam</button> </div> <div className="feed"> {isWebcamStarted ? <video ref={videoRef} autoPlay muted /> : <div />} {/* Add the tags below to show a label using the p element and a box using the div element */} {predictions.length > 0 && ( predictions.map(prediction => { return <> <p style={{ left: `${prediction.bbox[0]}px`, top: `${prediction.bbox[1]}px`, width: `${prediction.bbox[2] - 100}px` }}>{prediction.class + ' - with ' + Math.round(parseFloat(prediction.score) * 100) + '% confidence.'}</p> <div className={"marker"} style={{ left: `${prediction.bbox[0]}px`, top: `${prediction.bbox[1]}px`, width: `${prediction.bbox[2]}px`, height: `${prediction.bbox[3]}px` }} /> </> }) )} </div> {/* Add the tags below to show a list of predictions to user */} {predictions.length > 0 && ( <div> <h3>Predictions:</h3> <ul> {predictions.map((prediction, index) => ( <li key={index}> {`${prediction.class} (${(prediction.score * 100).toFixed(2)}%)`} </li> ))} </ul> </div> )} </div> );這將在網路攝像頭畫面的右下方顯示預測列表,並使用 Coco SSD 提供的座標在預測物件周圍繪製一個方框,同時在方框頂部新增一個標籤。
- 要正確設定方框和標籤的樣式,請在 index.css 檔案中新增以下程式碼:
.feed { position: relative; p { position: absolute; padding: 5px; background-color: rgba(255, 111, 0, 0.85); color: #FFF; border: 1px dashed rgba(255, 255, 255, 0.7); z-index: 2; font-size: 12px; margin: 0; } .marker { background: rgba(0, 255, 0, 0.25); border: 1px dashed #fff; z-index: 1; position: absolute; } }至此,應用程式開發完成。現在可以重新啟動開發伺服器來測試應用程式。下面是應用程式完成後的樣子:

使用網路攝像頭實時檢測物體的演示。
您可以在此 GitHub 程式碼庫中找到完整程式碼。
將完成的應用程式部署到伺服器
最後一步是將應用程式部署到伺服器(以 Kinsta 為例),讓使用者可以使用。
Git 倉庫準備就緒後,請按照以下步驟將物件檢測應用程式部署到 Kinsta:
- 登入或建立賬戶,檢視 MyKinsta 面板。
- 使用 Git 提供商授權 Kinsta。
- 單擊左側邊欄上的 Static Sites,然後單擊 Add site。
- 選擇要部署的版本庫和分支。
- 為網站指定一個唯一的名稱。
- 按以下格式新增構建設定:
構建命令:yarn build或npm run build - 節點版本:
20.2.0 - 釋出目錄:
dist - 最後,點選 Create site。
應用程式部署完成後,您可以從儀表板單擊 Visit Site 來訪問應用程式。現在,您可以嘗試在裝有攝像頭的各種裝置上執行該應用程式,看看它的效能如何。
小結
您已經使用 React 和 TensorFlow.js 成功構建了一個實時物件檢測應用程式。這將使您能夠探索令人興奮的計算機視覺世界,並直接在使用者瀏覽器中建立互動式體驗。
請記住,我們使用的 Coco SSD 模型只是一個起點。通過進一步探索,您可以使用 TensorFlow.js 深入研究自定義物件檢測,從而定製應用程式以識別與您的需求相關的特定物件。

評論留言