Skip to content

Commit a844c7a

Browse files
authored
Improvements related to image dithering and low-bit-depth output (#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 77ff294 commit a844c7a

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
|
@@ -1309,8 +1370,9 @@ control aspects of the writing itself:
13091370
example by writing to a memory buffer.
13101371
* - ``oiio:dither``
13111372
- int
1312-
- If nonzero and outputting UINT8 values in the file, will add a small
1313-
amount of random dither to combat the appearance of banding
1373+
- If nonzero and outputting UINT8 values in the file from a source of
1374+
higher bit depth, will add a small amount of random dither to combat
1375+
the appearance of banding.
13141376

13151377
**Custom I/O Overrides**
13161378

@@ -1361,6 +1423,8 @@ other than 1 or 3 channels, no tiles, no multi-image, no MIPmapping.
13611423
It's not a smart choice unless you are sending your images back to the
13621424
1980's via a time machine.
13631425

1426+
**Attributes**
1427+
13641428
.. list-table::
13651429
:widths: 30 10 65
13661430
:header-rows: 1
@@ -1378,6 +1442,23 @@ It's not a smart choice unless you are sending your images back to the
13781442
ASCII. The PNM writer honors this attribute in the ImageSpec to
13791443
determine whether to write an ASCII or binary file.
13801444

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

13821463

13831464
|
@@ -1571,6 +1652,8 @@ originating from Wavefront Advanced Visualizer and used primarily by
15711652
software developed at Wavefront. RLA files commonly use the file extension
15721653
:file:`.rla`.
15731654

1655+
**Attributes**
1656+
15741657
.. list-table::
15751658
:widths: 30 10 65
15761659
:header-rows: 1
@@ -1649,6 +1732,23 @@ software developed at Wavefront. RLA files commonly use the file extension
16491732
- float
16501733
- the gamma correction value (if specified).
16511734

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

16531753
**Limitations**
16541754

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

1776+
**Attributes**
16761777

16771778
.. list-table::
16781779
:widths: 30 10 65
@@ -1688,6 +1789,23 @@ otherwise: no support for tiles, no MIPmaps, no multi-subimage, only 8- and
16881789
- string
16891790
- Image name.
16901791

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

16921810

16931811
|
@@ -1737,6 +1855,7 @@ files use the file extension :file:`.tga`, or, much more rarely,
17371855
:file:`.tpic`. The official Targa format specification may be found at:
17381856
http://www.dca.fee.unicamp.br/~martino/disciplinas/ea978/tgaffs.pdf
17391857

1858+
**Attributes**
17401859

17411860
.. list-table::
17421861
:widths: 30 10 65
@@ -1783,13 +1902,31 @@ http://www.dca.fee.unicamp.br/~martino/disciplinas/ea978/tgaffs.pdf
17831902
- float
17841903
- the gamma correction value (if specified).
17851904

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

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

17951932
* The Targa reader reserves enough memory for the entire image. Therefore it
@@ -1950,6 +2087,11 @@ aspects of the writing itself:
19502087
- int
19512088
- Requests a rescaling to a specific bits per sample (such as writing
19522089
12-bit TIFFs).
2090+
* - ``oiio:dither``
2091+
- int
2092+
- If nonzero and outputting UINT8 values in the file from a source of
2093+
higher bit depth, will add a small amount of random dither to combat
2094+
the appearance of banding.
19532095
* - ``tiff:write_exif``
19542096
- int
19552097
- If zero, will not write any Exif data to the TIFF file. (The default
@@ -2167,6 +2309,8 @@ Webp
21672309
WebP is an image file format developed by Google that is intended to be an
21682310
open standard for lossy-compressed images for use on the web.
21692311

2312+
**Attributes**
2313+
21702314
.. list-table::
21712315
:widths: 30 10 65
21722316
:header-rows: 1
@@ -2185,6 +2329,24 @@ open standard for lossy-compressed images for use on the web.
21852329
- int
21862330
- Deprecated synonym for ``oiio:LoopCount``.
21872331

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

21902352
* 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)