官方教程
教程網址: https://github.com/tensorflow/tfjs-models/tree/master/coco-ssd
目標檢測模型,旨在定位和識別單個圖像中的多個目標。
該模型是 COCO-SSD 模型的 TensorFlow.js 移植。有關 Tensorflow 對象檢測 API 的更多信息,請查看 tensorflow/object_detection中的自述文件。
該模型檢測 COCO 數據集中定義的對象,這是一個大規模的對象檢測、分割和字幕數據集。您可以在這裡找到更多信息。該模型能夠檢測80 類物體。(SSD 代表單次多盒檢測)。
此 TensorFlow.js 模型不需要您了解機器學習。它可以將輸入作為任何基於瀏覽器的圖像元素(例如<img>
、<video>
、<canvas>
元素),並返回帶有類名稱和置信度的邊界框數組。
<!-- Load TensorFlow.js. This is required to use coco-ssd model. -->
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"> </script>
<!-- Load the coco-ssd model. -->
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/coco-ssd"> </script>
<!-- Replace this with your image. Make sure CORS settings allow reading the image! -->
<img id="img" src="cat.jpg"/>
<!-- Place your code in the script tag below. You can also use an external .js file -->
<script>
// Notice there is no 'import' statement. 'cocoSsd' and 'tf' is
// available on the index-page because of the script tag above.
const img = document.getElementById('img');
// Load the model.
cocoSsd.load().then(model => {
// detect objects in the image.
model.detect(img).then(predictions => {
console.log('Predictions: ', predictions);
});
});
</script>
讀取攝像機
以下為一個簡單讀取攝像機並且作物件偵測的程式範例
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Test</title>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"> </script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/coco-ssd"> </script>
</head>
<body>
<div class="select">
<label for="videoSource">Video source: </label><select id="videoSource"></select>
</div>
<button id="showVideo">Open camera</button>
<br />
<!-- Video element to capture camera input -->
<video id="video" autoplay playsinline style="position: absolute;z-index: -999;"></video><canvas id="canvas"
width="100%"></canvas>
<div id="message"></div>
<script>
const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
document.querySelector('#showVideo').addEventListener('click', e => init(e));
const videoSelect = document.querySelector('select#videoSource');
function gotDevices(deviceInfos) {
console.log(deviceInfos)
deviceInfos.forEach(deviceInfo => {
if (deviceInfo.kind == "videoinput") {
const option = document.createElement('option');
option.value = deviceInfo.deviceId;
option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`;
videoSelect.appendChild(option);
}
});
}
function gotStream(stream) {
window.stream = stream; // make stream available to console
videoElement.srcObject = stream;
// Refresh button list in case labels have become available
return navigator.mediaDevices.enumerateDevices();
}
window.onload = () => {
navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError);
const constraints = {
audio: { deviceId: audioSource ? { exact: audioSource } : undefined },
video: { deviceId: videoSource ? { exact: videoSource } : undefined }
};
navigator.mediaDevices.getUserMedia(constraints).then(gotStream).then(gotDevices).catch(handleError);
}
function getRandomColor() {
const randomColor = Math.floor(Math.random() * 16777215).toString(16);
return "#" + ("000000" + randomColor).slice(-6);
}
function handleSuccess(stream) {
const videoTracks = stream.getVideoTracks();
var predictions = [];
video.srcObject = stream;
// When the video is playing, draw it on the canvas
video.addEventListener('play', () => {
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
// Continuously draw the video frames on the canvas
function drawFrame() {
// Draw the video frame on the canvas
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
const scaleX = canvas.width / video.videoWidth;
const scaleY = canvas.height / video.videoHeight;
// Draw the bounding boxes on the canvas
predictions.forEach(prediction => {
const x = prediction.bbox[0] * scaleX;
const y = prediction.bbox[1] * scaleY;
const width = prediction.bbox[2] * scaleX;
const height = prediction.bbox[3] * scaleY;
ctx.strokeStyle = 'blue';
ctx.lineWidth = 2;
ctx.strokeRect(x, y, width, height);
ctx.fillStyle = 'blue';
ctx.font = '18px Arial';
ctx.fillText(prediction.class, x, y);
});
// Call the drawFrame function again to continuously update the canvas
requestAnimationFrame(drawFrame);
}
// Start drawing video frames
drawFrame();
// Load the model.
cocoSsd.load().then(model => {
function detectFrame() {
// detect objects in the image.
model.detect(video).then(preds => {
predictions = preds
setTimeout(detectFrame, 100);
});
}
detectFrame()
});
});
}
function handleError(error) {
if (error.name === 'OverconstrainedError') {
const v = constraints.video;
alert(`The resolution ${v.width.exact}x${v.height.exact} px is not supported by your device.`);
} else if (error.name === 'NotAllowedError') {
alert('Permissions have not been granted to use your camera and ' +
'microphone, you need to allow the page access to your devices in ' +
'order for the demo to work.');
}
alert(`getUserMedia error: ${error.name}`, error);
}
async function init(e) {
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: false, video: { deviceId: videoSelect.value ? { exact: videoSelect.value } : undefined } });
handleSuccess(stream);
e.target.disabled = true;
} catch (e) {
handleError(e);
}
}
</script>
</body>
</html>
執行成果
以下為範例執行程式: https://claire-chang.com/wp-content/uploads/2023/08/sample.html
要開啟鏡頭權限需要至網站設定開啟權限