即時心率估算器
NOTE
僅限網頁 SDK 即時估算功能目前僅適用於網頁版 SDK(JavaScript、React、Vue)。不適用於行動裝置 SDK(iOS、Android、Flutter、React Native)。
概述
即時估算器在影片擷取過程中提供即時心率回饋,最快可在 3-5 秒內顯示結果,無需等待完整的 30 秒掃描。這創造了更具吸引力的使用者體驗,並幫助使用者調整位置和光線以獲得最佳測量結果。
快速開始
typescript
import { createVitalSignCamera, RealtimeEstimatorType } from 'ts-vital-sign-camera';
const camera = createVitalSignCamera({
realtimeEstimationConfig: {
estimatorType: RealtimeEstimatorType.MeRppg, // 預設:AI 驅動
earlyEstimation: true,
minDuration: 3,
minConfidence: 0.3
},
onVideoFrameProcessed: (event) => {
// 即時估算可從事件中取得
if (event.realtimeEstimation) {
console.log(`心率:${event.realtimeEstimation.heartRate} BPM`);
console.log(`信心度:${event.realtimeEstimation.confidence}`);
console.log(`穩定:${event.realtimeEstimation.isStable}`);
}
}
});可用的估算器
ME-rPPG 估算器(預設)🤖
AI 驅動的神經網路方法
- 最適合:消費者應用程式、變化的環境、現代裝置
- 準確度:最先進(±2-3 BPM)
- 速度:約 3 秒內首次結果
- 動作容忍度:優秀
- 光線容忍度:優秀
- 授權:開源
- 需求:約 10 MB 模型檔案
typescript
const camera = createVitalSignCamera({
realtimeEstimationConfig: {
estimatorType: RealtimeEstimatorType.MeRppg
}
});FDA 估算器 📈
訊號處理方法
- 最適合:醫療應用程式、即時初始化、最小套件大小
- 準確度:醫療級(±2-3 BPM)
- 速度:約 5 秒內首次結果
- 動作容忍度:良好
- 光線容忍度:良好
- 授權:專有(PanopticAI)
- 需求:無(即時初始化)
typescript
const camera = createVitalSignCamera({
realtimeEstimationConfig: {
estimatorType: RealtimeEstimatorType.Fda
}
});配置選項
基本配置
typescript
interface RealtimeEstimationConfig {
// 要使用的估算器
estimatorType?: RealtimeEstimatorType;
// 在完整掃描完成前顯示結果
earlyEstimation?: boolean;
// 顯示結果前的最小秒數
minDuration?: number;
// 最小信心度閾值(0-1)
minConfidence?: number;
// 啟用除錯記錄
debug?: boolean;
}ME-rPPG 特定選項
typescript
{
// 模型檔案路徑(可選,提供預設值)
modelPath?: string;
statePath?: string;
welchPath?: string;
hrPath?: string;
// 時間正規化參數
lambda?: number; // 預設:1.0
}估算結果
RealtimeEstimation 介面
typescript
interface RealtimeEstimation {
// 心率(BPM)
heartRate: number;
// 信心度(0-1)
confidence: number;
// 結果是否足夠穩定可顯示
isStable: boolean;
// 訊噪比(可選)
snr?: number;
// 訊號品質分數 0-100(可選)
signalQuality?: number;
}使用估算結果
typescript
camera.onVideoFrameProcessed = (event) => {
const estimation = event.realtimeEstimation;
if (!estimation) return;
if (estimation.isStable && estimation.confidence > 0.6) {
// 高信心度 - 顯著顯示
displayHeartRate(estimation.heartRate);
} else if (estimation.confidence > 0.3) {
// 中等信心度 - 顯示指示器
displayHeartRate(estimation.heartRate, '精煉中...');
} else {
// 低信心度 - 引導使用者
showMessage('調整中... 請保持靜止');
}
};訊號視覺化
顯示原始 PPG 訊號以進行除錯或使用者回饋。
基本用法
typescript
import { SignalVisualizer } from 'ts-vital-sign-camera';
// 建立視覺化器
const container = document.getElementById('signal-container');
const visualizer = new SignalVisualizer(container, {
width: 600,
height: 200,
visualizationType: 'PPG', // 或 'ECG' 進行模擬
lineColor: '#00ff00',
backgroundColor: '#000000'
});
// 使用影片幀事件中的訊號資料更新
camera.onVideoFrameProcessed = (event) => {
if (event.signalData) {
visualizer.updateSignal(event.signalData, event.realtimeEstimation);
}
};
// 清理
visualizer.destroy();配置選項
typescript
interface SignalVisualizerConfig {
width?: number; // 畫布寬度(預設:600)
height?: number; // 畫布高度(預設:200)
maxPoints?: number; // 最大資料點(預設:300)
lineColor?: string; // 訊號線顏色
backgroundColor?: string; // 畫布背景
gridColor?: string; // 網格線顏色
visualizationType?: 'PPG' | 'ECG'; // 訊號類型
debug?: boolean; // 除錯記錄
}視覺化類型
PPG 模式(預設):
- 顯示來自相機的實際光體積描記訊號
- 即時滾動波形
- 適用於除錯訊號品質
ECG 模式:
- 模擬心電圖動畫
- 測量期間的視覺回饋
- 符合估算的心率
typescript
// PPG 視覺化(實際訊號)
const ppgVisualizer = new SignalVisualizer(container, {
visualizationType: 'PPG'
});
// ECG 模擬(動畫)
const ecgVisualizer = new SignalVisualizer(container, {
visualizationType: 'ECG',
lineColor: '#ff6b6b'
});SDK 行為
時間軸
0秒 ────────► 3秒 ────────► 10秒 ────────► 30秒
│ │ │ │
│ │ │ └─ 完整掃描完成
│ │ └─ 達到最佳準確度
│ └─ 首次即時估算(ME-rPPG)
└─ 掃描開始估算生命週期
初始化(0-3秒)
- 相機開始擷取
- 人臉偵測啟動
- 訊號緩衝區填充
早期估算(3-5秒)
- 首次結果可用
- 較低信心度
- 持續精煉
穩定估算(10秒以上)
- 高信心度結果
- 最佳準確度
- 準備顯示
掃描完成(30秒)
- 伺服器端驗證
- 最終結果可用
- 即時估算器可重置
事件流程
typescript
// 掃描生命週期
camera.onVideoFrameProcessed = (event) => {
// 即時估算在此可用
if (event.realtimeEstimation) {
console.log('即時更新:', event.realtimeEstimation);
}
};
camera.startScanning(); // 開始掃描
// 最終結果來自健康結果
camera.onVideoFrameProcessed = (event) => {
if (event.healthResult) {
console.log('最終結果:', event.healthResult);
}
};最佳實踐
1. 選擇正確的估算器
typescript
// 適用於具有變化環境的消費者應用程式
const config = {
estimatorType: RealtimeEstimatorType.MeRppg,
earlyEstimation: true,
minDuration: 3,
minConfidence: 0.3
};
// 適用於需要即時初始化的醫療應用程式
const config = {
estimatorType: RealtimeEstimatorType.Fda,
earlyEstimation: false,
minDuration: 10,
minConfidence: 0.7
};2. 提供使用者回饋
typescript
camera.onVideoFrameProcessed = (event) => {
const estimation = event.realtimeEstimation;
if (!estimation) return;
// 顯示信心度指示器
updateConfidenceBar(estimation.confidence);
// 根據品質引導使用者
if (estimation.confidence < 0.4) {
showTip('改善光線或保持靜止');
}
// 穩定時顯示
if (estimation.isStable) {
displayHeartRate(estimation.heartRate);
}
};3. 處理邊緣情況
typescript
let noEstimationTimeout;
let hasReceivedEstimation = false;
camera.startScanning();
// 設定無估算的逾時
noEstimationTimeout = setTimeout(() => {
if (!hasReceivedEstimation) {
showError('無法偵測心率。請調整光線。');
}
}, 15000); // 15 秒
camera.onVideoFrameProcessed = (event) => {
const estimation = event.realtimeEstimation;
if (estimation) {
hasReceivedEstimation = true;
clearTimeout(noEstimationTimeout);
if (estimation.confidence > 0.5) {
hideError();
}
}
};4. 最佳化效能
typescript
// 節流 UI 更新
let lastUpdate = 0;
const UPDATE_INTERVAL = 500; // 500毫秒
camera.onVideoFrameProcessed = (event) => {
const estimation = event.realtimeEstimation;
if (!estimation) return;
const now = Date.now();
if (now - lastUpdate > UPDATE_INTERVAL) {
updateUI(estimation);
lastUpdate = now;
}
};常見使用案例
健身應用程式
typescript
const camera = createVitalSignCamera({
realtimeEstimationConfig: {
estimatorType: RealtimeEstimatorType.MeRppg,
earlyEstimation: true,
minDuration: 3,
minConfidence: 0.3
},
onVideoFrameProcessed: (event) => {
if (event.realtimeEstimation) {
updateWorkoutDisplay(event.realtimeEstimation.heartRate);
updateHeartRateZone(event.realtimeEstimation.heartRate);
}
}
});醫療應用程式
typescript
const camera = createVitalSignCamera({
realtimeEstimationConfig: {
estimatorType: RealtimeEstimatorType.Fda,
earlyEstimation: false,
minDuration: 10,
minConfidence: 0.7
},
onVideoFrameProcessed: (event) => {
const estimation = event.realtimeEstimation;
if (estimation?.isStable && estimation.confidence > 0.7) {
recordMeasurement(estimation);
}
}
});使用訊號視覺化
typescript
const visualizer = new SignalVisualizer(container, {
visualizationType: 'PPG',
width: 800,
height: 300
});
camera.onVideoFrameProcessed = (event) => {
if (event.signalData) {
visualizer.updateSignal(event.signalData, event.realtimeEstimation);
}
};疑難排解
無即時估算
問題:事件中未收到即時估算
解決方案:
- 確保設定
earlyEstimation: true - 檢查人臉是否正確偵測
- 驗證光線條件是否充足
- 至少等待
minDuration秒 - 檢查
event.realtimeEstimation不為 null
低信心度分數
問題:信心度持續低於閾值
解決方案:
- 改善光線(自然光最佳)
- 確保使用者保持靜止
- 檢查人臉是否居中且穩定
- 降低
minConfidence閾值 - 使用 ME-rPPG 以獲得更好的動作容忍度
ME-rPPG 模型未載入
問題:模型載入失敗
解決方案:
- 驗證模型檔案在正確的目錄中
- 檢查 CORS 標頭允許模型載入
- 確保正確的檔案路徑(使用絕對路徑)
- 檢查瀏覽器控制台是否有錯誤
API 參考
RealtimeEstimator 介面
typescript
interface RealtimeEstimator {
readonly estimation: RealtimeEstimation | null;
readonly signalData: SignalData | null;
configure(config?: RealtimeEstimationConfig): void;
reset(): void;
}SignalVisualizer 類別
typescript
class SignalVisualizer {
constructor(container: HTMLElement, config?: SignalVisualizerConfig);
updateSignal(
signalData: SignalData | null,
realtimeEstimation?: RealtimeEstimation | null
): void;
resetScale(): void;
destroy(): void;
}VideoFrameProcessedEvent
typescript
interface VideoFrameProcessedEvent {
videoFrameInfo: VideoFrameInfo;
videoFrame: VideoFrame;
facebox?: NormalizedFacebox;
healthResult?: ScanResult;
scanConditions?: ScanConditions;
landmarks?: NormalizedLandmarkList;
// 即時估算資料
realtimeEstimation?: RealtimeEstimation | null;
signalData?: SignalData | null;
}