diff --git a/README.md b/README.md index 975c1f5..f8d476e 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![build status](https://git.sofusrose.com/so-rose/openlut/badges/master/build.svg)](https://git.sofusrose.com/so-rose/openlut/commits/master) **Main Dev Repo**: https://git.sofusrose.com/so-rose/openlut (GitLab) + **PyPi Package**: https://pypi.python.org/pypi/openlut What is it? diff --git a/doc/images/rock-transformed.jpg b/doc/images/rock-transformed.jpg new file mode 100644 index 0000000..e5755e3 --- /dev/null +++ b/doc/images/rock-transformed.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:20d82b6797ea51318ec741adea19233136fb80eecae99d302d28a1354e552b18 +size 192650 diff --git a/doc/images/rock.jpg b/doc/images/rock.jpg new file mode 100644 index 0000000..868e535 --- /dev/null +++ b/doc/images/rock.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:35184cd6a88ce59c4662c6e5716805e5d79210624de6d9e577b8d2f0289368b7 +size 130943 diff --git a/doc/source/_themes/sphinx_rtd_theme b/doc/source/_themes/sphinx_rtd_theme deleted file mode 120000 index 3f934cd..0000000 --- a/doc/source/_themes/sphinx_rtd_theme +++ /dev/null @@ -1 +0,0 @@ -sphinx_rtd_theme_git/sphinx_rtd_theme/ \ No newline at end of file diff --git a/doc/source/_themes/sphinx_rtd_theme_git b/doc/source/_themes/sphinx_rtd_theme_git deleted file mode 160000 index eef98b3..0000000 --- a/doc/source/_themes/sphinx_rtd_theme_git +++ /dev/null @@ -1 +0,0 @@ -Subproject commit eef98b316b947a9d8854add13cba702f41f00c14 diff --git a/doc/source/builtins.rst b/doc/source/builtins.rst index 770e4ad..a4ba199 100644 --- a/doc/source/builtins.rst +++ b/doc/source/builtins.rst @@ -1,17 +1,18 @@ Builtin Resources ================= -openlut.gamma module --------------------- +gamma: Gamma functions. +------------------------ .. automodule:: openlut.gamma :members: :undoc-members: :show-inheritance: + :exclude-members: PGamma -openlut.gamut module --------------------- +gamut: Color Matrices. +----------------------- .. automodule:: openlut.gamut :members: @@ -19,14 +20,15 @@ openlut.gamut module :show-inheritance: -openlut.lib.olOpt module ------------------------- +olOpt: Low-Level Optimized Functions +------------------------------------------ olOpt is the reason openlut is snappy! It contains the lower-level, fast functions that drive the rest of openlut. -.. automodule:: openlut.lib.olOpt +.. automodule:: openlut.olOpt :members: :undoc-members: :show-inheritance: + :noindex: diff --git a/doc/source/conf.py b/doc/source/conf.py index 511971e..5b02908 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -63,9 +63,9 @@ author = u'Sofus Rose' # built documents. # # The short X.Y version. -version = u'0.2.3' +version = u'0.2.6' # The full version, including alpha/beta/rc tags. -release = u'0.2.3' +release = u'0.2.6' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -139,7 +139,7 @@ html_theme_options = { import sphinx_rtd_theme sphinx_rtd_theme.get_html_theme_path() -html_theme_path = ["_themes",sphinx_rtd_theme.get_html_theme_path()] +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # The name for this set of Sphinx documents. # " v documentation" by default. diff --git a/doc/source/imageio.rst b/doc/source/imageio.rst index 5e2990a..fb07e8a 100644 --- a/doc/source/imageio.rst +++ b/doc/source/imageio.rst @@ -1,10 +1,79 @@ -Image Input/Output +Image IO ================= +This section deals with getting images in and out of openlut. -All image IO happens via the ColMap module. +Introduction +---------------------------- -openlut.ColMap module ---------------------- +Image IO in openlut happens via the ColMap module, which handles loading, transforming, +and saving images. As the name might suggest, a ColMap is a simple container storing RGB +data. + +Internally, it uses a 32-bit numpy float array with an unenforced clipping range of [0, 1], of the +shape **(height, width, 3)**. + +First, import the relevant code: + +.. doctest:: + + >>> import openlut as ol + >>> from openlut import ColMap, Func, gamma + +You can open an image on the disk with the :py:func:`~openlut.ColMap.open` method and +an image path: + +.. doctest:: + + >>> img = ColMap.open('../img_test/rock.exr') + >>> ColMap.display('../img_test/rock.exr') #Display the image directly from a path. + +The referenced image 'rock.exr' looks like this: + +.. image:: ../images/rock.jpg + +*The linear exr data has been transformed for correct web browser viewing. See the NOTE at the bottom.* + +Saving that image is as easy as a call to :py:func:`~openlut.ColMap.save`, which infers +the output format directly from the extension: + +.. doctest:: + + >>> img.save('../img_test/saved_rock.dpx') + +But now to the meat of it: Image transforms are trivial to apply to ColMaps because +of the :py:func:`~openlut.ColMap.apply` method! See :py:class:`~openlut.ColMap.Transform` for more. + +.. doctest:: + + >>> transform = Func(gamma.sRGB) #We'll be applying an sRGB function today. + >>> img.apply(transform).show() + +The transformed image looks like this: + +.. image:: ../images/rock-transformed.jpg + +*The linear exr data has been transformed for correct web browser viewing. See the NOTE at the bottom.* + +There's a few elements at play here: + +* We can plop **any subclass** of :py:class:`~openlut.Transform` into the :py:func:`~openlut.ColMap.apply` method. +* :py:class:`~openlut.Func` is one such class. In this case, we initialize it with openlut's builtin :py:const:`~openlut.gamma.sRGB` function. +* The :py:const:`~openlut.gamma.sRGB` function comes from the :py:mod:`~openlut.gamma` module, where you can find a wide variety of such functions. +* The :py:func:`~openlut.ColMap.show` method displays the image interactively, in an OpenGL viewer. + +After applying a transform, you can . :py:func:`~openlut.ColMap.save` it perhaps, apply more transforms, etc. . But are the basics! +Take a look at the ColMap class documentation for more! + + +**IMPORTANT NOTE**: When loading/saving images, **openlut won't touch the raw image data**. This can be problematic, +because most formats like jpg and png store their data already transformed by an sRGB gamma curve, making +your image as shown in openlut **look too bright**. + +* You can undo this easily: Just apply an inverse sRGB LUT or Func. +* EXR is one of the only formats that won't touch your data, keeping it linear. + +ColMap: Image IO +------------------------ .. automodule:: openlut.ColMap :members: diff --git a/doc/source/index.rst b/doc/source/index.rst index 33ea6a4..7a426d5 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -6,6 +6,7 @@ Welcome to openlut's documentation! =================================== +You'll find tutorials, explanations, and everything you'll need to get going with openlut! Table of Contents: @@ -31,6 +32,6 @@ Full Docs No nice explanations here - just all the docs in a list. .. toctree:: - :maxdepth: 3 + :maxdepth: 2 modules diff --git a/doc/source/intro.rst b/doc/source/intro.rst index 92b64be..c061a93 100644 --- a/doc/source/intro.rst +++ b/doc/source/intro.rst @@ -1,4 +1,4 @@ -Introduction to openlut +Overview ====================== Hello! TBD diff --git a/doc/source/openlut.lib.rst b/doc/source/openlut.lib.rst deleted file mode 100644 index 04678ce..0000000 --- a/doc/source/openlut.lib.rst +++ /dev/null @@ -1,22 +0,0 @@ -openlut.lib package -=================== - -Submodules ----------- - -openlut.lib.files module ------------------------- - -.. automodule:: openlut.lib.files - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: openlut.lib - :members: - :undoc-members: - :show-inheritance: diff --git a/doc/source/openlut.rst b/doc/source/openlut.rst index a106afb..3425f27 100644 --- a/doc/source/openlut.rst +++ b/doc/source/openlut.rst @@ -1,15 +1,8 @@ -openlut package +openlut =============== -Subpackages ------------ - -.. toctree:: - - openlut.lib - -Module contents ---------------- +Package contents +--------------------- .. automodule:: openlut :members: @@ -17,9 +10,9 @@ Module contents :show-inheritance: C++ Extension: olOpt --------------- +------------------------ -.. automodule:: openlut.lib.olOpt +.. automodule:: openlut.olOpt :members: :undoc-members: :show-inheritance: diff --git a/doc/source/transforms.rst b/doc/source/transforms.rst index 447ea0c..fe54885 100644 --- a/doc/source/transforms.rst +++ b/doc/source/transforms.rst @@ -1,10 +1,10 @@ Transforms ================= -Doing image transforms in openlut uses the :py:func:`~ColMap.apply` method to apply Transform objects. A Transform +Doing image transforms in openlut uses the :py:func:`~openlut.ColMap.apply` method to apply Transform objects. A Transform object is any subclass of the Transform listed below. Examples include LUT, Func, and ColMat. -openlut.Transform module +Transform: The Base ------------------------ .. automodule:: openlut.Transform @@ -13,24 +13,24 @@ openlut.Transform module :show-inheritance: -openlut.LUT module ------------------- +LUT: 1D Lookup Tables +------------------------ .. automodule:: openlut.LUT :members: :undoc-members: :show-inheritance: -openlut.Func module -------------------- +Func: Gamma Functions +----------------------------- .. automodule:: openlut.Func :members: :undoc-members: :show-inheritance: -openlut.ColMat module ---------------------- +ColMat: Color Matrices +--------------------------- .. automodule:: openlut.ColMat :members: diff --git a/mkDocs.sh b/mkDocs.sh index 43bc2d8..b7e180a 100755 --- a/mkDocs.sh +++ b/mkDocs.sh @@ -1 +1,4 @@ -make -C doc html +SCRIPT_PATH="$(dirname $(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$(basename "${BASH_SOURCE[0]}"))/doc" + +make -C "$SCRIPT_PATH" doctest +make -C "$SCRIPT_PATH" html diff --git a/mkRst.sh b/mkRst.sh new file mode 100755 index 0000000..401be51 --- /dev/null +++ b/mkRst.sh @@ -0,0 +1 @@ +pandoc --from=markdown --to=rst --output=README.rst README.md diff --git a/openlut/ColMap.py b/openlut/ColMap.py index 032d58d..62d26d3 100644 --- a/openlut/ColMap.py +++ b/openlut/ColMap.py @@ -25,22 +25,21 @@ class ColMap : ''' The ColMap class stores an image in its 32 bit float internal working space. - :var DEPTHS: A dictionary of depths in relation to the Depths dictionary. - - ColMaps are initialized by default with 0's; a black image. You can use - `open` to load a path, :py:func:`~fromArray` to load from a numpy array, or :py:func:`~fromBinary` to load from - a binary representation (useful in pipes). - :param shape: The numpy-style shape of the empty image. Specify width, then height. :type shape: tuple[int, int] or tuple[int, int, int] :param depth: The integer depth used for int format's input and output. Set to DEPTHS['full'] by default. :type depth: int or None + ColMaps are initialized by default with 0's; a black image. You can use + `open` to load a path, :py:func:`~openlut.ColMap.fromArray` to load from a numpy array, or :py:func:`~openlut.ColMap.fromBinary` to load from + a binary representation (useful in pipes). + :return: An empty ColMap, holding a black image of specified shape. :raises ValueError: When trying to use unsupported bit depth. :raises ValueError: When using invalid image shape. ''' + #: A static dictionary of supported bit depths. 'default' is never actually used. DEPTHS = { 'default' : None, 'comp' : 8, 'half' : 16, @@ -64,7 +63,7 @@ class ColMap : ''' Initialize a ColMap from a numpy array of either float or int type (containing an image). - See :py:class:`~ColMap` initialization for a lower-level constructor. + See :py:class:`~openlut.ColMap` initialization for a lower-level constructor. :param imgArr: The numpy image array. Must have shape (width, height, 3) :param depth: The integer depth used for int format's input and output. None will use highest available. @@ -111,7 +110,7 @@ class ColMap : @staticmethod def fromBinary(binData, fmt, width=None, height=None) : ''' - Construct a ColMap from an image in binary form. See :py:func:`~ColMap.toBinary` for the inverse. + Construct a ColMap from an image in binary form. See :py:func:`~openlut.ColMap.toBinary` for the inverse. * This won't work for greyscale data - it's assumed to be RGB. @@ -120,7 +119,7 @@ class ColMap : :param str width: You may specify a specific width if you're having problems. :param str height: You may specify a specific height if you're having problems. :return: The image, as a ColMat. - :rtype: :py:class:`~ColMap` + :rtype: :py:class:`~openlut.ColMap` This is great for pipes, where you're receiving binary data through stdin. * Set binData to `sys.stdin.buffer.read()` in a script to pipe data into it! @@ -139,7 +138,7 @@ class ColMap : :param str path: The image path to open. :return: The image, as a ColMat. - :rtype: :py:class:`~ColMap` + :rtype: :py:class:`~openlut.ColMap` ColMap currently uses ImageMagick to open a wide range of formats, including: @@ -163,14 +162,14 @@ class ColMap : #Operations - returns new ColMaps. def apply(self, transform) : ''' - Apply an image transformation, in the form of a subclass of :py:class:`~Transform`. + Apply an image transformation, in the form of a subclass of :py:class:`~openlut.Transform`. - You can apply LUTs, gamma functions, matrices - simply insert an instance of :py:class:`~LUT`, - :py:class:`~Func`, :py:class:`~ColMat`, or any other :py:class:`~Transform` object to apply it + You can apply LUTs, gamma functions, matrices - simply insert an instance of :py:class:`~openlut.LUT`, + :py:class:`~openlut.Func`, :py:class:`~openlut.ColMat`, or any other :py:class:`~openlut.Transform` object to apply it to the image! :param transform: An image transform. - :type transform: :py:class:`~Transform` + :type transform: :py:class:`~openlut.Transform` :return: A transformed ColMap. ''' return ColMap.fromArray(transform.sample(self.asarray())) @@ -179,11 +178,11 @@ class ColMap : @staticmethod def openWand(path) : ''' - Vendor-specific :py:func:`~ColMap.open` function. See :py:func:`~ColMap.open` + Vendor-specific :py:func:`~openlut.ColMap.open` function. See :py:func:`~openlut.ColMap.open` :param str path: The image path to open. :return: The image, as a ColMat. - :rtype: :py:class:`~ColMap` + :rtype: :py:class:`~openlut.ColMap` ''' with wand.image.Image(filename=path) as img: @@ -238,7 +237,7 @@ class ColMap : def saveWand(self, path, compress = None, depth = None) : ''' - Vendor-specific :py:func:`~ColMap.save` function. See :py:func:`~ColMap.save` + Vendor-specific :py:func:`~openlut.ColMap.save` function. See :py:func:`~openlut.ColMap.save` :param str path: The image path to save to. :param compress: Compression options passed to Wand. Currently broken. @@ -274,7 +273,7 @@ class ColMap : :param width: The desired width of the viewer; the height is automatically gleaned from the aspect ratio. - For the viewer source code, see :py:class:`~Viewer`. + For the viewer source code, see :py:class:`~openlut.Viewer`. ''' img = ColMap.open(path).rgbArr @@ -291,7 +290,7 @@ class ColMap : :param width: The desired width of the viewer; the height is automatically gleaned from the aspect ratio. - For the viewer source code, see :py:class:`~Viewer`. + For the viewer source code, see :py:class:`~openlut.Viewer`. ''' #Use my custom OpenGL viewer! @@ -328,13 +327,13 @@ class ColMap : def toBinary(self, fmt, depth=None) : ''' - Output this ColMap in binary form. See :py:func:`~ColMap.fromBinary` for the inverse. + Output this ColMap in binary form. See :py:func:`~openlut.ColMap.fromBinary` for the inverse. :param str fmt: Wand needs to know what format to output! See https://www.imagemagick.org/script/formats.php . :param depth: You may override the ColMap's bit depth if you wish. :type depth: int or None :return: The image, as a ColMat. - :rtype: :py:class:`~ColMap` + :rtype: :py:class:`~openlut.ColMap` This is great for pipes, where you're sending binary data through stdout. * Use the return value as the argument of sys.stdout.write() to pipe the image to other applications! @@ -384,3 +383,6 @@ class ColMap : #Overloads def __repr__(self) : return 'ColMap.fromArray( \n\trgbArr = {0}\n)'.format('\n\t\t'.join([line.strip() for line in repr(self.rgbArr).split('\n')])) + + def __str__(self) : + return "" diff --git a/openlut/__init__.py b/openlut/__init__.py index 9ef09d4..64865f6 100644 --- a/openlut/__init__.py +++ b/openlut/__init__.py @@ -9,6 +9,15 @@ from .Viewer import Viewer #Ensure the package namespace lines up. from . import gamma from . import gamut +from .lib import olOpt -__all__ = ['ColMap', 'Transform', 'LUT', 'Func', 'ColMat', 'Viewer', 'gamma', 'gamut'] - +__all__ = [ 'ColMap', + 'Transform', + 'LUT', + 'Func', + 'ColMat', + 'Viewer', + 'gamma', + 'gamut', + 'olOpt' +] diff --git a/openlut/gamma.py b/openlut/gamma.py index 1c3c1dd..6693dee 100644 --- a/openlut/gamma.py +++ b/openlut/gamma.py @@ -7,13 +7,30 @@ from .lib import olOpt as olo #Static Gamma Functions, borrowed from olo. #inv goes from space to lin. +#: The lin --> lin gamma function. An alias for olOpt's fast :py:func:`~openlut.olOpt.lin`. lin = olo.lin + +#: The lin --> sRGB gamma function. An alias for olOpt's fast :py:func:`~openlut.olOpt.sRGB`. sRGB = olo.sRGB + +#: The sRGB --> lin gamma function. An alias for olOpt's fast :py:func:`~openlut.olOpt.sRGBinv`. sRGBinv = olo.sRGBinv + +#: The lin --> Rec709 gamma function. An alias for olOpt's fast :py:func:`~openlut.olOpt.Rec709`. Rec709 = olo.Rec709 + +#: The lin --> ReinhardHDR gamma function. An alias for olOpt's fast :py:func:`~openlut.olOpt.ReinhardHDR`. ReinhardHDR = olo.ReinhardHDR + +#: The lin --> sLog gamma function. An alias for olOpt's fast :py:func:`~openlut.olOpt.sLog`. See +#: https://pro.sony.com/bbsccms/assets/files/mkt/cinema/solutions/slog_manual.pdf . sLog = olo.sLog + +#: The lin --> sLog2 gamma function. An alias for olOpt's fast :py:func:`~openlut.olOpt.sLog2`. See +#: http://community.sony.com/sony/attachments/sony/large-sensor-camera-F5-F55/12359/2/TechnicalSummary_for_S-Gamut3Cine_S-Gamut3_S-Log3_V1_00.pdf . sLog2 = olo.sLog2 + +#: The lin --> DanLog gamma function. An alias for olOpt's fast fast :py:func:`~openlut.olOpt.DanLog`. DanLog = olo.DanLog class PGamma : @@ -25,7 +42,7 @@ class PGamma : def sRGB(x) : ''' - sRGB formula. Domain must be within [0, 1]. + The lin --> lin gamma function. ''' return ( (1.055) * (x ** (1.0 / 2.4)) ) - 0.055 if x > 0.0031308 else x * 12.92 def sRGBinv(x) : diff --git a/openlut/lib/olOpt.cpp b/openlut/lib/olOpt.cpp index b452ae1..e7af928 100644 --- a/openlut/lib/olOpt.cpp +++ b/openlut/lib/olOpt.cpp @@ -214,7 +214,7 @@ PYBIND11_PLUGIN(olOpt) { mod.def( "lin", &lin, - "The linear gamma function.", + "The lin --> lin gamma function.", py::arg("x") );