Skip to content

即時心率估算器

NOTE

僅限網頁 SDK 即時估算功能目前僅適用於網頁版 SDK(JavaScript、React、Vue)。不適用於行動裝置 SDK(iOS、Android、Flutter、React Native)。

概述

即時估算器在影片擷取過程中提供即時心率回饋,最快可在 3-8 秒內顯示結果,無需等待完整的 30 秒掃描。這創造了更具吸引力的使用者體驗,並幫助使用者調整位置和光線以獲得最佳測量結果。

快速開始

typescript
import { createVitalSignCamera, RealtimeEstimatorType } from 'ts-vital-sign-camera';

const camera = createVitalSignCamera({
  realtimeEstimationConfig: {
    estimatorType: RealtimeEstimatorType.Panoptic // 預設
  },
  onVideoFrameProcessed: (event) => {
    // 即時估算可從事件中取得
    if (event.realtimeEstimation) {
      console.log(`心率:${event.realtimeEstimation.heartRate} BPM`);
      console.log(`信心度:${event.realtimeEstimation.confidence}`);
      console.log(`穩定:${event.realtimeEstimation.isStable}`);
    }
  }
});

簡單設定

想要以最簡潔的方式使用 Panoptic 估算器預設值,請使用 enableRealtimeEstimation 布林值:

typescript
import { createVitalSignCamera } from 'ts-vital-sign-camera';

const camera = createVitalSignCamera({
  enableRealtimeEstimation: true,
  onVideoFrameProcessed: (event) => {
    if (event.realtimeEstimation) {
      console.log(`心率:${event.realtimeEstimation.heartRate} BPM`);
    }
  }
});

Vue SDK:

vue
<VitalSignCamera
  :enableRealtimeEstimation="true"
  @onVideoFrameProcessed="onVideoFrameProcessed"
/>

這會以預設配置啟動 Panoptic 估算器。若需要自訂配置,請使用 realtimeEstimationConfig

可用的估算器

ME-rPPG 估算器 🤖

AI 驅動的神經網路方法

  • 最適合:消費者應用程式、變化的環境、現代裝置
  • 準確度:最先進(±2-3 BPM)
  • 速度:約 3 秒內首次結果
  • 動作容忍度:優秀
  • 光線容忍度:優秀
  • 授權:開源
  • 需求:約 10 MB 模型檔案
typescript
const camera = createVitalSignCamera({
  realtimeEstimationConfig: {
    estimatorType: RealtimeEstimatorType.MeRppg
  }
});

Panoptic 估算器(預設)📈

訊號處理方法

  • 最適合:醫療應用程式、即時初始化、最小套件大小
  • 準確度:醫療級(±2-3 BPM)
  • 速度:~8 秒內首次結果
  • 動作容忍度:良好
  • 光線容忍度:良好
  • 授權:專有(PanopticAI)
  • 需求:無(即時初始化)
typescript
const camera = createVitalSignCamera({
  realtimeEstimationConfig: {
    estimatorType: RealtimeEstimatorType.Panoptic
  }
});

配置選項

基本配置

typescript
interface RealtimeEstimationConfig {
  // 要使用的估算器
  estimatorType?: RealtimeEstimatorType;
  
  // 訊號品質計算延遲(秒)
  signalQualityDelay?: number;
  
  // 進行估算所需的最小樣本數
  minSamples?: number;
  
  // 每次掃描的持續時間(秒)
  scanDuration?: number;
  
  // 使用的視覺化訊號類型
  visualSignalType?: 'ppg' | 'respiratory';
  
  // 啟用除錯記錄
  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 和呼吸波形)的完整文件,請參閱訊號視覺化器指南

訊號視覺化器會在相機畫面旁顯示滾動的 PPG/呼吸波形資料。它是一個獨立元件,透過相機的 visualizer 屬性或 onVideoFrameProcessed 回呼進行連接。

如需完整的可視化選項(包括熱圖、邊界框和面部網格疊加層),請參閱可視化選項總覽

SDK 行為

時間軸

0秒 ────────► 3秒 ────────► 8秒 ────────► 15秒 ────────► 30秒
│            │            │            │             │
│            │            │            │             └─ 完整掃描完成
│            │            │            └─ 達到最佳準確度(Panoptic 15秒)
│            │            └─ 首次即時估算(Panoptic ~8秒)
│            └─ 首次即時估算(ME-rPPG ~3秒)
└─ 掃描開始

估算生命週期

  1. 初始化(0-3秒)

    • 相機開始擷取
    • 人臉偵測啟動
    • 訊號緩衝區填充
  2. 早期估算(3-8秒)

    • 首次結果可用(ME-rPPG 約 3 秒,Panoptic 約 8 秒)
    • 較低信心度
    • 持續精煉
  3. 穩定估算(15秒以上)

    • 高信心度結果
    • 最佳準確度
    • 準備顯示
  4. 掃描完成(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
};

// 適用於需要即時初始化的醫療應用程式
const config = {
  estimatorType: RealtimeEstimatorType.Panoptic
};

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
  },
  onVideoFrameProcessed: (event) => {
    if (event.realtimeEstimation) {
      updateWorkoutDisplay(event.realtimeEstimation.heartRate);
      updateHeartRateZone(event.realtimeEstimation.heartRate);
    }
  }
});

醫療應用程式

typescript
const camera = createVitalSignCamera({
  realtimeEstimationConfig: {
    estimatorType: RealtimeEstimatorType.Panoptic
  },
  onVideoFrameProcessed: (event) => {
    const estimation = event.realtimeEstimation;
    if (estimation?.isStable && estimation.confidence > 0.7) {
      recordMeasurement(estimation);
    }
  }
});

使用訊號視覺化

如需完整範例,請參閱訊號視覺化器指南

疑難排解

無即時估算

問題:事件中未收到即時估算

解決方案

  1. 檢查人臉是否正確偵測
  2. 驗證光線條件是否充足
  3. 暖機期間(~8 秒)耐心等待
  4. 檢查 event.realtimeEstimation 不為 null

低信心度分數

問題:信心度持續低於閾值

解決方案

  1. 改善光線(自然光最佳)
  2. 確保使用者保持靜止
  3. 檢查人臉是否居中且穩定
  4. 使用 ME-rPPG 以獲得更好的動作容忍度

ME-rPPG 模型未載入

問題:模型載入失敗

解決方案

  1. 驗證模型檔案在正確的目錄中
  2. 檢查 CORS 標頭允許模型載入
  3. 確保正確的檔案路徑(使用絕對路徑)
  4. 檢查瀏覽器控制台是否有錯誤

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;
}

下一步