MotionShot

AhmadHassan-BTed活跃维护

把快速运动过程定格成一张频闪合成照片的安卓相机应用,靠端侧计算机视觉、2D 防抖和手动曝光控制实现。

Camera app that freezes fast motion sequences into a single stroboscopic photo; powered by on-device computer vision, 2D stabilization, and manual exposure controls

暂无版本4,653star1fork同步于 2026-11-10 23:38 UTC

怎么上手

由 README 提炼,执行前请确认
git clone https://github.com/AhmadHassan-BTed/MotionShot.git
cd MotionShot
./gradlew assembleDebug
硬件要求按 README 说明

Android API 24+ 设备,依赖CameraX/Camera2硬件曝光与ISO控制;README未说明具体GPU或内存要求。

下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

安卓端频闪运动合成相机,用设备端视觉把连拍动作叠加成一张多姿态照片

把快速运动过程定格成一张频闪合成照片的安卓相机应用,靠端侧计算机视觉、2D 防抖和手动曝光控制实现。

核心能力

  • 用2D平移对齐锁定背景,消除手持抖动
  • 归一化色度差分检测运动,抗曝光变化与阴影
  • 手动快门1/30s至1/8000s冻结高速动作
  • 手动ISO最高102400补偿高快门下的暗光
  • 可插拔MotionEngine接口,引擎可替换不改UI

容易踩的坑

需Android Studio Ladybug/Jellyfish或更新版本、Compile SDK 37、Kotlin 2.2.10、Gradle 8.13+;手动快门与ISO依赖设备Camera2 HAL支持,部分机型可能不可用;README未提供预编译APK,需自行构建。

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

0 个版本

暂无 release 数据(可能没有发版,或尚未同步)。

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    Overview & Vision

    Human movement is inherently transient. Whether an athlete sprinting, a dancer executing a spin, a gymnast mid-air, or a child jumping, fleeting physical motion unfolds and vanishes within fractions of a second.

    MotionShot bridges high-speed mobile computer vision with human kinetic expression. Inspired by Sony's legacy Motion Shot technology, MotionShot captures dynamic action bursts and synthesizes a single, multi-pose stroboscopic composite image directly on-device in real time.

    Operating entirely offline with zero cloud latency and zero reliance on heavy AI neural networks, MotionShot renders motion as an aligned visual trajectory: sharp, stabilized, and captured in full sensor resolution.

    Visual Showcase

    Camera ViewfinderHardware SlidersStep 1 Raw GalleryComposite Result

    Technical Specifications

    ParameterSpecification & RangeEngineering Function
    Timer Window1s, 2s, 5s, Custom (1–60s)Dynamic sequence capture deadline
    Frame Count5, 15, 25, Custom (2–50)Trajectory density sampling points
    Shutter SpeedAuto, 1/30s to 1/8000sLogarithmic hardware motion-freeze slider
    ISO SensitivityAuto, ISO 50 to ISO 102,400Continuous sensor gain boost
    Stabilization$\pm 16\text{px}$ 2D translation searchSub-5ms background micro-jitter alignment
    Blending EnginePorterDuff.Mode.SRC_OVERSequential alpha layer compositing
    PersistenceSharedPreferencesAutomatic parameter restoration across sessions

    Key Features

    • Pixel-to-Pixel Handheld Image Stabilization: The 2D translation alignment engine (ImageStabilizer) correlates background grid pixels across frames, locking static elements in place to eliminate camera shake.
    • Normalized Chromaticity Motion Differencing: Evaluates $r, g$ color space ratios alongside BT.601 luminance separation, making motion detection 100% immune to camera exposure shifts and shadows.
    • High Shutter Speed Freeze-Frame Control: Manual shutter speed control down to 1/8000s ($125,\mu\text{s}$ exposure) freezes ultra-fast movement without motion blur.
    • Extended ISO Gain Boost: Manual ISO control scaling up to ISO 102,400 maintains crisp image brightness even under high shutter speeds in low light.
    • Fast Motion Slide & Auto-Play Flipbook Preview: Interactive touch-drag preview and a ▶ Play button (15 FPS flipbook) allow instant sequence verification before finalizing.
    • Pluggable Engine Architecture: Decoupled MotionEngine interface and MotionEngineFactory allow instant engine swapping without modifying UI state logic.

    Architecture Overview

    MotionShot follows a strict Contract-Based Clean Architecture, decoupling UI presentation, state orchestration, image processing algorithms, and Camera2 hardware controls.

    graph TD
        subgraph Presentation["Presentation Layer (Jetpack Compose)"]
            MA[MainActivity] --> CS[CameraScreen]
            CS --> CP[CameraPreview Viewfinder]
            CS --> CC[CaptureControls Sheet & Sliders]
            CS --> RV[Step1ResultView Flipbook Gallery]
        end
    
        subgraph Domain["Domain Contracts & Storage"]
            VM[MotionShotViewModel] --> |Preferences| PR[PreferencesRepository]
            VM --> |Pluggable Contract| ME[MotionEngine Interface]
        end
    
        subgraph Engine["Image Processing Realizations"]
            ME --> FDEM[FastDifferenceMotionEngine]
            FDEM --> STAB[ImageStabilizer Engine]
            FDEM --> DIFF[FrameDifferencer Engine]
            FDEM --> MORPH[MorphologyOps Engine]
            FDEM --> CCMP[CanvasCompositor Engine]
        end
    
        subgraph Hardware["Hardware Capture Layer (CameraX / Camera2)"]
            VM --> FA[FrameAnalyzer]
            FA --> YR[Native C++ YuvToRgb]
            VM --> C2[Camera2Interop Control]
            C2 --> CP
        end
    

    Technical Processing Pipeline

    Each captured frame sequence moves through a zero-allocation processing pipeline:

    flowchart TD
        A["Raw Frame Burst (N Frames)"] --> B["1. 2D Translation Alignment (ImageStabilizer)"]
        B --> C["2. Normalized Chromaticity Differencing (FrameDifferencer)"]
        C --> D["3. 3x3 Morphological Opening (MorphologyOps)"]
        D --> E["4. Soft Contour Edge Feathering"]
        E --> F["5. Sequence Alpha Decay (CanvasCompositor)"]
        F --> G["Final Stroboscopic Composite Image"]
    

    Request Lifecycle & Frame Acquisition

    sequenceDiagram
        autonumber
        actor User
        participant UI as CameraScreen / Controls
        participant VM as MotionShotViewModel
        participant Analyzer as FrameAnalyzer
        participant Engine as MotionEngine
    
        User->>UI: Tap Capture Button
        UI->>VM: onCaptureToggle()
        VM->>VM: Lock Start Time & Set Hard Deadline (T seconds)
        
        loop Dynamic Time Window (T / N-1)
            VM->>Analyzer: shouldCapture.set(true)
            Analyzer-->>VM: frameChannel.receive() [Time-Bounded Timeout Guard]
        end
    
        VM->>Engine: process(capturedFrames)
        Engine->>Engine: 2D Translation Alignment
        Engine->>Engine: Normalized Chromaticity Masking
        Engine->>Engine: 3x3 Morphological Noise Removal
        Engine->>Engine: Native Canvas PorterDuff Stamping
        Engine-->>VM: Return Composite Bitmap
        VM->>UI: Phase = Done (Show Result & Interactive Flipbook)
    

    Technical Deep-Dives

    Camera micro-jitter causes static background edges to shift between frames. MotionShot computes an optimal $(\Delta x, \Delta y)$ alignment vector over a $\pm 16\text{px}$ search window using a 4x grid subsampling strategy:

    $$\Delta x, \Delta y = \arg\min_{dx, dy} \sum_{y, x} \left| \text{Base}(x, y) - \text{Curr}(x + dx, y + dy) \right|$$

    Target frame pixels are shifted by $(\Delta x, \Delta y)$ prior to motion differencing, locking static background elements 100% in place.

    Camera auto-exposure shifts brightness across frames. Simple RGB subtraction fails under exposure drift. MotionShot converts pixels to Normalized Chromaticity:

    $$r = \frac{R}{R + G + B + 1}, \quad g = \frac{G}{R + G + B + 1}$$

    Combining chromaticity distance $\Delta_{\text{chroma}} = |r_1 - r_0| + |g_1 - g_0|$ with BT.601 luminance separation ($\Delta_Y = |Y_1 - Y_0|$) ensures lighting fluctuations and shadows are 100% ignored.

    High shutter speeds (1/500s to 1/8000s) eliminate subject motion blur. CameraX parameters are applied directly to the Camera2 HAL via Camera2CameraControl:

    • CaptureRequest.CONTROL_AE_MODE: Set to OFF for manual exposure control.
    • CaptureRequest.SENSOR_EXPOSURE_TIME: Configured in nanoseconds via logarithmic slider.
    • CaptureRequest.SENSOR_SENSITIVITY: Configured up to ISO 102,400 for low-light gain compensation.

    Repository Structure

    bted.app.motionshot/
    ├── capture/
    │   ├── FrameAnalyzer.kt       # CameraX ImageAnalysis analyzer
    │   └── YuvToRgb.kt            # Native C++ accelerated ImageProxy to Bitmap
    ├── data/
    │   └── PreferencesRepository.kt # SharedPreferences persistence (Timer, Count, Shutter, ISO)
    ├── engine/
    │   ├── MotionEngine.kt        # Pluggable engine interface contract
    │   ├── FastDifferenceMotionEngine.kt  # Math & Differencing engine
    │   ├── MotionEngineFactory.kt # Engine registry & factory
    │   └── DebugPipelineConfig.kt # Step-by-step pipeline config
    ├── processing/
    │   ├── FrameDifferencer.kt    # Normalized chromaticity & luminance differencer
    │   ├── ImageStabilizer.kt     # Pixel-to-pixel 2D handheld stabilizer
    │   ├── MorphologyOps.kt       # 3x3 Erode, Dilate, and Morphological Opening
    │   └── CanvasCompositor.kt    # Native Canvas PorterDuff compositing
    ├── ui/
    │   ├── components/
    │   │   ├── CaptureControls.kt # Sliders, custom input, tap-to-record button
    │   │   └── LoadingOverlay.kt  # Pulsing progress overlay
    │   ├── state/
    │   │   ├── MotionShotUiState.kt # UI state holder & CameraParameterUtils
    │   │   └── CapturePhase.kt    # Capture phase lifecycle
    │   ├── theme/                 # Dark aesthetic color, typography, theme
    │   ├── CameraPreview.kt       # CameraX preview + Camera2Interop hardware controls
    │   └── CameraScreen.kt        # Root camera & result flipbook gallery screen
    └── viewmodel/
        └── MotionShotViewModel.kt # StateFlow, preferences, capture loop, engine dispatcher
    

    Building & Requirements

    System Requirements

    • Android Studio: Ladybug / Jellyfish or newer
    • Android SDK: Compile SDK 37 (Min SDK 24)
    • Kotlin: 2.2.10
    • Gradle: 8.13+

    Local Build Commands

    # Clone the repository
    git clone https://github.com/AhmadHassan-BTed/MotionShot.git
    cd MotionShot
    
    # Execute unit tests
    ./gradlew test
    
    # Build Debug APK
    ./gradlew assembleDebug