Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Keim, Stefan committed Jun 12, 2021
0 parents commit c5dc8e2
Show file tree
Hide file tree
Showing 22 changed files with 1,030 additions and 0 deletions.
28 changes: 28 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# .coveragerc to control coverage.py
[run]
branch = True
source = kubi
# omit = bad_file.py

[paths]
source =
src/
*/site-packages/

[report]
# Regexes for lines to exclude from consideration
exclude_lines =
# Have to re-enable the standard pragma
pragma: no cover

# Don't complain about missing debug-only code:
def __repr__
if self\.debug

# Don't complain if tests don't hit defensive assertion code:
raise AssertionError
raise NotImplementedError

# Don't complain if non-runnable code isn't run:
if 0:
if __name__ == .__main__.:
58 changes: 58 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Temporary and binary files
*~
*.py[cod]
*.so
*.cfg
!.isort.cfg
!setup.cfg
*.orig
*.log
*.pot
__pycache__/*
.cache/*
.*.swp
*/.ipynb_checkpoints/*
.DS_Store

# Project files
.ropeproject
.project
.pydevproject
.settings
.idea
.vscode
tags

# Package files
*.egg
*.eggs/
.installed.cfg
*.egg-info

# Unittest and coverage
htmlcov/*
.coverage
.coverage.*
.tox
junit*.xml
coverage.xml
.pytest_cache/

# Build and docs folder/files
build/*
dist/*
sdist/*
docs/api/*
docs/_rst/*
docs/_build/*
cover/*
MANIFEST

# Per-project virtualenvs
.venv*/
.conda*/

docs
htmlcov
tests/in
tests/out
5 changes: 5 additions & 0 deletions AUTHORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
============
Contributors
============

* Keim, Stefan <https://github.com/indus>
10 changes: 10 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
=========
Changelog
=========

Version 0.1 "Bowman"
===========

- Basic functionality implemented
- Basic tests implemented (98% coverage | 188run | 0 missing | 2 excluded | 5 partial)
- Simple Benchmarks
21 changes: 21 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2021 Keim, Stefan

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
110 changes: 110 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# kubi

**kubi** is a fast and flexible cubemap generator based on [libvips](https://libvips.github.io/libvips/)

## Install

``` shell
pip install git+https://github.com/indus/kubi.git
```
### Requirements
- [numpy](https://numpy.org/)
- [pyvips](https://libvips.github.io/pyvips/) (bindings for libvips)

## Description

**kubi** can convert equirectangular images into a variety of common [layouts](#layouts). All image formats supported by vips (JPEG, PNG, TIFF, WEBP, HEIF, ...) can be used for input and output. With the [DZ format](https://libvips.github.io/libvips/API/current/Making-image-pyramids.md.html) of libvips it is even possible to [create tiled images](#tiled-cubemaps) of the cubefaces.
When used with a glob pattern for multiple input files, **kubi** generates an [index file](https://libvips.github.io/libvips/API/current/libvips-resample.html#vips-mapim) once and reuses it while processing all found images. This can lead to a [significant speedup](#multiple-input-files).

## Usage
### all options
``` shell
kubi -h
```

### basic usage
``` shell
kubi [-s <size>] [-l {row,column,crossL,crossR,crossH}] srcfile [dstfile]
```

#### Layouts

| none | row | column |
| :---: | :---: | :---: |
| ![none](./img/kubi_layouts_none.png "none") | ![row](./img/kubi_layouts_row.png "row") | ![column](./img/kubi_layouts_column.png "column") |

| ![crossL](./img/kubi_layouts_crossL.png "crossL") | ![crossR](./img/kubi_layouts_crossR.png "crossR") | ![crossH](./img/kubi_layouts_crossH.png "crossH") |
| :---: | :---: | :---: |
| crossL | crossR | crossH |

### tiled cubemaps
``` shell
kubi -s 2048 -co tile_size=512 -co depth=onetile -co overlap=0 -co layout=google -co suffix=.jpg[Q=75] -n l r u d f b srcfile dstfile.dz
```
| argument | explanation |
| :--- | :--- |
| ```-s 2048``` | every cubeface has an overall size of 2048px |
| ```-co tile_size=512``` | every cubeface gets split into tiles with a size of 512px (≙ 3 levels) |
| ```-co depth=onetile``` | stop tiling with onetile (vips default is one pixel!) |
| ```-co overlap=0``` | tiles should have an overlap of 0px (vips default is one pixel!) |
| ```-co layout=google``` | use the google folder/file layout (options are ```dz```, ```zoomify```, ```google```, ```iiif```) |
| ```-co suffix=.jpg[Q=75]```| tiles should be JPEG with a quality of 75 |
| ```-f r l u d f b``` | defined suffixes r(ight), l(eft), u(p), ... |
| ```srcfile``` | the input file; could be a glob pattern |
| ```dstfile.dz``` | the output folder name; use ```.dz``` extension for tiles |

With some fiddling the file and folder structure could be made compatiple to 360° image viewers.
The above would work with [Marzipano](https://www.marzipano.net/):
``` JS
Marzipano.ImageUrlSource.fromString("<some_path>/dstfile_{f}/{z}/{y}/{x}.jpg");
```

## Benchmark

***system:*** CPU: i7-6700 CPU @ 3.40GHz, 4 cores; MEM: 64GB; OS: Win 10

### single input file
***input:*** equirectangular image with 4096x2048px
***output:*** cubemap with a cross layout

| face size | 1024px | 2048px | 4096px |
| ---| --- | --- | --- |
| kubi | 0.9s | 1.7s | 4.9s |
| [py360convert](https://pypi.org/project/py360convert/) | 2.5s | 8.7s | 33.0s |
| *any others ?* | - | - | - |

### single input file - tiled output
***input:*** equirectangular image with 4096x2048px
***output:*** cubemap as seperate tiles

| face size | 1024px | 2048px | 4096px |
| ---| --- | --- | --- |
| kubi | 0.9s | 1.4s | 3.5s |
| [panorama_windows.exe](https://github.com/blackironj/panorama) | 1.4s | 4.4s | 16.8s |
| *any others ?* | - | - | - |

### multiple input files
If only a few cubemaps are needed, performance is probably of minor concern. But with **kubi** it should also be possible to process thousands of animation frames in a reasonable time:

***input:*** multiple equirectangular images with 4096x2048px
***output:*** multiple cubemaps with a cross layout and a face size of 2048px
| count | total time | time per cubemap |
| :---: | :---: | :---: |
| 1 | 1.7s | 1.7s |
| 2 | 2.6s | 1.3s |
| 3 | 3.5s | 1.2s |
| 5 | 5.2s | 1.0s |
| 10 | 9.9s | 1.0s |
| 20 | 18.5s | 0.9s |

# Transforms
In addition to regular cubemaps, two optimized mappings can be generated:
- **Equi-Angular Cubemap (EAC)**; C.Brown (2017): [Bringing pixels front and center in VR video](https://blog.google/products/google-ar-vr/bringing-pixels-front-and-center-vr-video/)
- **Optimized Tangens Cubemap (OTC)**; M.Zucker & Y.Higashi (2018): [Cube-to-sphere Projections for Procedural Texturing and Beyond](http://jcgt.org/published/0007/02/01/paper.pdf) (Ch. 3.2 & Ch. 5)

Both transforms significantly reduce the distortion of the cubemap and thus optimize the pixel yield. However, support in other tools and libraries is rather scarce.

| deviation | ltr: regular cubemap, EAC, OTC |
| :---: | :---: |
| area | ![error_area](./img/error_area.png "error_area")
| distance | ![error_distance](./img/error_distance.png "error_distance")
Binary file added img/error_area.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/error_distance.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/kubi_layouts_column.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/kubi_layouts_crossH.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/kubi_layouts_crossL.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/kubi_layouts_crossR.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/kubi_layouts_none.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/kubi_layouts_row.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
128 changes: 128 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# This file is used to configure your project.
# Read more about the various options under:
# http://setuptools.readthedocs.io/en/latest/setuptools.html#configuring-setup-using-setup-cfg-files

[metadata]
name = kubi
description = cubemap generator
author = Keim, Stefan
license = MIT
long_description = file: README.md
long_description_content_type = text/markdown; charset=UTF-8
url = https://github.com/pyscaffold/pyscaffold/
# Add here related links, for example:
project_urls =
Documentation = https://github.com/indus/kubi/
Source = https://github.com/indus/kubi/
Changelog = https://github.com/indus/kubi/blob/main/CHANGELOG.rst
Tracker = https://github.com/indus/kubi/issues
# Conda-Forge = https://anaconda.org/conda-forge/pyscaffold
Download = https://github.com/indus/kubi/releases/
# Twitter = https://twitter.com/PyScaffold

# Change if running only on Windows, Mac or Linux (comma-separated)
platforms = any

# Add here all kinds of additional classifiers as defined under
# https://pypi.python.org/pypi?%3Aaction=list_classifiers
classifiers =
Development Status :: 4 - Beta
Programming Language :: Python


[options]
zip_safe = False
packages = find_namespace:
include_package_data = True
package_dir =
=src

# Require a min/specific Python version (comma-separated conditions)
# python_requires = >=3.8

# Add here dependencies of your project (line-separated), e.g. requests>=2.2,<3.0.
# Version specifiers like >=2.2,<3.0 avoid problems due to API changes in
# new major versions. This works if the required packages follow Semantic Versioning.
# For more information, check out https://semver.org/.
install_requires =
importlib-metadata; python_version<"3.8"
pyvips
numpy


[options.packages.find]
where = src
exclude =
tests

[options.extras_require]
# Add here additional requirements for extra features, to install with:
# `pip install kubi[PDF]` like:
# PDF = ReportLab; RXP

# Add here test requirements (semicolon/line-separated)
testing =
setuptools
pytest
pytest-cov

[options.entry_points]
# Add here console scripts like:
# console_scripts =
# script_name = kubi.module:function
# For example:
console_scripts =
kubi = kubi.kubi:run
# And any other entry points, for example:
# pyscaffold.cli =
# awesome = pyscaffoldext.awesome.extension:AwesomeExtension

[tool:pytest]
# Specify command line options as you would do when invoking pytest directly.
# e.g. --cov-report html (or xml) for html/xml output or --junitxml junit.xml
# in order to write a coverage file that can be read by Jenkins.
# CAUTION: --cov flags may prohibit setting breakpoints while debugging.
# Comment those flags to avoid this py.test issue.
addopts =
--cov kubi --cov-report term-missing
--verbose
norecursedirs =
dist
build
.tox
testpaths = tests
# Use pytest markers to select/deselect specific tests
# markers =
# slow: mark tests as slow (deselect with '-m "not slow"')
# system: mark end-to-end system tests

[bdist_wheel]
# Use this option if your package is pure-python
universal = 1

[devpi:upload]
# Options for the devpi: PyPI server and packaging tool
# VCS export must be deactivated since we are using setuptools-scm
no_vcs = 1
formats = bdist_wheel

[flake8]
# Some sane defaults for the code style checker flake8
max_line_length = 88
extend_ignore = E203, W503
# ^ Black-compatible
# E203 and W503 have edge cases handled by black
exclude =
.tox
build
dist
.eggs
docs/conf.py

[pyscaffold]
# PyScaffold's parameters when the project was created.
# This will be used when updating. Do not change!
version = 4.0.1
package = kubi
extensions =
no_pyproject
21 changes: 21 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""
Setup file for kubi.
Use setup.cfg to configure your project.
This file was generated with PyScaffold 4.0.1.
PyScaffold helps you to put up the scaffold of your new Python project.
Learn more under: https://pyscaffold.org/
"""
from setuptools import setup

if __name__ == "__main__":
try:
setup(use_scm_version={"version_scheme": "no-guess-dev"})
except: # noqa
print(
"\n\nAn error occurred while building the project, "
"please ensure you have the most updated version of setuptools, "
"setuptools_scm and wheel with:\n"
" pip install -U setuptools setuptools_scm wheel\n\n"
)
raise
Loading

0 comments on commit c5dc8e2

Please sign in to comment.