{"id":20858582,"url":"https://github.com/smidm/flashvideosynchronization","last_synced_at":"2025-07-05T03:33:26.250Z","repository":{"id":145439510,"uuid":"76856193","full_name":"smidm/flashvideosynchronization","owner":"smidm","description":"Sub-millisecond accurate offline multiple video synchronization using camera flashes.","archived":false,"fork":false,"pushed_at":"2024-03-15T10:59:31.000Z","size":145,"stargazers_count":19,"open_issues_count":0,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-03-15T12:08:40.720Z","etag":null,"topics":["camera","capture","offline","post-processing","synchronization"],"latest_commit_sha":null,"homepage":"https://cmp.felk.cvut.cz/~smidm/rolling-shutter-camera-synchronization-with-sub-millisecond-accuracy.html","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/smidm.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2016-12-19T11:26:05.000Z","updated_at":"2024-03-15T10:56:04.000Z","dependencies_parsed_at":"2024-03-15T12:10:59.720Z","dependency_job_id":null,"html_url":"https://github.com/smidm/flashvideosynchronization","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smidm%2Fflashvideosynchronization","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smidm%2Fflashvideosynchronization/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smidm%2Fflashvideosynchronization/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smidm%2Fflashvideosynchronization/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/smidm","download_url":"https://codeload.github.com/smidm/flashvideosynchronization/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225130753,"owners_count":17425506,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["camera","capture","offline","post-processing","synchronization"],"created_at":"2024-11-18T04:46:34.727Z","updated_at":"2024-11-18T04:46:35.172Z","avatar_url":"https://github.com/smidm.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Sub-millisecond Accurate Multiple Video Synchronization Using Camera Flashes\n\nA python module for offline synchronization of multiple videos using flashes present in the footage. The module synchronizes arbitrary number of video sequences when there are present abrupt lighting changes that affect majority of pixels (e.g. flashes). The video sequences do not require overlapping fields of view.\n\nSequences acquired using rolling shutter image sensors (vast majority of CMOS image sensors) can be synchronized up to sub-millisecond accuracy.\n\nOutputs:\n\n- sub-frame synchronized time for a frame, row pair (for rolling shutter)\n- synchronized video sequences (frames with minimal temporal distances from all input sequences)\n\nFor details, sample synchronized videos and published paper see [project page](http://cmp.felk.cvut.cz/~smidm/rolling-shutter-camera-synchronization-with-sub-millisecond-accuracy.html).\n\n## Installation\n\n```\npip install git+https://github.com/smidm/flashvideosynchronization.git\n```\n\n## Download Sample Videos\n\nThree videos with duration ~60 seconds containing multiple camera flashes. Started manually. One camera was\nrecording upside down. \n\n```\ncurl -LO http://cmp.felk.cvut.cz/~smidm/download/sample_data.zip\nunzip sample_data.zip\nrm sample_data.zip\n```\n\nsize: ~200 MB\n\n## CLI\n\nCommand line tool for video synchronization. Features: \n\n- show detected flashes\n- write a preview video montage of synchronized videos\n- write synchronized videos \n- show video files time offsets and other synchronization model parameters \n\n```\nusage: synchronizevideo [-h] [--write-preview WRITE_PREVIEW]\n                        [--out-synchronized-dir OUT_SYNCHRONIZED_DIR]\n                        [--show-flashes] [--model-json] [--model-yaml]\n                        files [files ...]\n\nSynchronize multiple video files containing camera flashes.\n\npositional arguments:\n  files                 input video files\n\noptional arguments:\n  -h, --help            show this help message and exit\n  --write-preview WRITE_PREVIEW\n                        write synchronized preview montage\n  --out-synchronized-dir OUT_SYNCHRONIZED_DIR\n                        write input files synchronized to a directory\n  --show-flashes        show a chart with detected flashes\n  --model-json          print synchronization model in json\n  --model-yaml          print synchronization model in yaml\n```\n\nExamples:\n\n```\n$ synchronizevideo --show-flashes sample_data/*\n\n[Memory]0.0s, 0.0min    : Loading detect_events_in_video...\n[Memory]0.0s, 0.0min    : Loading detect_events_in_video...\n[Memory]0.0s, 0.0min    : Loading detect_events_in_video...\nsample_data/1.mp4: time per sensor row 0.039 ms\nsample_data/2.mp4: time offset -10.68 s, sensor clock drift 0.9997, time per sensor row 0.017 ms\nsample_data/3.mp4: time offset -4.98 s, sensor clock drift 1.0002, time per sensor row 0.036 ms\n```\n\n![detected flashes in input video files](assets/detected_flashes.png)\n\n```\n$ synchronizevideo --write-preview montage.mp4 sample_data/*\n\n[Memory]0.0s, 0.0min    : Loading detect_events_in_video...\n[Memory]0.0s, 0.0min    : Loading detect_events_in_video...\n[Memory]0.0s, 0.0min    : Loading detect_events_in_video...\nsample_data/1.mp4: time per sensor row 0.039 ms\nsample_data/2.mp4: time offset -10.68 s, sensor clock drift 0.9997, time per sensor row 0.017 ms\nsample_data/3.mp4: time offset -4.98 s, sensor clock drift 1.0002, time per sensor row 0.036 ms\n  0%|                                                                                           | 0/576 [00:00\u003c?, ?it/s]\n.../imagesource/video.py:115: UserWarning: using slow but frame accurate seeking (reading frame by frame)\n  warn('using slow but frame accurate seeking (reading frame by frame)')\n100%|█████████████████████████████████████████████████████████████████████████████████| 576/576 [00:15\u003c00:00, 36.92it/s]\n```\n\n![frame from synchronized preview](assets/montage.jpg)\n\n## API\n\n```python\nimport matplotlib.pylab as plt\nimport imagesource\nfrom flashvideosynchronization import FlashVideoSynchronization\n\n# example 3 camera synchronization\ncameras = [1, 2, 3]\nfilenames = {cam: 'sample_data/%d.mp4' % cam for cam in cameras}\n\n# load video files and extract frame timestamps\nsources = {cam: imagesource.TimedVideoSource(filenames[cam])\n           for cam in cameras}\nfor source in sources.values():\n    source.extract_timestamps()\n\nsync = FlashVideoSynchronization()\nsync.detect_flash_events(filenames)\n\n# manually set rough offset by matching an event\nsync.show_events()\nmatching_events = {1: 0, 2: 0, 3: 0}\noffsets = {cam: sync.events[cam][matching_events[cam]]['frame_time'] for cam in cameras}\nsync.show_events(offsets)  # now the events should appear aligned\n\n# synchronize cameras: find parameters transformations that map camera time to reference camera time\nsync.synchronize(cameras, offsets, base_cam=1)\nprint(sync)\n\n# get sub-frame sychronized time for camera 1, frame 10 and row 100\nprint(sync.get_time(cam=1, frame_time=sources[1].timestamps_ms[10], row=100))\n\n# get frame synchronized image sources\nsources_sync = sync.get_synchronized_image_sources(sources, master=1, dropped=False)\n\n# show synchronized frames\nframe = 10\nfor cam in cameras:\n    plt.figure()\n    plt.imshow(sources_sync[cam].get_image(frame))\n\nplt.show()\n```\n\nFor more see [sample.py](sample.py).\n\nThe computationally demanding functions `FlashVideoSynchronization.detect_flash_events()` and `extract_features()` are cached using [joblib](https://pythonhosted.org/joblib/). Until the inputs change, they are computed only once. The cache is stored in `./joblib` directory.\n\nFor more examples see: https://github.com/smidm/flashvideosynchronization-notebook.\n\n## Your Video Sequences\n\nI would like to evaluate the software on more multi-view video sequences with abrupt lighting changes. If you can provide your data, please contact me at http://cmp.felk.cvut.cz/~smidm/.\n\n## Cite\n\nM. Šmíd and J. Matas, “Rolling Shutter Camera Synchronization with Sub-millisecond Accuracy,” in VISAPP - 12th International Conference on Computer Vision Theory and Applications, 2017.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmidm%2Fflashvideosynchronization","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmidm%2Fflashvideosynchronization","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmidm%2Fflashvideosynchronization/lists"}