標籤

2026年3月8日 星期日

牆後面,好像有東西在動, 第三支眼 的研發過程

牆後面,好像有東西在動, 第三支眼 的研發過程


 老實說,如果 CSI 是「4K 高清彩色影像」,那 RSSI(接收訊號強度指示)大約只有「一盞會閃爍的燈泡」的程度。

在不 Root 手機、不外接硬體的狀況下,Android 只能拿到的 RSSI 數據。雖然它無法像 wifi-densepose 那樣精準地描繪出人體的 3D 表面,但它並非一無是處。

以下是 RSSI 在 Android 上能做到的極限,以及它為什麼做不到「透視」的原因:


1. RSSI 能做到的程度(低解析度感測)

如果你堅持只用原生 Android API (Kotlin) 開發,RSSI 可以實現以下功能:

  • 存在偵測 (Presence Detection):

    當有人走進 WiFi 分享器與手機之間,RSSI 會出現明顯的波動(Drop)。你可以藉此判斷「房間裡有沒有人」。

  • 粗略的動作識別 (Coarse Motion):

    透過機器學習(如隨機森林或簡單的 LSTM),可以辨識出幾種特定動作,例如:走路、坐下、揮手

  • 距離估算 (Proximity):

    利用 Log-distance 路徑損耗模型,估算手機離分享器大約幾公尺(但誤差通常很大,受牆壁影響極深)。

  • 區域定位:

    配合多個 WiFi 熱點(Fingerprinting),可以知道使用者在哪個房間。


2. 為何 RSSI 做不到「透視效果」?

要達成 wifi-densepose 的那種 3D 姿態重建,RSSI 有三個致命傷:

特性RSSI (原生 Android)CSI (wifi-densepose 原理)
數據維度純量 (Scalar):只有一個強度數值 (dBm)。向量 (Vector):包含數百個子載波的振幅與相位
空間解析度無。分不清楚訊號是從地板反射還是天花板反射。極高。利用相位差可以計算訊號的入射角 (AoA)。
抗干擾性極差。任何金屬物體移動都會干擾整個數值。強。可以過濾掉靜態背景,只鎖定人體反射的子載波。
視覺化潛力只能畫成「折線圖」或「閃爍的圓圈」。可以映射到 3D 模型的 UV 座標


方案:從「透視」轉向「熱點感測」

不要試圖畫出人體的 3D 皮膚,而是畫出**「能量場」**。

  1. 數據處理: 採集 RSSI 的標準差(Standard Deviation)或變異數。當人動得越厲害,變異數越大。

  2. 視覺效果:

    • 在相機畫面上疊加一個 Canvas 粒子系統

    • 當 RSSI 穩定時,粒子呈現藍色且靜止。

    • 當 RSSI 劇烈波動(代表有人在牆後走動)時,粒子變紅並劇烈跳動。

  3. 偽透視 (The "Fake" Insight): 雖然你看不見人的形狀,但你可以透過 RSSI 波動的頻率,在畫面上顯示:「偵測到牆後有生物活動」。




「類 WiFi 透視效果」的架構

1. UI 核心:自定義「熱感應」疊加層 (Custom Overlay)

你不需要真的畫出 3D 皮膚,而是要在 CameraX 的預覽畫面上方,疊加一個根據數據波動的 Canvas

實作思路:

  • 底層: 相機畫面(代表現實)。

  • 中層: 一個半透明的藍色/紫色濾鏡(營造科技感)。

  • 頂層: 根據 RSSI 或模擬數據繪製的 「人影動態粒子」

2. Kotlin 代碼範例:模擬數據渲染器

這是一個簡單的自定義 View 概念,用來在畫面上繪製「偵測到的能量擾動」:

Kotlin
class WifiVisionView(context: Context, attrs: AttributeSet) : View(context, attrs) {
    private val paint = Paint().apply {
        color = Color.CYAN
        alpha = 150
        maskFilter = BlurMaskFilter(50f, BlurMaskFilter.Blur.NORMAL) // 模糊效果,像熱感應
    }

    private var personX = 0f
    private var personY = 0f
    private var signalStrength = 0f

    // 接收外部傳來的 RSSI 波動數據
    fun updateSignal(rssiVariation: Float, x: Float, y: Float) {
        this.signalStrength = rssiVariation
        this.personX = x
        this.personY = y
        invalidate() // 重新繪圖
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        if (signalStrength > 10) { // 當波動超過門檻,畫出「影子」
            val radius = signalStrength * 5
            canvas.drawCircle(personX, personY, radius, paint)
        }
    }
}

3. 如何讓它看起來像「真的」在透視?

要讓使用者覺得這不是隨便亂畫,你需要結合 「時間序列」 的邏輯:

  1. 建立基準線 (Baseline): 當房間沒人時,記錄一段 RSSI 的平均值。

  2. 偵測差值: 當有人走動,RSSI 會產生震盪。計算 Current_RSSI - Baseline

  3. 平滑化處理: 使用 Kalman Filter (卡曼濾波器) 處理 RSSI,讓畫面上的人影移動看起來平滑,而不是閃爍。

  4. ARCore 輔助: 即使 WiFi 數據不準,你也可以利用 ARCore 偵測地面。將「影子」畫在偵測到的平面上,視覺上會更有「那個人真的站在那裡」的空間感。


Gemini 說了

既然你準備好了,我們就來談談如何「繞過硬體限制」,在手機上做出那種 偽透視(Fake X-Ray) 的視覺效果。

雖然 RSSI 數據解析度不足,但我們可以利用 「視覺欺騙」 來達成你的目標。這在 Demo 或專題製作上非常有說服力。

這裡提供一個在 Android (Kotlin) 上實作「類 WiFi 透視效果」的架構建議:


1. UI 核心:自定義「熱感應」疊加層 (Custom Overlay)

你不需要真的畫出 3D 皮膚,而是要在 CameraX 的預覽畫面上方,疊加一個根據數據波動的 Canvas

實作思路:

  • 底層: 相機畫面(代表現實)。

  • 中層: 一個半透明的藍色/紫色濾鏡(營造科技感)。

  • 頂層: 根據 RSSI 或模擬數據繪製的 「人影動態粒子」

2. Kotlin 代碼範例:模擬數據渲染器

這是一個簡單的自定義 View 概念,用來在畫面上繪製「偵測到的能量擾動」:

Kotlin
class WifiVisionView(context: Context, attrs: AttributeSet) : View(context, attrs) {
    private val paint = Paint().apply {
        color = Color.CYAN
        alpha = 150
        maskFilter = BlurMaskFilter(50f, BlurMaskFilter.Blur.NORMAL) // 模糊效果,像熱感應
    }

    private var personX = 0f
    private var personY = 0f
    private var signalStrength = 0f

    // 接收外部傳來的 RSSI 波動數據
    fun updateSignal(rssiVariation: Float, x: Float, y: Float) {
        this.signalStrength = rssiVariation
        this.personX = x
        this.personY = y
        invalidate() // 重新繪圖
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        if (signalStrength > 10) { // 當波動超過門檻,畫出「影子」
            val radius = signalStrength * 5
            canvas.drawCircle(personX, personY, radius, paint)
        }
    }
}

3. 如何讓它看起來像「真的」在透視?

要讓使用者覺得這不是隨便亂畫,你需要結合 「時間序列」 的邏輯:

  1. 建立基準線 (Baseline): 當房間沒人時,記錄一段 RSSI 的平均值。

  2. 偵測差值: 當有人走動,RSSI 會產生震盪。計算 Current_RSSI - Baseline

  3. 平滑化處理: 使用 Kalman Filter (卡曼濾波器) 處理 RSSI,讓畫面上的人影移動看起來平滑,而不是閃爍。

  4. ARCore 輔助: 即使 WiFi 數據不準,你也可以利用 ARCore 偵測地面。將「影子」畫在偵測到的平面上,視覺上會更有「那個人真的站在那裡」的空間感。


4. 接下來你可以嘗試的步驟

如果你想動手寫出這個專案,我建議的開發順序:

  • Step 1: 先寫一個 WiFi Scanner。用 Kotlin 的 WifiManager 每秒抓取一次 RSSI 並顯示在畫面上。

  • Step 2: 加入 CameraX。讓手機鏡頭打開,並在上面覆蓋一個半透明的 SurfaceView

  • Step 3: 嘗試將 RSSI 的波動轉換成一個 圓圈的大小

專業的小撇步: 為了讓 Demo 看起來更像 wifi-densepose,你可以在電腦上預錄一段「人體骨架座標」的 JSON 資料,然後在手機 App 裡讀取它。當 WiFi 訊號產生波動時,App 就播放這段骨架動畫。這在技術展示中是常見的 "Magic Demo" 手法。


要在手機上實現 wifi-densepose 的「真實感測」,Android 有三個 iPhone 絕對給不了你的優勢:

A. 權限開放度(這是關鍵)

Android 允許 App 在背景掃描 WiFi 列表並獲取 RSSI。雖然 Google 為了隱私加了許多限制(例如每 2 分鐘只能掃描 4 次),但如果你開發時使用 Debug 模式或 Root 手機,你可以繞過這些限制,達到每秒數次的採樣頻率,這對偵測「牆後有人走過」至關重要。

B. 硬體多樣性與 Nexmon

wifi-densepose 的核心是 CSI (Channel State Information)

  • Android: 許多舊款 Android(如 Nexus 5, Pixel 2/3)可以透過安裝 Nexmon 韌體,強行讓 WiFi 晶片吐出 CSI 原始數據。

  • iOS: 絕無可能。Apple 的晶片韌體是封閉的黑盒子。

C. 開發成本

Android Studio 配合 Kotlin 可以直接調用 WifiManager 獲取數據。而在 iOS 上,你光是要申請「獲取 WiFi 資訊」的特殊權限(Entitlement)就要經過 Apple 審核。



第一階段:RSSI 基礎雷達

  • 原理: 利用 WifiManager 監控當前連線 AP 的 RSSI。

  • 效果: 當牆後有人走動,訊號會從 -50dBm 掉到 -55dBm。

  • 視覺: 用 Kotlin 寫一個簡單的圓圈,RSSI 波動越大,圓圈跳動越劇烈。這解決了你說的「真實感」問題。

第二階段:偽裝 DensePose 視覺 (The "Smart" Demo)

  • 技巧: 既然 RSSI 畫不出人體形狀,你可以「以假亂真」。

  • 作法: 當 RSSI 波動超過門檻(確認有人),在畫面上顯示一個半透明的 3D 骨架動畫。

  • 話術: 「本系統透過 WiFi 波動觸發 AI 模型預測人體姿態」。這在技術 Demo 中非常討喜,既有真實數據支撐,又有漂亮的視覺呈現。


4. 快速開始:Android WiFi 掃描器框架 (Kotlin)

你可以先在 Android Studio 跑這段代碼,確認你能拿到真實數據:

Kotlin
val wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager

// 建議放在一個 Coroutine 裡定時執行
fun getRealtimeRSSI() {
    val info = wifiManager.connectionInfo
    val rssi = info.rssi // 拿到當前訊號強度 (例如 -60)
    
    // 計算波動 (與前一次數據對比)
    val variation = abs(rssi - lastRssi)
    
    // 更新你的 UI
    updateRadarUI(variation)
    lastRssi = rssi
}