How WiFi DensePose Works Without Cameras: A Technical Deep Dive into CSI-Based Pose Estimation

WiFi DensePose estimates human body pose by capturing and interpreting Wi-Fi Channel State Information (CSI) instead of visual images, using a pipeline that translates radio-frequency signals into dense pose predictions through modality translation networks.

WiFi DensePose is an open-source implementation in the ruvnet/wifi-densepose repository that enables camera-free human pose estimation using standard Wi-Fi hardware. By analyzing how wireless signals interact with the human body, the system reconstructs dense 3D body poses from Channel State Information (CSI) data. This article explains the technical architecture, detailing how raw radio signals transform into accurate body part segmentation and UV coordinate predictions without any visual input.

The WiFi DensePose Pipeline: From Radio Signals to Body Poses

The system operates through a tightly-coupled sequence of components that mirror classic vision-based DensePose systems, but process purely wireless signals.

1. CSI Acquisition: Capturing Wi-Fi Channel State Information

The pipeline begins with hardware-level signal capture. In src/hardware/csi_extractor.py, the CSIExtractor class connects to Wi-Fi hardware such as ESP32 microcontrollers or commercial routers and reads raw CSI frames.

The extractor supports multiple hardware parsers including ESP32CSIParser and RouterCSIParser, validating incoming data through CSIParseError and CSIValidationError exceptions. This abstraction allows the system to work with diverse Wi-Fi chipsets while maintaining consistent data structures.

2. Signal Pre-processing and Feature Extraction

Raw CSI data contains noise and irrelevant environmental reflections. The src/core/csi_processor.py module handles this through the CSIProcessor class, which optionally pre-processes signals using noise removal, windowing, and amplitude normalization.

The processor extracts a rich feature set (CSIFeatures) including:

  • Amplitude mean and variance
  • Phase differences
  • Correlation matrices
  • Doppler shifts
  • Power-spectral density

Human presence detection occurs via detect_human_presence, filtering frames without human subjects to reduce computational load on downstream components.

3. Phase Sanitization (Optional)

For enhanced signal stability, src/core/phase_sanitizer.py implements optional phase cleaning. This component unwraps phase values and removes phase noise that could distort body geometry reconstruction, particularly important in environments with multipath interference.

4. Modality Translation: Converting CSI to Visual Features

WiFi DensePose bridges the domain gap between radio-frequency signals and visual pose estimation networks. The src/models/modality_translation.py module contains ModalityTranslationNetwork, an encoder-decoder CNN with optional multi-head attention that maps CSI tensors to a visual feature space (visual_features).

This translation is crucial because standard DensePose heads expect visual-like tensors, while CSI data represents spatial variations in wireless channels caused by human body reflection and absorption.

5. DensePose Prediction

The final inference stage occurs in src/models/densepose_head.py through the DensePoseHead architecture. This component contains:

  • A shared convolutional trunk for feature processing
  • A segmentation head for body-part logits
  • A UV-regression head for dense texture coordinates

The head produces per-pixel body-part classification and UV coordinates identical to the original DensePose model, but derived entirely from Wi-Fi signals rather than RGB images.

6. Service Orchestration and API Delivery

src/services/pose_service.py coordinates the entire pipeline through the PoseService class. It initializes the CSIProcessor, PhaseSanitizer, ModalityTranslationNetwork, and DensePoseHead, then exposes async methods (initialize, start, estimate_poses) for API consumers.

HTTP and WebSocket endpoints in src/api/routers/pose.py and src/api/websocket/pose_stream.py deliver pose data (person IDs, confidence scores, keypoints, segmentation masks) to clients without ever transmitting or requiring camera images.

Implementation: Running WiFi DensePose

Synchronous Pose Estimation Example

import asyncio
from src.services.pose_service import PoseService
from src.config.settings import Settings
from src.config.domains import DomainConfig

async def run_once():
    # Load configuration (can be customised via Settings / DomainConfig)

    settings = Settings()          # uses defaults defined in src/config/settings.py

    domain = DomainConfig()        # domain‑specific limits, e.g., zones

    
    # Initialise the service

    pose_srv = PoseService(settings, domain)
    await pose_srv.initialize()
    await pose_srv.start()
    
    # Ask the service for a pose estimate (mock CSI data is used internally)

    result = await pose_srv.estimate_poses(
        zone_ids=["zone_1"],
        confidence_threshold=0.6,
        max_persons=5,
        include_keypoints=True,
        include_segmentation=False
    )
    
    print("Pose estimation result:", result)

# Execute the coroutine

asyncio.run(run_once())

Key files referenced: src/services/pose_service.py, src/config/settings.py, src/config/domains.py.

Real-Time WebSocket Streaming

import asyncio
import websockets
import json
from src.services.pose_service import PoseService
from src.config.settings import Settings
from src.config.domains import DomainConfig

WS_URL = "ws://localhost:8000/ws/pose"

async def stream_poses():
    settings = Settings()
    domain = DomainConfig()
    pose_srv = PoseService(settings, domain)
    await pose_srv.initialize()
    await pose_srv.start()
    
    async with websockets.connect(WS_URL) as ws:
        while True:
            zone_data = await pose_srv.get_current_pose_data()
            await ws.send(json.dumps(zone_data))
            await asyncio.sleep(0.1)  # adjust to desired streaming rate

asyncio.run(stream_poses())

Key files referenced: src/api/websocket/pose_stream.py, src/services/pose_service.py.

Debugging Low-Level CSI Features

from src.hardware.csi_extractor import CSIExtractor
from src.core.csi_processor import CSIProcessor

# Initialise extractor for an ESP32 device

extractor = CSIExtractor({
    "hardware_type": "esp32",
    "sampling_rate": 1000,
    "buffer_size": 256,
    "timeout": 2,
    "validation_enabled": True
})

# Grab a raw CSI frame (async)

raw = await extractor.read()
csi_data = extractor.parser.parse(raw)

# Process the frame

processor = CSIProcessor({
    "sampling_rate": 1000,
    "window_size": 512,
    "overlap": 0.5,
    "noise_threshold": 10
})
features = processor.extract_features(csi_data)

print("Amplitude mean shape:", features.amplitude_mean.shape)
print("Phase diff mean:", features.phase_difference.mean())

Key files referenced: src/hardware/csi_extractor.py, src/core/csi_processor.py.

Key Components and Architecture

Component File Purpose
CSI acquisition src/hardware/csi_extractor.py Reads raw CSI frames, parses ESP32 / router formats
CSI data model src/hardware/router_interface.py Low‑level router communication (mocked in tests)
Pre‑processing & feature extraction src/core/csi_processor.py Noise removal, windowing, feature extraction, human detection
Phase sanitisation src/core/phase_sanitizer.py Cleans phase data (optional)
Modality translation network src/models/modality_translation.py Maps CSI tensors to visual feature space
DensePose head src/models/densepose_head.py Segmentation & UV regression for dense pose
Pose orchestration service src/services/pose_service.py Coordinates all components, provides async API
WebSocket streaming src/api/websocket/pose_stream.py Streams live pose data to clients
REST pose endpoint src/api/routers/pose.py HTTP API for pose queries
Configuration src/config/settings.py Global service settings
Domain config src/config/domains.py Per‑zone limits and policies
Health & metrics src/services/health_check.py Service health reporting

Summary

  • WiFi DensePose eliminates the need for cameras by using Channel State Information (CSI) from standard Wi-Fi hardware to detect human body geometry.
  • The pipeline in ruvnet/wifi-densepose processes raw CSI through acquisition, feature extraction, modality translation, and DensePose prediction stages.
  • ModalityTranslationNetwork in src/models/modality_translation.py bridges the gap between radio-frequency signals and visual feature spaces required by standard pose networks.
  • The system exposes camera-free pose data via REST and WebSocket APIs, delivering per-person keypoints, segmentation masks, and UV coordinates derived entirely from wireless signal variations.

Frequently Asked Questions

How does WiFi DensePose achieve pose estimation without visual input?

WiFi DensePose captures Channel State Information (CSI) from Wi-Fi signals, which records how wireless channels change as signals bounce off human bodies. The system extracts spatial features from these radio-frequency measurements and uses a ModalityTranslationNetwork to convert them into visual-like tensors that standard DensePose heads can process, effectively replacing camera pixels with wireless signal geometry.

What hardware is required to run WiFi DensePose?

The system supports commodity Wi-Fi hardware including ESP32 microcontrollers and commercial routers, as implemented in src/hardware/csi_extractor.py through ESP32CSIParser and RouterCSIParser. The hardware must support CSI extraction (available in many modern Wi-Fi chipsets) and connect to the processing pipeline via the CSIExtractor class, which handles validation and hardware-specific parsing.

How accurate is WiFi DensePose compared to camera-based systems?

While the source code in ruvnet/wifi-densepose implements the full pipeline from CSI to DensePose coordinates, accuracy depends on the quality of the modality translation and the density of Wi-Fi antennas. The system uses phase sanitization (src/core/phase_sanitizer.py) and advanced feature extraction to minimize noise, but like all wireless sensing, it operates under constraints of multipath interference and spatial resolution limits inherent to Wi-Fi wavelengths.

Can WiFi DensePose track multiple people simultaneously?

Yes, the PoseService in src/services/pose_service.py supports multi-person detection through the estimate_poses method, which accepts parameters like max_persons and confidence_threshold. The service aggregates CSI data across configured zones (DomainConfig) and returns per-person pose data including keypoints and segmentation masks, enabling simultaneous tracking of multiple subjects within the Wi-Fi coverage area.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →