{"id":16117115,"url":"https://github.com/mlange-42/chrono-photo","last_synced_at":"2026-03-09T04:07:41.195Z","repository":{"id":137862543,"uuid":"251459055","full_name":"mlange-42/chrono-photo","owner":"mlange-42","description":"Chronophotography command line tool and library in Rust.","archived":false,"fork":false,"pushed_at":"2020-05-02T15:28:29.000Z","size":359,"stargazers_count":16,"open_issues_count":8,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-02T14:51:41.188Z","etag":null,"topics":["chrono-photo","chronophotography","image-processing","ornithology","outlier-detection","photo","photography","rust"],"latest_commit_sha":null,"homepage":"https://mlange-42.github.io/chrono-photo/","language":"Rust","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/mlange-42.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,"publiccode":null,"codemeta":null}},"created_at":"2020-03-31T00:19:12.000Z","updated_at":"2025-03-24T05:56:59.000Z","dependencies_parsed_at":"2023-07-01T19:15:48.063Z","dependency_job_id":null,"html_url":"https://github.com/mlange-42/chrono-photo","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/mlange-42/chrono-photo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mlange-42%2Fchrono-photo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mlange-42%2Fchrono-photo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mlange-42%2Fchrono-photo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mlange-42%2Fchrono-photo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mlange-42","download_url":"https://codeload.github.com/mlange-42/chrono-photo/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mlange-42%2Fchrono-photo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30282739,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-09T02:57:19.223Z","status":"ssl_error","status_checked_at":"2026-03-09T02:56:26.373Z","response_time":61,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["chrono-photo","chronophotography","image-processing","ornithology","outlier-detection","photo","photography","rust"],"created_at":"2024-10-09T20:28:34.178Z","updated_at":"2026-03-09T04:07:41.033Z","avatar_url":"https://github.com/mlange-42.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# chrono-photo\n\n[![Build Status](https://travis-ci.com/mlange-42/chrono-photo.svg?branch=master)](https://travis-ci.com/mlange-42/chrono-photo)\n\nChronophotography command line tool and library in [Rust](https://www.rust-lang.org/).\n\nThis tool helps to create chrono-photos like \n[Xavi Bou's \"Ornithographies\"](http://www.xavibou.com/index.php/project/ornitographies/) \nfrom photo series or ([later](#how-to-prepare-videos)) video footage.\n\n* **[Download binaries](https://github.com/mlange-42/chrono-photo/releases/)**\n* [Sources on GitHub](https://github.com/mlange-42/chrono-photo)\n* [Image gallery](docs/gallery.md)\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/44003176/77975353-236da480-72fa-11ea-9ff9-5c110895fe5d.jpg\" alt=\"A simple Chronophotography example\" width=\"750\" /\u003e\u003cbr/\u003e\n\u003csup\u003e\u003ci\u003eA simple Chronophotography example\u003c/i\u003e\u003c/sup\u003e\n\u003c/p\u003e\n\n**Content**\n* [Features](#features)\n* [Installation](#installation)\n* [Getting started](#getting-started)\n* [Tutorials](#tutorials)\n* [Examples](#examples)\n* [How it works](#how-it-works)\n* [Command line options](#command-line-options)\n* [How to prepare videos](#how-to-prepare-videos)\n* [Library / crate](#library--crate)\n* [License](#license)\n\n## Features\n\n* Complete chrono-photography workflow in a single command\n* Create chrono-photos and chrono-videos\n* Different algorithms, maximum control:\n  * Powerful and flexible outlier-based core algorithm\n  * Simple and fast alternative algorithms\n* Process virtually unlimited amounts of images with minimal memory footprint\n* Camera shake correction\n* Multi-threading\n\n## Installation\n\n* Download the [latest binaries](https://github.com/mlange-42/chrono-photo/releases).\n* Unzip somewhere with write privileges (only required for running examples in place).\n\n## Getting started\n\n* Try the example batch files in sub-directory [/cmd_examples](https://github.com/mlange-42/chrono-photo/tree/master/cmd_examples)\n(run `create-test-data` before to generate the required example data). \n* See section [Command line options](#command-line-options) or run `chrono-photo --help` to view the full list of options.\n* See [docs/options.md](docs/options.md) for a detailed explanation of all options.\n* See section [How it works](#how-it-works) for an explanation of the algorithm .\n\n## Tutorials\n\n* [Recording material for chrono-photo](docs/tutorial_recording.md)\n* [Preparing video material](docs/tutorial_prepare.md)\n* **[Creating chrono-photos](docs/tutorial_photos.md)**\n* [Creating chrono-videos](docs/tutorial_videos.md)\n\n## Examples\n\nMinimal example:\n```\nchrono-photo ^\n  --pattern \"input/image-*.jpg\" ^\n  --output output/out.jpg\n```\n\n\u003e _Note 1:_ The ^ at the end of each line is required for breaking commands into multiple lines (at least on Windows).\n\n\u003e _Note 2:_ You can copy the chrono-photo executable anywhere to use it with convenient paths,\nin case adding it to the PATH environmental variable is not an option. \nNo further files from the installation directory are required to run chrono-photo.\n\nFor more options, see [Command line options](#command-line-options).\n\n## How it works\n\nThe basic algorithm to use is selected by option `--mode`.\n\nThree different modes are available: `darker`, `lighter` and `outlier`. \nThe first two modes simply select the darkest or brightest value found for a certain pixel among all images.\nCalculations are very fast, but control over the result is limited.\n\nThe core algorithm of this tool, which is explained in detail below,\nis based on outlier detection (`--mode outlier`).\nThis method offers great control over the result and can handle a far wider range of scenarios.\nHowever, it is also computationally more expensive.\n\nThe principle idea is to stack all images to be processes, and analyze the entire stack pixel by pixel\n(but see also section [Technical realization](#technical-realization)).\n\nGiven a typical use case like a moving object in front of a static background, \na certain pixel will have very similar colors in most images. \nIn one or a few images, the pixel's value may be different, as it shows the object rather than the background.\nI.e. among the pixel's color from all images, these images would be outliers.\n\nThe idea now is to use these outliers for the output image, if they exist for a certain pixel,\nor a non-outlier if they don't. Actually, the algorithm blends the outlier into the background depending on \"how much of an outlier\" it is.\n\n### Outlier detection\n\nOutlier detection in the current version uses multi-dimensional distance to the median,\nand an absolute or relative (lower) threshold provided via option `--threshold` (default: abs. 0.05; `--threshold abs/0.05/0.2`). \nThe _absolute_ threshold (recommended, typically \u003c 1) is relative to the per-band color range (i.e. fraction of range [0, 255] for 8 bits per color band),\nwhile the _relative_ threshold (typically \u003e 1) is relative to the inter-quartile range in each band/dimension.\n\nA pixel value is categorized as an outlier if it's distance from the median is at least the threshold.\nIf multiple outliers are found, one is selected according the description in \n[Pixel selection among outliers](#pixel-selection-among-outliers).\n\nIf the distance of the outlier to the median is between lower and upper threshold (the two numbers in `--threshold abs/0.05/0.2`),\nthe pixel color is blended between background and outlier (linear). \nIf the distance is above the upper threshold, the outlier's color is used without blending.\n\n#### Pixel selection among outliers\n\nIf only one outlier is found for a pixel, it is used as the pixel's value.\n\nIf more than one outlier is found for a pixel, different methods can be used to select among them \nvia **option `--outlier`**:\n* `extreme`: use the most extreme outlier (the default value).\n* `average`: use the average of all outliers.\n* `forward`, `backward`: progressively blends all outliers over the background, starting with the first or last, respectively.\n* `first`: use the first outlier found.\n* `last`: use the last outlier found.\n\n#### Background pixel selection\n\nIf no outliers are found for a pixel (or for blending), different methods can be used to select the \npixel's value via **option `--background`**:\n* `random`: Use a randomly selected pixel value, selected among all non-outlier images. The default value, but may result in a noisy image.\n* `first`: Use the pixel value from the first non-outlier image.\n* `average`: Use the average pixel value of all non-outlier images. Can be used for blurring, but may result in banding for low contrast backgrounds.\n* `median`: Use the median pixel value of all images (including outliers!). May result in banding for low contrast backgrounds.\n\n#### Parameter selection\n\nFinding the best options for pixel selection, as well as an outlier threshold that fits the noise in the input images,\nmay require some trial and error.\n\nIn addition to inspection of the produced image, use option `--output-blend \u003cpath\u003e` to write a greyscale\nimage showing which pixels were filled based on outliers (greyscale blend value), and which were not (black).\n\nIf there are black pixels inside the moving object(s), the outlier threshold(s) should be decreased. \nOn the other hand, if there are white or grey pixels outside the moving object(s), the threshold(s) should be increased\n(may happen due to too much image noise, an insufficiently steady camera, or due to motion in the background).\n\n### Technical realization\n\nHolding a large number of high resolution images in memory at the same time is not feasible. \n\nTherefore, before actual processing, the time-stack of images with (x, y) coordinates\nis converted into a number of temporary files, each containing data in (x, t) coordinates.\nFor example, the first temporary file contains the first row of pixels from each image.\n\nUsing these temporary files, all images can be processes row by row, without overloading memory, as explained above.\n\nActually, the above description is a simplification. Option `--slice` provides control\nover how much data from each image goes into each temporary file. The option accepts different forms.\nExamples:\n* `--slice rows/4`: Writes 4 rows of each image into each time slice.\n* `--slice pixels/1000`: Writes 1000 pixels of each image into each time slice.\n* `--slice count/100`: Internally determines the amount of data written, in order to create a total of 100 time slices.\n\nThe default (`rows/4`) should be sufficient for most scenarios. \n\n**Higher values** can however be used to reduce the number of temporary files created, \nand to slightly increase the efficiently of compression of these files.\n\n**Lower values** may be necessary when processing really huge numbers of images.\nDuring the actual processing, one entire time slice file is loaded into memory at a time.\nAs an example, processing 100'000 frames in Full HD resolution with `--slice rows/1` requires loading\n`frames * width` pixels (200 megapixels) into memory, which are approximately 600 MB. \nBy writing, e.g., only half a row per file (`--slice pixels/960` for Full HD),\nmemory usage can also be reduces to the half, while producing twice as many temporary files.\n\n## Command line options\n\n**For detailed explanation, see [docs/options.md](docs/options.md)**.\n\n```\nCommand-line tool for combining images into a single chrono-photograph or chrono-video.\n\nUse `chrono-photo -h`     for help, or\n    `chrono-photo --help` for more detailed help.\n\nFor more documentation and explanation of the algorithm, see the GitHub repository:\n     https://mlange-42.github.io/chrono-photo/\n\nUSAGE:\n    chrono-photo [FLAGS] [OPTIONS] --output \u003cpath\u003e --pattern \u003cpattern\u003e\n\nFLAGS:\n    -d, --debug      Prints debug information (i.e. parsed cmd parameters) before processing\n    -h, --help       Prints help information\n    -V, --version    Prints version information\n    -w, --wait       Keeps the terminal open after processing and waits for user key press\n\nOPTIONS:\n    -b, --background \u003cbg\u003e           Background pixel selection mode (first|random|average|median). Optional, default\n                                    'random'. Used with `--mode outlier` only\n    -c, --compression \u003ccomp/lev\u003e    Compression mode and level (0 to 9) for time slices (gzip|zlib|deflate)[/\u003clevel\u003e].\n                                    Used with `--mode outlier` only. Optional, default 'gzip/6'\n        --fade \u003cfade\u003e               Frame fading. Optional, default None. Format:\n                                    (clamp|repeat)/(abs|rel)/(f1,v1)/(f2,v2)[/(f,v)...]\n    -f, --frames \u003cframes\u003e           Frames to be used from those matching pattern: `start/end/step`. Optional. For\n                                    default values, use `.`, e.g. `././2`\n    -m, --mode \u003cmode\u003e               Pixel selection mode (lighter|darker|outlier). Optional, default 'outlier'\n    -l, --outlier \u003cmode\u003e            Outlier selection mode in case more than one outlier is found\n                                    (first|last|extreme|average|forward|backward). Optional, default 'extreme'. Used\n                                    with `--mode outlier` only\n    -o, --output \u003cpath\u003e             Path to output file\n        --output-blend \u003cpath\u003e       Path of output image showing which pixels are outliers (blend value). Used with\n                                    `--mode outlier` only\n    -p, --pattern \u003cpattern\u003e         File search pattern. ** MUST be quoted on Unix systems! **\n    -q, --quality \u003cquality\u003e         Output image quality for JPG files, in percent. Optional, default '95'\n        --sample \u003csample\u003e           Restricts calculation of median and inter-quartile range to a sub-sample of input\n                                    images. Use for large amounts of images to speed up calculations. Optional. Used\n                                    with `--mode outlier` only\n        --shake \u003cr1/r2\u003e             Camera shake reduction parameters. Optional, default none. Format: `anchor-\n                                    radius/shake-radius`\n        --shake-anchors \u003cx/y\u003e...    Camera shake reduction anchors. Optional, default none. Format: `x1/y1 [x2/y2\n                                    [...]]`\n        --shake-threads \u003cnum\u003e       Number of threads for camera shake reduction. Optional, default equal to number of\n                                    processors. Limiting this may be required if memory usage is too high\n    -s, --slice \u003cslice\u003e             Controls slicing to temp files (rows|pixels|count)/\u003cnumber\u003e. Used with `--mode\n                                    outlier` only. Optional, default 'rows/4'\n        --temp-dir \u003cpath\u003e           Temp directory. Used with `--mode outlier` only. Optional, default system temp\n                                    directory\n        --threads \u003cnum\u003e             Number of threads. Optional, default equal to number of processors\n    -t, --threshold \u003cthresh\u003e        Outlier threshold mode (abs|rel)/\u003clower\u003e[/\u003cupper\u003e]. Optional, default\n                                    'abs/0.05/0.2'. Used with `--mode outlier` only\n        --video-in \u003cframes\u003e         Video input frames. Frames to be used per video frame: `start/end/step`. Optional\n        --video-out \u003cframes\u003e        Video output frames. Range and step width of video output frames: `start/end/step`.\n                                    Optional\n        --video-threads \u003cnum\u003e       Number of threads for parallel video frame output. Optional, default equal to\n                                    number of processors. Limiting this may be required if memory usage is too high\n        --weights \u003cw\u003e...            Color channel weights (4 values: RGBA) for distance calculation. Optional, default\n                                    '1 1 1 1'\n```\n\n## How to prepare videos\n\nSee also the tutorial on [Preparing video material](docs/tutorial_prepare.md).\n\nThere is no support for direct video file processing _yet_.\n\nTo process videos, they have to be converted into a sequence of images by a third party tool.\nE.g. with the open source software [Blender](https://www.blender.org/),\nusing it's _Video Sequencer_. The required settings are shown in the image below\n(particularly, see 'Output' in the bottom-left corner).\n\n![Blender-VideoSequencer](https://user-images.githubusercontent.com/44003176/78508454-58a94500-7787-11ea-9e55-675e88cf14d7.PNG)  \n_Blender with_ Video Sequencer _view (right part) and required output settings (bottom left).\nTo start rendering, click 'Render Animation' in menu 'Render' (top-most menu bar) or press Ctrl+F12._\n\n## Library / crate\n\nTo use this crate as a library, add the following to your `Cargo.toml` dependencies section:\n```\nchrono-photo = { git = \"https://github.com/mlange-42/chrono-photo.git\" }\n```\n\n_Warning:_ The API is still incomplete and highly unstable, so be prepared for frequent changes. \nAny help to stabilize the API is highly appreciated.\n\nFor the latest development version, see branch [`dev`](https://github.com/mlange-42/chrono-photo/tree/dev).\n\n## License\n\n[MIT](LICENSE) \u0026copy; M. Lange","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmlange-42%2Fchrono-photo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmlange-42%2Fchrono-photo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmlange-42%2Fchrono-photo/lists"}