Slideo: This tool uses OpenCV to automatically synchronize slides with videos that show these slides.

Overview

Slideo: Synchronize Slides With Video

This tool matches video frames against PDF pages by using computer vision. It also ships a web app in which you can click on a PDF page to play the video from the first frame showing the page. Its primary use-case is to quickly play a recorded lecture from a given slide.

Works best if the PDF page in the video is captured through screen recording and video is 1080p, but it might work in other scenarios too (rotation, shifting, scaling, obstruction and additional on-screen content is supported).

See Background for building instructions and how the matching algorithm works.

This is tool is more a proof of concept rather than a polished product. Please reach out if you want to make a nice open source product out of it.

Installation

See Releases. An installer is not yet provided. Feel free to contribute!

Windows Requirements

Linux, Mac Requirements

(untested)

  • OpenCV 4.5.2
  • Poppler

Usage

Synchronize a Set of PDFs With a Set of Videos

Any given lecture slide can appear in any given video. For performance and accuracy, keep the amount of pdf files small and prefer seperate invocations. Synchronizing an entire lecture (<1000 slides) should work well though.

slideo lecture1.pdf lecture2.pdf video1.mp4 video2.mp4

When you know that video1 does not contain any slides of lecture2, you can do this to improve accuracy:

slideo lecture1.pdf video1.mp4 --non-interactive && slideo lecture2.pdf video2.mp4 --non-interactive

View a Synchronized PDF

slideo lecture1.pdf

This will spawn a webserver on port 63944 and print an url that you can open in your favorite browser to open the viewer.

You can drag&drop any processed PDF into the viewer!

TODO

  • Use wry to build a proper web GUI.
  • Use rustcv to get rid of the OpenCV dependency.

Other Stuff You Might Like

A big Thank You to all my sponsors on GitHub!

You might also like...
A cross-platform tool for embedding GPS data into photographs

nya-exif 中文 | English 介绍 nya-exif 是一个用于匹配照片 GPS 信息, 并写入文件 EXIF 信息的工具, 支持 JPEG 和 PNG 及各大相机厂商的主流RAW格式. 本工具基于 Rust 编写, 支持全平台使用 Features 支持 JPEG 和 PNG 及各大

👩‍❤️‍💋‍👩 Synchronize installed packages on multiple machines
👩‍❤️‍💋‍👩 Synchronize installed packages on multiple machines

emplace Command-line tool to mirror installed software on multiple machines. Features Outputs a human-readable (RON) file to sync between machines: .e

Synchronize games from other platforms into your Steam library

BoilR Description This little tool will synchronize games from other platforms into your Steam library, using the Steam Shortcuts feature. The goal is

Mycelite is a SQLite extension that allows you to synchronize changes from one instance of SQLite to another.

Mycelite What is Mycelite? Mycelite is a SQLite extension that allows you to synchronize changes from one instance of SQLite to another. Currently, it

Repository containing schedules, slides/talk and user submissions for the 2023 devconnect hackerhouse

2023 DevConnect Hacker House Content Schedule Hackathon Tracks xChain dapps - Total Prize pool of USD 12k (5k, 4k, 3k) Fully on-chain dapps - Total Pr

Schema2000 is a tool that parses exsiting JSON documents and tries to derive a JSON schema from these documents.

Schema 2000 Schema2000 is a tool that parses exsiting JSON documents and tries to derive a JSON schema from these documents. Currently, Schema2000 is

A CLI tool that uses ChatGPT to automatically generate commit messages.

Auto Git Commit This project is a tool that uses the OpenAI GPT model to automatically generate commit messages for Git commits based on the changes m

Rust bindings for OpenCV 3 & 4

Rust OpenCV bindings Experimental Rust bindings for OpenCV 3 and 4. The API is usable, but unstable and not very battle-tested; use at your own risk.

OpenCV Sample Projects in Rust

OpenCV Sample Projects in Rust

Motion detection & video recording software based on OpenCV, built for research on Bumblebees

BombusCV Motion detection & video recording software based on OpenCV, built for research on Bumblebees (hence the name). Index Use case Examples Insta

Just set of functions to utilize YOLO v3, v4, v7 and v8 version with OpenCV's DNN module

Object detection utilities in Rust programming language for YOLO-based neural networks in OpenCV ecosystem This crate provides some basic structures a

Host These Things Please - a basic http server for hosting a folder fast and simply

http Host These Things Please - a basic HTTP server for hosting a folder fast and simply Selected features See the manpage for full list. Symlinks fol

Interfaces for Relations and SNARKs for these relations

SNARK and Relation Traits The arkworks ecosystem consists of Rust libraries for designing and working with zero knowledge succinct non-interactive arg

I'm currently learning Rust and these are my first programs with this language

learning-Rust I follow the Rust by example official doc for learning That is also available in 'doc pdf' alongside another great rust learning sheet I

A CLI tool that converts videos to ASCII and displays them to the terminal on the fly
A CLI tool that converts videos to ASCII and displays them to the terminal on the fly

A CLI tool that converts videos to ASCII and displays them to the terminal on the fly

A bunch of links to blog posts, articles, videos, etc for learning Rust

rust-learning A bunch of links to blog posts, articles, videos, etc for learning Rust. Feel free to submit a pull request if you have some links/resou

Plays back videos in your terminal in an insanely slow and inefficient way.
Plays back videos in your terminal in an insanely slow and inefficient way.

term-video I guess this is usable now... Compilation Since this project is built using Rust, install its toolchain first, for example using rustup. gi

📼 Wrapper around ffmpeg which simplifies merging of multiple videos
📼 Wrapper around ffmpeg which simplifies merging of multiple videos

Vidmerger A wrapper around ffmpeg which simplifies merging of multiple videos. 🙉 What is this exactly? Vidmerger is a command-line-tool which uses ff

Nazuna - 🐦  Download Twitter videos using your terminal!
Nazuna - 🐦 Download Twitter videos using your terminal!

Nazuna 🐦 Download Twitter videos using your terminal! Installation Binary Download the desired file for your OS (Windows, Mac, Linux) from https://gi

Comments
  • Missing Documentation for building

    Missing Documentation for building

    Today I tried to build this project because I am using MacOS and the opencv-linking seemed to be broken. using cargo was easy (even though I am not that familiar with rust but finding out that the page needed to be built using yarn was quite something.

    Some building documentation would be nice. (Some lines on where to use cargo build and yarn install && yarn build).

    opened by LukasSchulz 4
  • attempt to subtract with overflow in db.rs

    attempt to subtract with overflow in db.rs

    When trying to build and run on macos/linux I get the following error: thread 'main' panicked at 'attempt to subtract with overflow', crates/app/src/db.rs:180:31 I seemed to have already fixed the issue by modifying the db.rs file (after some googling I found out that this issue seems to accur, when you try to subtract 1 from 0)

    diff --git a/crates/app/src/db.rs b/crates/app/src/db.rs
    index 2478358..da7e2b1 100644
    --- a/crates/app/src/db.rs
    +++ b/crates/app/src/db.rs
    @@ -177,7 +177,12 @@ impl<'a> Db<'a, TransactionMarker> {
                 let pdf_hash = matching.image.map(|p| p.pdf_hash);
                 let video_ms = matching.video_time.as_millis() as u32;
                 let page_nr = matching.image.map(|p| p.page_nr as u32).unwrap_or(0);
    -            let page_offset = page_nr - 1;
    +            let page_offset;
    +            if page_nr > 0 {
    +                page_offset = page_nr - 1;
    +            } else {
    +                page_offset = 0;
    +            }
                 sqlx::query!(
                     "INSERT INTO videos_mapping(video_id, video_ms, pdf_hash, page) VALUES (?, ?, ?, ?)",
                     video_id,
    
    opened by LukasSchulz 1
  • Comment on design

    Comment on design

    Hi, I was looking for such software... If I am right, the slide matching can be done by a background processing application that return a JSON slide timing output to perform a bisect. This application can be written in C++, or even in Python since most of the job in done in OpenCV. MuPDF could be used to render the PDF page as a better alternative to Poppler. Then the display can be done by a web application that connect the video current time to PDF.js For sure such application is trivial to build in Qt QML. Well, I don't understand why you want to use Rust for everything.

    opened by FabriceSalvaire 1
  • thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', in slideo/crates/matching-opencv/src/lib.rs:371:69 stack backtrace:

    thread '' panicked at 'called `Option::unwrap()` on a `None` value', in slideo/crates/matching-opencv/src/lib.rs:371:69 stack backtrace:

    On some Videos/pdf-combinations I get this error on MacOS while slideo is processing frames: (This only happens on certain frames and always on the same ones)

    Then, after completely processing the video the webserver isn't started and when the pdf is opened manually by executing slideo file.pdf the pdf doesn't have any timestamps.

    Full Backtrace:

    thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', /Users/lukas/Documents/slideo/crates/matching-opencv/src/lib.rs:371:69
    stack backtrace:
       0:        0x10bcf78de - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h04abbaabf148650a
       1:        0x10bd3a98e - core::fmt::write::h14dac7cadec1cc70
       2:        0x10bcf708a - std::io::Write::write_fmt::hfaf2e10dfdcc61d8
       3:        0x10bd159e9 - std::panicking::default_hook::{{closure}}::h350fee0bf60f2674
       4:        0x10bd1555b - std::panicking::default_hook::h0b4e3bc46e6dcb8d
       5:        0x10bd15f7a - std::panicking::rust_panic_with_hook::h8cdc0a575f4a5a7b
       6:        0x10bcf8079 - std::panicking::begin_panic_handler::{{closure}}::h7a7b30fd1c313876
       7:        0x10bcf7a28 - std::sys_common::backtrace::__rust_end_short_backtrace::h2e099be83c81509d
       8:        0x10bd15af3 - _rust_begin_unwind
       9:        0x10bd473ef - core::panicking::panic_fmt::h4f63e4f6b62b650b
      10:        0x10bd47347 - core::panicking::panic::hb3c06f51e2e58141
      11:        0x10afa59a9 - core::option::Option<T>::unwrap::hb3706e21acd48f48
                                   at /opt/local/var/macports/build/_opt_bblocal_var_buildworker_ports_build_ports_lang_rust/rust/work/rustc-1.51.0-src/library/core/src/option.rs:386:21
      12:        0x10b105cb2 - matching_opencv::OpenCVVideoMatcherTask<I>::match_images_with_frame::{{closure}}::h6ac2efa761b34801
                                   at /Users/lukas/Documents/slideo/crates/matching-opencv/src/lib.rs:371:47
      13:        0x10b0e2242 - alloc::slice::<impl [T]>::sort_by::{{closure}}::h4e32b55bca503dbc
                                   at /opt/local/var/macports/build/_opt_bblocal_var_buildworker_ports_build_ports_lang_rust/rust/work/rustc-1.51.0-src/library/alloc/src/slice.rs:311:33
      14:        0x10b0e0f62 - alloc::slice::insert_head::h22f59d896a4d25dc
                                   at /opt/local/var/macports/build/_opt_bblocal_var_buildworker_ports_build_ports_lang_rust/rust/work/rustc-1.51.0-src/library/alloc/src/slice.rs:840:24
      15:        0x10b0dd846 - alloc::slice::merge_sort::h50931d4fdb6fb654
                                   at /opt/local/var/macports/build/_opt_bblocal_var_buildworker_ports_build_ports_lang_rust/rust/work/rustc-1.51.0-src/library/alloc/src/slice.rs:1047:17
      16:        0x10b108531 - alloc::slice::<impl [T]>::sort_by::h296008c9323b96d6
                                   at /opt/local/var/macports/build/_opt_bblocal_var_buildworker_ports_build_ports_lang_rust/rust/work/rustc-1.51.0-src/library/alloc/src/slice.rs:311:9
      17:        0x10b1054cb - matching_opencv::OpenCVVideoMatcherTask<I>::match_images_with_frame::h2e9e32b4065f5258
                                   at /Users/lukas/Documents/slideo/crates/matching-opencv/src/lib.rs:371:13
      18:        0x10b103ea8 - <matching_opencv::OpenCVVideoMatcherTask<I> as matching::VideoMatcherTask<I>>::process::{{closure}}::{{closure}}::h69525bcbd55619bc
                                   at /Users/lukas/Documents/slideo/crates/matching-opencv/src/lib.rs:214:36
      19:        0x10b0239d6 - rayon_core::scope::ScopeFifo::spawn_fifo::{{closure}}::{{closure}}::h14d50d9aafa378d9
                                   at /Users/lukas/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.0/src/scope/mod.rs:495:47
      20:        0x10b116d31 - <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once::h82d2844e73051b6f
                                   at /opt/local/var/macports/build/_opt_bblocal_var_buildworker_ports_build_ports_lang_rust/rust/work/rustc-1.51.0-src/library/std/src/panic.rs:344:9
      21:        0x10b00bf95 - std::panicking::try::do_call::h43dc9bd5aa331631
                                   at /opt/local/var/macports/build/_opt_bblocal_var_buildworker_ports_build_ports_lang_rust/rust/work/rustc-1.51.0-src/library/std/src/panicking.rs:379:40
      22:        0x10b00de3d - ___rust_try
      23:        0x10b00a231 - std::panicking::try::h93de8b23b179aca6
                                   at /opt/local/var/macports/build/_opt_bblocal_var_buildworker_ports_build_ports_lang_rust/rust/work/rustc-1.51.0-src/library/std/src/panicking.rs:343:19
      24:        0x10b1177e1 - std::panic::catch_unwind::haa922ddd00603855
                                   at /opt/local/var/macports/build/_opt_bblocal_var_buildworker_ports_build_ports_lang_rust/rust/work/rustc-1.51.0-src/library/std/src/panic.rs:431:14
      25:        0x10b15dd11 - rayon_core::unwind::halt_unwinding::hb8f4d4b69b63ef43
                                   at /Users/lukas/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.0/src/unwind.rs:17:5
      26:        0x10b023491 - rayon_core::scope::ScopeBase::execute_job_closure::h2b938e0ac14a5ca7
                                   at /Users/lukas/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.0/src/scope/mod.rs:561:15
      27:        0x10b023425 - rayon_core::scope::ScopeBase::execute_job::h8bcba628953f50d9
                                   at /Users/lukas/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.0/src/scope/mod.rs:549:29
      28:        0x10b02397d - rayon_core::scope::ScopeFifo::spawn_fifo::{{closure}}::hcd25299f0e0d3306
                                   at /Users/lukas/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.0/src/scope/mod.rs:495:17
      29:        0x10b0d35dd - <rayon_core::job::HeapJob<BODY> as rayon_core::job::Job>::execute::ha6e2be962215648e
                                   at /Users/lukas/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.0/src/job.rs:167:9
      30:        0x10b7532b5 - rayon_core::job::JobRef::execute::h9905210a4b77f273
                                   at /Users/lukas/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.0/src/job.rs:59:9
      31:        0x10b7533c8 - <rayon_core::job::JobFifo as rayon_core::job::Job>::execute::ha3c023d7050ec006
                                   at /Users/lukas/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.0/src/job.rs:211:50
      32:        0x10b7532b5 - rayon_core::job::JobRef::execute::h9905210a4b77f273
                                   at /Users/lukas/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.0/src/job.rs:59:9
      33:        0x10b728e3d - rayon_core::registry::WorkerThread::execute::h52bdcf205839c2ce
                                   at /Users/lukas/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.0/src/registry.rs:753:9
      34:        0x10bd41548 - rayon_core::registry::WorkerThread::wait_until_cold::h856430079a15650f
                                   at /Users/lukas/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.0/src/registry.rs:730:17
      35:        0x10b728c78 - rayon_core::registry::WorkerThread::wait_until::ha9dbb2d013ef9bc2
                                   at /Users/lukas/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.0/src/registry.rs:704:13
      36:        0x10b7295f3 - rayon_core::registry::main_loop::h2141c7566ae34282
                                   at /Users/lukas/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.0/src/registry.rs:837:5
      37:        0x10b7264c0 - rayon_core::registry::ThreadBuilder::run::hccf2fa9a1df253e9
                                   at /Users/lukas/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.0/src/registry.rs:56:18
      38:        0x10b7269d1 - <rayon_core::registry::DefaultSpawn as rayon_core::registry::ThreadSpawn>::spawn::{{closure}}::h70f699ea15ed07e4
                                   at /Users/lukas/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.0/src/registry.rs:101:20
      39:        0x10b72f860 - std::sys_common::backtrace::__rust_begin_short_backtrace::hfdc1dafbe1be5b5f
                                   at /opt/local/var/macports/build/_opt_bblocal_var_buildworker_ports_build_ports_lang_rust/rust/work/rustc-1.51.0-src/library/std/src/sys_common/backtrace.rs:125:18
      40:        0x10b73d8b1 - std::thread::Builder::spawn_unchecked::{{closure}}::{{closure}}::h8f274698cf915304
                                   at /opt/local/var/macports/build/_opt_bblocal_var_buildworker_ports_build_ports_lang_rust/rust/work/rustc-1.51.0-src/library/std/src/thread/mod.rs:474:17
      41:        0x10b7534a4 - <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once::h3f5ee8f562c0bcc0
                                   at /opt/local/var/macports/build/_opt_bblocal_var_buildworker_ports_build_ports_lang_rust/rust/work/rustc-1.51.0-src/library/std/src/panic.rs:344:9
      42:        0x10b72ac45 - std::panicking::try::do_call::hc7ca871d6321fd0b
                                   at /opt/local/var/macports/build/_opt_bblocal_var_buildworker_ports_build_ports_lang_rust/rust/work/rustc-1.51.0-src/library/std/src/panicking.rs:379:40
      43:        0x10b72cf8d - ___rust_try
      44:        0x10b72a6c1 - std::panicking::try::h67011bda65e0bc0b
                                   at /opt/local/var/macports/build/_opt_bblocal_var_buildworker_ports_build_ports_lang_rust/rust/work/rustc-1.51.0-src/library/std/src/panicking.rs:343:19
      45:        0x10b753e94 - std::panic::catch_unwind::h03d7cd8b3a38bb63
                                   at /opt/local/var/macports/build/_opt_bblocal_var_buildworker_ports_build_ports_lang_rust/rust/work/rustc-1.51.0-src/library/std/src/panic.rs:431:14
      46:        0x10b73d07e - std::thread::Builder::spawn_unchecked::{{closure}}::h7e67fa4f6020f6d7
                                   at /opt/local/var/macports/build/_opt_bblocal_var_buildworker_ports_build_ports_lang_rust/rust/work/rustc-1.51.0-src/library/std/src/thread/mod.rs:473:30
      47:        0x10b741ed1 - core::ops::function::FnOnce::call_once{{vtable.shim}}::h9a7c2579ff92d2b4
                                   at /opt/local/var/macports/build/_opt_bblocal_var_buildworker_ports_build_ports_lang_rust/rust/work/rustc-1.51.0-src/library/core/src/ops/function.rs:227:5
      48:        0x10bd2023b - std::sys::unix::thread::Thread::new::thread_start::h2ede5f70c14488e7
      49:     0x7fff6a7db109 - __pthread_start
    

    Commenting out line 370 in the mentioined lib.rs seems to fix the issue even though I don't know why. The program also seems to still work fine after commenting out this line, because the same thing is written in line 329.

    opened by LukasSchulz 10
Owner
Henning Dieterichs
Let's build the software of the future!
Henning Dieterichs
OpenCV Sample Projects in Rust

OpenCV Sample Projects in Rust

iwatake 9 Jan 28, 2022
Motion detection & video recording software based on OpenCV, built for research on Bumblebees

BombusCV Motion detection & video recording software based on OpenCV, built for research on Bumblebees (hence the name). Index Use case Examples Insta

Marco Radocchia 7 Dec 27, 2022
Just set of functions to utilize YOLO v3, v4, v7 and v8 version with OpenCV's DNN module

Object detection utilities in Rust programming language for YOLO-based neural networks in OpenCV ecosystem This crate provides some basic structures a

Dimitrii Lopanov 3 Nov 17, 2023
CLI and utilities for converting media files (images/videos) to ascii outputs (output media file or print to console)

CLI and utilities for converting media files (images/videos) to ascii outputs (output media file or print to console). Supports most standard image formats, and some video formats.

Michael 30 Jan 1, 2023
Lust is a static image server designed to automatically convert uploaded image to several formats and preset sizes

What is Lust? Lust is a static image server designed to automatically convert uploaded image to several formats and preset sizes with scaling in mind.

Harrison Burt 242 Dec 22, 2022
tai (Terminal Ascii Image) tool to convert images to ascii written in Rust

TAI Terminal Ascii Image A tool to convert images to ascii art written in Rust ?? Notes This tool is still in development stage. Contributions All Con

Mustafa Salih 258 Dec 5, 2022
The tool to make svg with triangles by length from two points.

The tool to make svg with triangles by length from two points.

null 2 Sep 27, 2021
Signed distance field font and image command line tool based on OpenCL.

SDFTool Signed distance field font and image command line tool based on OpenCL. Build Windows Run cargo build --release in Visual Studio developer x64

弦语蝶梦 7 Oct 16, 2022
A support tool for creating shaders that display pixel arts.

dot2shader --> PRE-BUILD PAGE IS HERE <-- A tool for generating shaders displaying pixel art textures in Shadertoy and twigl. Quick start Go to pre-bu

理論屋 2 Feb 17, 2022
Focus Annotator - a tool for annotation the focal plane of a part of an image

Focus Annotator Focus Annotator is a tool for annotation the focal plane of a part of an image. It is a tool I built in rust as part of my master's th

Hannes Kuchelmeister 17 Sep 27, 2022