Skip to content

Commit f9a8b45

Browse files
imagebuf docs examples: c++ examples, outfile, run script, and doc
1 parent 5731449 commit f9a8b45

File tree

4 files changed

+251
-92
lines changed

4 files changed

+251
-92
lines changed

src/doc/imagebuf.rst

Lines changed: 31 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -369,57 +369,28 @@ For the remainder of this section, we will assume that you have a
369369
Example: Visiting all pixels to compute an average color
370370
--------------------------------------------------------
371371

372-
.. code-block:: cpp
372+
.. tabs::
373+
374+
.. tab:: C++
375+
.. literalinclude:: ../../testsuite/docs-examples-cpp/src/docs-examples-imagebuf.cpp
376+
:language: c++
377+
:start-after: BEGIN-imagebuf-get-pixel-average
378+
:end-before: END-imagebuf-get-pixel-average
379+
:dedent: 4
373380

374-
void print_channel_averages (const std::string &filename)
375-
{
376-
// Set up the ImageBuf and read the file
377-
ImageBuf buf (filename);
378-
bool ok = buf.read (0, 0, true, TypeDesc::FLOAT); // Force a float buffer
379-
if (! ok)
380-
return;
381-
382-
// Initialize a vector to contain the running total
383-
int nc = buf.nchannels();
384-
std::vector<float> total (n, 0.0f);
385-
386-
// Iterate over all pixels of the image, summing channels separately
387-
for (ImageBuf::ConstIterator<float> it (buf); ! it.done(); ++it)
388-
for (int c = 0; c < nc; ++c)
389-
total[c] += it[c];
390-
391-
// Print the averages
392-
imagesize_t npixels = buf.spec().image_pixels();
393-
for (int c = 0; c < nc; ++c)
394-
std::cout << "Channel " << c << " avg = " (total[c] / npixels) << "\n";
395-
}
396-
397-
398-
.. _sec-make-black:
399381

400382
Example: Set all pixels in a region to black
401383
--------------------------------------------
402384

403-
.. code-block:: cpp
404385

405-
bool make_black (ImageBuf &buf, ROI region)
406-
{
407-
if (buf.spec().format != TypeDesc::FLOAT)
408-
return false; // Assume it's a float buffer
409-
410-
// Clamp the region's channel range to the channels in the image
411-
roi.chend = std::min (roi.chend, buf.nchannels);
412-
413-
// Iterate over all pixels in the region...
414-
for (ImageBuf::Iterator<float> it (buf, region); ! it.done(); ++it) {
415-
if (! it.exists()) // Make sure the iterator is pointing
416-
continue; // to a pixel in the data window
417-
for (int c = roi.chbegin; c < roi.chend; ++c)
418-
it[c] = 0.0f; // clear the value
419-
}
420-
return true;
421-
}
386+
.. tabs::
422387

388+
.. tab:: C++
389+
.. literalinclude:: ../../testsuite/docs-examples-cpp/src/docs-examples-imagebuf.cpp
390+
:language: c++
391+
:start-after: BEGIN-imagebuf-set-region-black
392+
:end-before: END-imagebuf-set-region-black
393+
:dedent: 4
423394

424395
Dealing with buffer data types
425396
==============================
@@ -474,37 +445,14 @@ Strategy 2: Template your iterating functions based on buffer type
474445
Consider the following alternate version of the `make_black` function
475446
from Section `Example: Set all pixels in a region to black`_ ::
476447

477-
template<typename BUFT>
478-
static bool make_black_impl (ImageBuf &buf, ROI region)
479-
{
480-
// Clamp the region's channel range to the channels in the image
481-
roi.chend = std::min (roi.chend, buf.nchannels);
482-
483-
// Iterate over all pixels in the region...
484-
for (ImageBuf::Iterator<BUFT> it (buf, region); ! it.done(); ++it) {
485-
if (! it.exists()) // Make sure the iterator is pointing
486-
continue; // to a pixel in the data window
487-
for (int c = roi.chbegin; c < roi.chend; ++c)
488-
it[c] = 0.0f; // clear the value
489-
}
490-
return true;
491-
}
492-
493-
bool make_black (ImageBuf &buf, ROI region)
494-
{
495-
if (buf.spec().format == TypeDesc::FLOAT)
496-
return make_black_impl<float> (buf, region);
497-
else if (buf.spec().format == TypeDesc::HALF)
498-
return make_black_impl<half> (buf, region);
499-
else if (buf.spec().format == TypeDesc::UINT8)
500-
return make_black_impl<unsigned char> (buf, region);
501-
else if (buf.spec().format == TypeDesc::UINT16)
502-
return make_black_impl<unsigned short> (buf, region);
503-
else {
504-
buf.error ("Unsupported pixel data format %s", buf.spec().format);
505-
return false;
506-
}
507-
}
448+
.. tabs::
449+
450+
.. tab:: C++
451+
.. literalinclude:: ../../testsuite/docs-examples-cpp/src/docs-examples-imagebuf.cpp
452+
:language: c++
453+
:start-after: BEGIN-imagebuf-iterator-template
454+
:end-before: END-imagebuf-iterator-template
455+
:dedent: 4
508456

509457
In this example, we make an implementation that is templated on the buffer
510458
type, and then a wrapper that calls the appropriate template specialization
@@ -515,22 +463,14 @@ In fact, :file:`imagebufalgo_util.h` provides a macro to do this (and
515463
several variants, which will be discussed in more detail in the next
516464
chapter). You could rewrite the example even more simply::
517465

518-
#include <OpenImageIO/imagebufalgo_util.h>
519-
520-
template<typename BUFT>
521-
static bool make_black_impl (ImageBuf &buf, ROI region)
522-
{
523-
... same as before ...
524-
}
525-
526-
bool make_black (ImageBuf &buf, ROI region)
527-
{
528-
bool ok;
529-
OIIO_DISPATCH_COMMON_TYPES (ok, "make_black", make_black_impl,
530-
buf.spec().format, buf, region);
531-
return ok;
532-
}
466+
.. tabs::
467+
468+
.. tab:: C++
469+
.. literalinclude:: ../../testsuite/docs-examples-cpp/src/docs-examples-imagebuf.cpp
470+
:language: c++
471+
:start-after: BEGIN-imagebuf-disptach
472+
:end-before: END-imagebuf-dispatch
473+
:dedent: 4
533474

534475
This other type-dispatching helper macros will be discussed in more
535476
detail in Chapter :ref:`chap-imagebufalgo`.
536-

testsuite/docs-examples-cpp/ref/out.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
findaverages.exr : 640 x 480, 3 channel, float openexr
2+
SHA-1: E8D3C267CBC4BBDE41343DCA008773A3E55B8159
3+
set-region-black.exr : 640 x 480, 3 channel, float openexr
4+
SHA-1: 7006ED82385E7BCD1FB338B9D3DBFF754541E980
5+
set-region-black-template-dispatch.exr : 640 x 480, 3 channel, half openexr
6+
SHA-1: FEB8B385D8784C4A16F3164D9B1A0F9113D64C86
7+
set-region-black-template-float.exr : 640 x 480, 3 channel, float openexr
8+
SHA-1: 7006ED82385E7BCD1FB338B9D3DBFF754541E980
9+
set-region-black-template-uint8.exr : 640 x 480, 3 channel, half openexr
10+
SHA-1: 9E09138C84FC4FDA52A6D76AED751B6551BB3417
111
error: Uninitialized input image
212
error: Uninitialized input image
313
zero1.exr : 512 x 512, 3 channel, float openexr

testsuite/docs-examples-cpp/run.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626
# hashes merely check that the images don't change, but saves us the space
2727
# of checking in a full copy of the image if it's not needed.
2828
hashes = [
29+
# Outputs from the ImageBuf chapter:
30+
"findaverages.exr",
31+
"set-region-black.exr",
32+
"set-region-black-template-dispatch.exr",
33+
"set-region-black-template-float.exr",
34+
"set-region-black-template-uint8.exr",
2935
# Outputs from the ImageBufAlgo chapter:
3036
"zero1.exr",
3137
"zero2.exr",

testsuite/docs-examples-cpp/src/docs-examples-imagebuf.cpp

Lines changed: 204 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,215 @@ void example1()
3030
//
3131
///////////////////////////////////////////////////////////////////////////
3232

33+
#include <OpenImageIO/imagebuf.h>
3334

35+
// BEGIN-imagebuf-get-pixel-avg
36+
void print_channel_averages(const std::string& filename)
37+
{
38+
// Set up the ImageBuf and read the file
39+
ImageBuf buf(filename);
40+
bool ok = buf.read(0, 0, true, TypeDesc::FLOAT); // Force a float buffer
41+
if (!ok)
42+
return;
43+
44+
// Initialize a vector to contain the running total
45+
int nc = buf.nchannels();
46+
std::vector<float> total(nc, 0.0f);
47+
48+
// Iterate over all pixels of the image, summing channels separately
49+
for (ImageBuf::ConstIterator<float> it(buf); !it.done(); ++it)
50+
for (int c = 0; c < nc; ++c)
51+
total[c] += it[c];
52+
53+
// Print the averages
54+
imagesize_t npixels = buf.spec().image_pixels();
55+
for (int c = 0; c < nc; ++c)
56+
std::cout << "Channel " << c << " avg = " << (total[c] / npixels)
57+
<< "\n";
58+
}
59+
60+
// END-imagebuf-get-pixel-avg
61+
62+
void print_channel_averages_example()
63+
{
64+
const std::string filename = "findaverages.exr";
65+
int x_sz = 640;
66+
int y_sz = 480;
67+
ImageBuf A(ImageSpec(x_sz, y_sz, 3, TypeDesc::FLOAT));
68+
for (int i = 0; i < x_sz; ++i)
69+
for (int j = 0; j < y_sz; ++j) {
70+
// Create a square RGB gradient so determining an average is interesting
71+
A.setpixel(i, j, 0,
72+
cspan<float>(
73+
{ powf(float(i) / (x_sz - 1), 2.0f),
74+
powf(float(j) / (y_sz - 1), 2.0f),
75+
powf(float(i * j) / (x_sz * y_sz - 1), 2.0f) }));
76+
}
77+
if (!A.write(filename)) {
78+
std::cout << "error: " << A.geterror() << "\n";
79+
} else {
80+
print_channel_averages(filename);
81+
}
82+
}
83+
84+
// BEGIN-imagebuf-set-region-black
85+
bool make_black(ImageBuf& buf, ROI region)
86+
{
87+
if (buf.spec().format != TypeDesc::FLOAT)
88+
return false; // Assume it's a float buffer
89+
90+
// Clamp the region's channel range to the channels in the image
91+
region.chend = std::min(region.chend, buf.nchannels());
92+
// Iterate over all pixels in the region...
93+
for (ImageBuf::Iterator<float> it(buf, region); !it.done(); ++it) {
94+
if (!it.exists()) // Make sure the iterator is pointing
95+
continue; // to a pixel in the data window
96+
for (int c = region.chbegin; c < region.chend; ++c)
97+
it[c] = 0.0f; // clear the value
98+
}
99+
return true;
100+
}
101+
// END-imagebuf-set-region-black
102+
103+
void make_black_example()
104+
{
105+
int x_sz = 640;
106+
int y_sz = 480;
107+
ImageBuf A(ImageSpec(x_sz, y_sz, 3, TypeDesc::FLOAT));
108+
for (int i = 0; i < x_sz; ++i)
109+
for (int j = 0; j < y_sz; ++j) {
110+
// Create RGB gradient so region changing is easy to see
111+
A.setpixel(i, j, 0,
112+
cspan<float>({ float(i) / (x_sz - 1),
113+
float(j) / (y_sz - 1),
114+
float(i * j) / (x_sz * y_sz - 1) }));
115+
}
116+
// A rectangular region straddling the middle of the image above
117+
ROI region(x_sz / 4, x_sz * 3 / 4, y_sz / 4, y_sz * 3 / 4, 0, 1, 0, 3);
118+
if (make_black(A, region)) {
119+
A.write("set-region-black.exr");
120+
} else {
121+
std::cout << "error: buffer is not a float buffer\n";
122+
}
123+
}
124+
125+
126+
127+
// BEGIN-imagebuf-iterator-template
128+
#include <OpenImageIO/half.h>
129+
template<typename BUFT>
130+
static bool make_black_impl(ImageBuf& buf, ROI region)
131+
{
132+
// Clamp the region's channel range to the channels in the image
133+
region.chend = std::min(region.chend, buf.nchannels());
134+
135+
// Iterate over all pixels in the region...
136+
for (ImageBuf::Iterator<BUFT> it(buf, region); !it.done(); ++it) {
137+
if (!it.exists()) // Make sure the iterator is pointing
138+
continue; // to a pixel in the data window
139+
for (int c = region.chbegin; c < region.chend; ++c)
140+
it[c] = 0.0f; // clear the value
141+
}
142+
return true;
143+
}
144+
145+
bool make_black_templated(ImageBuf& buf, ROI region)
146+
{
147+
if (buf.spec().format == TypeDesc::FLOAT)
148+
return make_black_impl<float>(buf, region);
149+
else if (buf.spec().format == TypeDesc::HALF)
150+
return make_black_impl<half>(buf, region);
151+
else if (buf.spec().format == TypeDesc::UINT8)
152+
return make_black_impl<unsigned char>(buf, region);
153+
else if (buf.spec().format == TypeDesc::UINT16)
154+
return make_black_impl<unsigned short>(buf, region);
155+
else {
156+
buf.errorf("Unsupported pixel data format %s",
157+
buf.spec().format.c_str());
158+
return false;
159+
}
160+
}
161+
// END-imagebuf-iterator-template
162+
163+
void make_black_template_example()
164+
{
165+
int x_sz = 640;
166+
int y_sz = 480;
167+
ImageBuf A(ImageSpec(x_sz, y_sz, 3, TypeDesc::FLOAT));
168+
for (int i = 0; i < x_sz; ++i)
169+
for (int j = 0; j < y_sz; ++j) {
170+
// Create RGB gradient so region changing is easy to see
171+
A.setpixel(i, j, 0,
172+
cspan<float>({ float(i) / (x_sz - 1),
173+
float(j) / (y_sz - 1),
174+
float(i * j) / (x_sz * y_sz - 1) }));
175+
}
176+
// A rectangular region straddling the middle of the image above
177+
ROI region(x_sz / 4, x_sz * 3 / 4, y_sz / 4, y_sz * 3 / 4, 0, 1, 0, 3);
178+
if (make_black_templated(A, region)) {
179+
A.write("set-region-black-template-float.exr");
180+
} else {
181+
std::cout << "error: " << A.geterror() << "\n";
182+
}
183+
184+
ImageBuf B(ImageSpec(x_sz, y_sz, 3, TypeDesc::UINT8));
185+
for (int i = 0; i < x_sz; ++i)
186+
for (int j = 0; j < y_sz; ++j) {
187+
// Create RGB gradient so region changing is easy to see
188+
B.setpixel(i, j, 0,
189+
cspan<float>({ float(i) / (x_sz - 1),
190+
float(j) / (y_sz - 1),
191+
float(i * j) / (x_sz * y_sz - 1) }));
192+
}
193+
// A rectangular region straddling the middle of the image above
194+
if (make_black_templated(B, region)) {
195+
B.write("set-region-black-template-uint8.exr");
196+
} else {
197+
std::cout << "error: " << B.geterror() << "\n";
198+
}
199+
}
200+
201+
// BEGIN-imagebuf-dispatch
202+
#include <OpenImageIO/imagebufalgo_util.h>
203+
bool make_black_dispatch(ImageBuf& buf, ROI region)
204+
{
205+
bool ok;
206+
OIIO_DISPATCH_COMMON_TYPES(ok, "make_black_dispatch", make_black_impl,
207+
buf.spec().format, buf, region);
208+
return ok;
209+
}
210+
// END-imagebuf-dispatch
211+
212+
void make_black_dispatch_example()
213+
{
214+
int x_sz = 640;
215+
int y_sz = 480;
216+
ImageBuf A(ImageSpec(x_sz, y_sz, 3, TypeDesc::UINT16));
217+
for (int i = 0; i < x_sz; ++i)
218+
for (int j = 0; j < y_sz; ++j) {
219+
// Create RGB gradient so region changing is easy to see
220+
A.setpixel(i, j, 0,
221+
cspan<float>({ float(i) / (x_sz - 1),
222+
float(j) / (y_sz - 1),
223+
float(i * j) / (x_sz * y_sz - 1) }));
224+
}
225+
// A rectangular region straddling the middle of the image above
226+
ROI region(x_sz / 4, x_sz * 3 / 4, y_sz / 4, y_sz * 3 / 4, 0, 1, 0, 3);
227+
if (make_black_templated(A, region)) {
228+
A.write("set-region-black-template-dispatch.exr");
229+
} else {
230+
std::cout << "error: " << A.geterror() << "\n";
231+
}
232+
}
34233

35234
int main(int /*argc*/, char** /*argv*/)
36235
{
37236
// Each example function needs to get called here, or it won't execute
38237
// as part of the test.
39-
example1();
238+
// example1();
239+
print_channel_averages_example();
240+
make_black_example();
241+
make_black_template_example();
242+
make_black_dispatch_example();
40243
return 0;
41244
}

0 commit comments

Comments
 (0)