Skip to content

Commit dd77238

Browse files
committed
Improvements related to image dithering and low-bit-depth output (AcademySoftwareFoundation#3141)
We have options that allow adding random dither to images before output, which when converting float images to 8 bit or less, can greatly reduce the appearance of banding artifacts. This PR makes a number of improvements: * When the option is used, it should apply dither any time you are reducing an image with > 8 bits/channel to an output with <= 8 bits/channel. Not just from float/half, but also from uint16, for example. (When outputting > 8 bits per channel, there are enough gradations that you tend not to see banding artifacts, so dithering is not necessary for 16 bit output, even if coming from a float data source.) * Change the actual dither we use to blue noise. The old dither just used a hash to add uniformly distributed random numbers to each pixel value before quantization, completely uncorrelated from pixel to pixel. Blue noise is specially constructed to still have a uniform distribution of the output range, but it ensures that spatially, similar values are distributed as far away from each other as possible, rather than having similar values sometimes clumped together. The result is a MUCH NICER appearance. * Of course, this means the we needed to store a blue noise table in the library, and some access routines for it. We incorporate a public domain blue noise texture as a table. * ImageBufAlgo::noise() and `oiiotool --noise` now take "blue" as a noise name to return blue noise. Also, make "white" the (preferred) synonym for "uniform" (to disambiguate the fact that both white and blue noise are uniformly distributed; the difference is that white is independently random for each pixel, whereas blue shapes the spectrum to favor high frequencies, making it better suited for dithering and sampling purposes. * ImageBufAlgo::bluenoise_image() returns a reference to a stored periodic blue noise image. * oiiotool -d would let you say "uint10" or "uint12" to indicate 10 or 12 bit output (for formats that support it), but had no way to ask for less than 8 bit output (for example, TIFF supports that). So we add "uint6", "uint4", "uint2", "uint1" as recognized names for the `-d` option in those rare cases when you specifically want to produce a low bit depth file. And furthermore, if you ask for `--dither` when using lower bit depths, the dither amplitude is adjusted to be right sized for the bit depth you are using. * Many format output modules that support 8 bit output honor the option to dither the output, but in the "built-in plugins" chapter of the docs, most did not list this option in the section that describes which special output options it knows. So now we've added this to the docs for all the output plugins that did support it.
1 parent a181a42 commit dd77238

26 files changed

+66059
-69
lines changed

src/doc/builtinplugins.rst

Lines changed: 168 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,11 @@ control aspects of the writing itself:
230230
- ptr
231231
- Pointer to a ``Filesystem::IOProxy`` that will handle the I/O, for
232232
example by writing to memory rather than the file system.
233+
* - ``oiio:dither``
234+
- int
235+
- If nonzero and outputting UINT8 values in the file from a source of
236+
higher bit depth, will add a small amount of random dither to combat
237+
the appearance of banding.
233238

234239
**Custom I/O Overrides**
235240

@@ -689,6 +694,7 @@ ICO
689694
ICO is an image file format used for small images (usually icons) on
690695
Windows. ICO files use the file extension :file:`.ico`.
691696

697+
**Attributes**
692698

693699
.. list-table::
694700
:widths: 30 10 65
@@ -704,6 +710,24 @@ Windows. ICO files use the file extension :file:`.ico`.
704710
- int
705711
- if nonzero, will cause the ICO to be written out using PNG format.
706712

713+
**Configuration settings for ICO output**
714+
715+
When opening an ICO ImageOutput, the following special metadata tokens
716+
control aspects of the writing itself:
717+
718+
.. list-table::
719+
:widths: 30 10 65
720+
:header-rows: 1
721+
722+
* - Output Configuration Attribute
723+
- Type
724+
- Meaning
725+
* - ``oiio:dither``
726+
- int
727+
- If nonzero and outputting UINT8 values in the file from a source of
728+
higher bit depth, will add a small amount of random dither to combat
729+
the appearance of banding.
730+
707731
**Limitations**
708732

709733
* ICO only supports UINT8 and UINT16 formats; all output images will
@@ -742,6 +766,24 @@ IFF files are used by Autodesk Maya and use the file extension :file:`.iff`.
742766
- int
743767
- the true bits per sample of the IFF file.
744768

769+
**Configuration settings for IFF output**
770+
771+
When opening an IFF ImageOutput, the following special metadata tokens
772+
control aspects of the writing itself:
773+
774+
.. list-table::
775+
:widths: 30 10 65
776+
:header-rows: 1
777+
778+
* - Output Configuration Attribute
779+
- Type
780+
- Meaning
781+
* - ``oiio:dither``
782+
- int
783+
- If nonzero and outputting UINT8 values in the file from a source of
784+
higher bit depth, will add a small amount of random dither to combat
785+
the appearance of banding.
786+
745787

746788

747789
|
@@ -769,7 +811,7 @@ also blessed by the Joint Photographic Experts Group that attempt to
769811
address some of these issues, such as JPEG-2000, but these do not have
770812
anywhere near the acceptance of the original JPEG/JFIF format.
771813

772-
814+
**Attributes**
773815

774816
.. list-table::
775817
:widths: 30 10 65
@@ -820,8 +862,9 @@ control aspects of the writing itself:
820862
- Meaning
821863
* - ``oiio:dither``
822864
- int
823-
- If nonzero and outputting UINT8 values in the file, will add a small
824-
amount of random dither to combat the appearance of banding.
865+
- If nonzero and outputting UINT8 values in the file from a source of
866+
higher bit depth, will add a small amount of random dither to combat
867+
the appearance of banding.
825868
* - ``oiio:ioproxy``
826869
- ptr
827870
- Pointer to a ``Filesystem::IOProxy`` that will handle the I/O, for
@@ -868,6 +911,7 @@ JPEG-2000 is not yet widely used, so OpenImageIO's support of it is
868911
preliminary. In particular, we are not yet very good at handling the
869912
metadata robustly.
870913

914+
**Attributes**
871915

872916
.. list-table::
873917
:widths: 30 10 65
@@ -881,6 +925,23 @@ metadata robustly.
881925
- specifies the JPEG-2000 stream format (``"none"`` or ``"jpc"``)
882926

883927

928+
**Configuration settings for JPEG-2000 output**
929+
930+
When opening a JPEG-2000 ImageOutput, the following special metadata tokens
931+
control aspects of the writing itself:
932+
933+
.. list-table::
934+
:widths: 30 10 65
935+
:header-rows: 1
936+
937+
* - Output Configuration Attribute
938+
- Type
939+
- Meaning
940+
* - ``oiio:dither``
941+
- int
942+
- If nonzero and outputting UINT8 values in the file from a source of
943+
higher bit depth, will add a small amount of random dither to combat
944+
the appearance of banding.
884945

885946

886947
|
@@ -1312,8 +1373,9 @@ control aspects of the writing itself:
13121373
example by writing to a memory buffer.
13131374
* - ``oiio:dither``
13141375
- int
1315-
- If nonzero and outputting UINT8 values in the file, will add a small
1316-
amount of random dither to combat the appearance of banding
1376+
- If nonzero and outputting UINT8 values in the file from a source of
1377+
higher bit depth, will add a small amount of random dither to combat
1378+
the appearance of banding.
13171379

13181380
**Custom I/O Overrides**
13191381

@@ -1364,6 +1426,8 @@ other than 1 or 3 channels, no tiles, no multi-image, no MIPmapping.
13641426
It's not a smart choice unless you are sending your images back to the
13651427
1980's via a time machine.
13661428

1429+
**Attributes**
1430+
13671431
.. list-table::
13681432
:widths: 30 10 65
13691433
:header-rows: 1
@@ -1381,6 +1445,23 @@ It's not a smart choice unless you are sending your images back to the
13811445
ASCII. The PNM writer honors this attribute in the ImageSpec to
13821446
determine whether to write an ASCII or binary file.
13831447

1448+
**Configuration settings for PNM output**
1449+
1450+
When opening a PNM ImageOutput, the following special metadata tokens
1451+
control aspects of the writing itself:
1452+
1453+
.. list-table::
1454+
:widths: 30 10 65
1455+
:header-rows: 1
1456+
1457+
* - Output Configuration Attribute
1458+
- Type
1459+
- Meaning
1460+
* - ``oiio:dither``
1461+
- int
1462+
- If nonzero and outputting UINT8 values in the file from a source of
1463+
higher bit depth, will add a small amount of random dither to combat
1464+
the appearance of banding.
13841465

13851466

13861467
|
@@ -1574,6 +1655,8 @@ originating from Wavefront Advanced Visualizer and used primarily by
15741655
software developed at Wavefront. RLA files commonly use the file extension
15751656
:file:`.rla`.
15761657

1658+
**Attributes**
1659+
15771660
.. list-table::
15781661
:widths: 30 10 65
15791662
:header-rows: 1
@@ -1652,6 +1735,23 @@ software developed at Wavefront. RLA files commonly use the file extension
16521735
- float
16531736
- the gamma correction value (if specified).
16541737

1738+
**Configuration settings for RLA output**
1739+
1740+
When opening a RLA ImageOutput, the following special metadata tokens
1741+
control aspects of the writing itself:
1742+
1743+
.. list-table::
1744+
:widths: 30 10 65
1745+
:header-rows: 1
1746+
1747+
* - Output Configuration Attribute
1748+
- Type
1749+
- Meaning
1750+
* - ``oiio:dither``
1751+
- int
1752+
- If nonzero and outputting UINT8 values in the file from a source of
1753+
higher bit depth, will add a small amount of random dither to combat
1754+
the appearance of banding.
16551755

16561756
**Limitations**
16571757

@@ -1676,6 +1776,7 @@ The SGI format is sometimes used for legacy apps, but has little merit
16761776
otherwise: no support for tiles, no MIPmaps, no multi-subimage, only 8- and
16771777
16-bit integer pixels (no floating point), only 1-4 channels.
16781778

1779+
**Attributes**
16791780

16801781
.. list-table::
16811782
:widths: 30 10 65
@@ -1691,6 +1792,23 @@ otherwise: no support for tiles, no MIPmaps, no multi-subimage, only 8- and
16911792
- string
16921793
- Image name.
16931794

1795+
**Configuration settings for SGI output**
1796+
1797+
When opening an SGI ImageOutput, the following special metadata tokens
1798+
control aspects of the writing itself:
1799+
1800+
.. list-table::
1801+
:widths: 30 10 65
1802+
:header-rows: 1
1803+
1804+
* - Output Configuration Attribute
1805+
- Type
1806+
- Meaning
1807+
* - ``oiio:dither``
1808+
- int
1809+
- If nonzero and outputting UINT8 values in the file from a source of
1810+
higher bit depth, will add a small amount of random dither to combat
1811+
the appearance of banding.
16941812

16951813

16961814
|
@@ -1740,6 +1858,7 @@ files use the file extension :file:`.tga`, or, much more rarely,
17401858
:file:`.tpic`. The official Targa format specification may be found at:
17411859
http://www.dca.fee.unicamp.br/~martino/disciplinas/ea978/tgaffs.pdf
17421860

1861+
**Attributes**
17431862

17441863
.. list-table::
17451864
:widths: 30 10 65
@@ -1786,13 +1905,31 @@ http://www.dca.fee.unicamp.br/~martino/disciplinas/ea978/tgaffs.pdf
17861905
- float
17871906
- the gamma correction value (if specified).
17881907

1789-
17901908
If the TGA file contains a thumbnail, its dimensions will be stored in the
17911909
attributes ``"thumbnail_width"``, ``"thumbnail_height"``, and
17921910
``"thumbnail_nchannels"``, and the thumbnail pixels themselves will be
17931911
retrievable via `ImageInput::get_thumbnail()` or `ImageBuf::thumbnail()` or
17941912
`ImageCache::get_thumbnail()`.
17951913

1914+
**Configuration settings for Targa output**
1915+
1916+
When opening a Targa ImageOutput, the following special metadata tokens
1917+
control aspects of the writing itself:
1918+
1919+
.. list-table::
1920+
:widths: 30 10 65
1921+
:header-rows: 1
1922+
1923+
* - Output Configuration Attribute
1924+
- Type
1925+
- Meaning
1926+
* - ``oiio:dither``
1927+
- int
1928+
- If nonzero and outputting UINT8 values in the file from a source of
1929+
higher bit depth, will add a small amount of random dither to combat
1930+
the appearance of banding.
1931+
1932+
17961933
**Limitations**
17971934

17981935
* The Targa reader reserves enough memory for the entire image. Therefore it
@@ -1953,6 +2090,11 @@ aspects of the writing itself:
19532090
- int
19542091
- Requests a rescaling to a specific bits per sample (such as writing
19552092
12-bit TIFFs).
2093+
* - ``oiio:dither``
2094+
- int
2095+
- If nonzero and outputting UINT8 values in the file from a source of
2096+
higher bit depth, will add a small amount of random dither to combat
2097+
the appearance of banding.
19562098
* - ``tiff:write_exif``
19572099
- int
19582100
- If zero, will not write any Exif data to the TIFF file. (The default
@@ -2170,6 +2312,8 @@ Webp
21702312
WebP is an image file format developed by Google that is intended to be an
21712313
open standard for lossy-compressed images for use on the web.
21722314

2315+
**Attributes**
2316+
21732317
.. list-table::
21742318
:widths: 30 10 65
21752319
:header-rows: 1
@@ -2188,6 +2332,24 @@ open standard for lossy-compressed images for use on the web.
21882332
- int
21892333
- Deprecated synonym for ``oiio:LoopCount``.
21902334

2335+
**Configuration settings for WebP output**
2336+
2337+
When opening a WebP ImageOutput, the following special metadata tokens
2338+
control aspects of the writing itself:
2339+
2340+
.. list-table::
2341+
:widths: 30 10 65
2342+
:header-rows: 1
2343+
2344+
* - Output Configuration Attribute
2345+
- Type
2346+
- Meaning
2347+
* - ``oiio:dither``
2348+
- int
2349+
- If nonzero and outputting UINT8 values in the file from a source of
2350+
higher bit depth, will add a small amount of random dither to combat
2351+
the appearance of banding.
2352+
21912353
**Limitations**
21922354

21932355
* WebP only supports 3-channel (RGB) or 4-channel (RGBA) images and must

src/doc/figures/bluenoise.jpg

76.1 KB
Loading

src/doc/imagebufalgo.rst

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,8 @@ checker() -- make a checker pattern
252252
|
253253
254254

255-
noise() -- make a noise pattern
256-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
255+
Noise patterns
256+
^^^^^^^^^^^^^^
257257

258258
.. doxygenfunction:: noise(string_view noisetype, float A = 0.0f, float B = 0.1f, bool mono = false, int seed = 0, ROI roi = {}, int nthreads = 0)
259259
..
@@ -277,19 +277,21 @@ noise() -- make a noise pattern
277277
..
278278
279279
.. |noiseimg1| image:: figures/unifnoise1.jpg
280+
:height: 1.25 in
281+
.. |noiseimg2| image:: figures/bluenoise.jpg
282+
:height: 1.25 in
283+
.. |noiseimg3| image:: figures/tahoe-gauss.jpg
280284
:height: 1.5 in
281-
.. |noiseimg2| image:: figures/tahoe-gauss.jpg
282-
:height: 1.5 in
283-
.. |noiseimg3| image:: figures/tahoe-pepper.jpg
285+
.. |noiseimg4| image:: figures/tahoe-pepper.jpg
284286
:height: 1.5 in
285287

286288
..
287289
288-
+------------------------+------------------------+------------------------+
289-
| |noiseimg1| | |noiseimg2| | |noiseimg3| |
290-
+------------------------+------------------------+------------------------+
291-
| uniform noise | gaussian noise added | salt & pepper dropouts |
292-
+------------------------+------------------------+------------------------+
290+
+------------------------+------------------------+------------------------+------------------------+
291+
| |noiseimg1| | |noiseimg2| | |noiseimg3| | |noiseimg4| |
292+
+------------------------+------------------------+------------------------+------------------------+
293+
| white noise | blue noise | gaussian noise added | salt & pepper dropouts |
294+
+------------------------+------------------------+------------------------+------------------------+
293295

294296
Result-as-parameter version:
295297

@@ -298,6 +300,15 @@ noise() -- make a noise pattern
298300
|
299301
300302

303+
.. doxygenfunction:: bluenoise_image()
304+
..
305+
306+
Example::
307+
308+
const ImageBuf& A = ImageBufAlgo::bluenoise_image();
309+
310+
311+
301312
Drawing shapes: points, lines, boxes
302313
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
303314

src/doc/makefigures.bash

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ ${OIIOTOOL} --pattern fill:top=0.1,0.1,0.1:bottom=0,0,0.75 320x240 3 --tocolorsp
3030
${OIIOTOOL} --pattern fill:left=0.1,0.1,0.1:right=0,0.75,0 320x240 3 --tocolorspace sRGB -o gradienth.jpg
3131
${OIIOTOOL} --pattern fill:topleft=.1,.1,.1:topright=1,0,0:bottomleft=0,1,0:bottomright=0,0,1 320x240 3 --tocolorspace sRGB -o gradient4.jpg
3232
${OIIOTOOL} --pattern checker:width=16:height=16 256x256 3 --tocolorspace sRGB -o checker.jpg
33-
${OIIOTOOL} --pattern noise:type=uniform:min=0:max=1:mono=1 256x256 3 --tocolorspace sRGB -o unifnoise1.jpg
34-
${OIIOTOOL} --pattern noise:type=uniform:min=0:max=1 256x256 3 --tocolorspace sRGB -o unifnoise3.jpg
33+
${OIIOTOOL} --pattern noise:type=white:min=0:max=1:mono=1 256x256 3 --tocolorspace sRGB -o unifnoise1.jpg
34+
${OIIOTOOL} --pattern noise:type=white:min=0:max=1 256x256 3 --tocolorspace sRGB -o unifnoise3.jpg
35+
${OIIOTOOL} --pattern noise:type=blue:min=0:max=1:mono=1 256x256 3 --tocolorspace sRGB -o bluenoise.jpg
3536
${OIIOTOOL} --pattern noise:type=gaussian:mean=0.5:stddev=0.2 256x256 3 --tocolorspace sRGB -o gaussnoise.jpg
3637
${OIIOTOOL} tahoe-small.jpg --noise:type=gaussian:mean=0:stddev=0.1 -o tahoe-gauss.jpg
3738
${OIIOTOOL} tahoe-small.jpg --noise:type=salt:portion=0.01:value=0:mono=1 -o tahoe-pepper.jpg

0 commit comments

Comments
 (0)