Skip to content

Commit d523fba

Browse files
antond-wetalgritz
authored andcommitted
feat(IBA): IBA::scale() (#4541)
Implements IBA::scale, an algo which takes two images, one of which is required to be a single channel image, each channel of the other image gets multiplied by that single channel, per pixel. Note that this is subtly different from IBA::mul(), which is a channel-by-channel multiplication, and so doesn't have a provision for allowing you to scale all channels of one image by the single channel of a second image. I have added tests for the C++ code, python code, oiiotool, and the documentation examples Signed-off-by: Anton Dukhovnikov <[email protected]>
1 parent f4370a2 commit d523fba

File tree

18 files changed

+216
-0
lines changed

18 files changed

+216
-0
lines changed

src/doc/figures/scale.jpg

99.4 KB
Loading

src/doc/imagebufalgo.rst

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,6 +1329,38 @@ Image arithmetic
13291329

13301330
|
13311331
1332+
.. doxygenfunction:: scale(const ImageBuf &A, const ImageBuf &B, KWArgs options = {}, ROI roi = {}, int nthreads = 0)
1333+
..
1334+
1335+
Result-as-parameter version:
1336+
1337+
.. doxygenfunction:: scale(ImageBuf &dst, const ImageBuf &A, const ImageBuf &B, KWArgs options = {}, ROI roi = {}, int nthreads = 0)
1338+
1339+
Examples:
1340+
1341+
.. tabs::
1342+
1343+
.. tab:: C++
1344+
.. literalinclude:: ../../testsuite/docs-examples-cpp/src/docs-examples-imagebufalgo.cpp
1345+
:language: c++
1346+
:start-after: BEGIN-imagebufalgo-scale
1347+
:end-before: END-imagebufalgo-scale
1348+
:dedent: 4
1349+
1350+
.. tab:: Python
1351+
.. literalinclude:: ../../testsuite/docs-examples-python/src/docs-examples-imagebufalgo.py
1352+
:language: py
1353+
:start-after: BEGIN-imagebufalgo-scale
1354+
:end-before: END-imagebufalgo-scale
1355+
:dedent: 4
1356+
1357+
.. code-tab:: bash oiiotool
1358+
1359+
# Pixel-by-pixel multiplication of all channels of one image by the only channel of another image
1360+
oiiotool a.exr mono.exr --scale -o scale.exr
1361+
1362+
|
1363+
13321364
.. doxygenfunction:: mul(Image_or_Const A, Image_or_Const B, ROI roi = {}, int nthreads = 0)
13331365
..
13341366

src/doc/oiiotool.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2507,6 +2507,27 @@ current top image.
25072507
Include/exclude subimages (see :ref:`sec-oiiotool-subimage-modifier`).
25082508

25092509

2510+
.. option:: --scale
2511+
2512+
Replace the *two* top images with a new image that is the pixel-by-pixel
2513+
multiplicative product of those images. One of the images must have a single
2514+
channel, that channel's pixel value is used to scale all channels of the
2515+
other image by.
2516+
2517+
2518+
Example::
2519+
2520+
# Apply vertical gradient
2521+
oiiotool tahoe.jpg --pattern fill:top=0.5:bottom=1 512x384 1 --scale -o scale.jpg
2522+
..
2523+
2524+
.. image:: figures/tahoe-small.jpg
2525+
:width: 2.0 in
2526+
.. image:: figures/scale.jpg
2527+
:width: 2.0 in
2528+
|
2529+
2530+
25102531
.. option:: --mul
25112532
--mulc <value>
25122533
--mulc <value0,value1,value2...>

src/doc/pythonbindings.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2833,6 +2833,23 @@ Image arithmetic
28332833
28342834
28352835
2836+
.. py:method:: ImageBuf ImageBufAlgo.scale (A, B, roi=ROI.All, nthreads=0)
2837+
bool ImageBufAlgo.scale (dst, A, B, roi=ROI.All, nthreads=0)
2838+
2839+
Per-pixel multiply all channels of one image by the single channle of the
2840+
other image. One of the input images must have only one channel.
2841+
2842+
Example:
2843+
2844+
.. code-block:: python
2845+
2846+
# Scale one image by the other
2847+
buf = ImageBufAlgo.scale (ImageBuf("a.exr"), ImageBuf("mono.exr"))
2848+
2849+
# Scale one image by the other, in place
2850+
ImageBufAlgo.scale (buf, buf, ImageBuf("mono.exr"))
2851+
2852+
28362853
.. py:method:: ImageBuf ImageBufAlgo.mul (A, B, roi=ROI.All, nthreads=0)
28372854
bool ImageBufAlgo.mul (dst, A, B, roi=ROI.All, nthreads=0)
28382855

src/include/OpenImageIO/imagebufalgo.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,21 @@ ImageBuf OIIO_API abs (const ImageBuf &A, ROI roi={}, int nthreads=0);
953953
bool OIIO_API abs (ImageBuf &dst, const ImageBuf &A, ROI roi={}, int nthreads=0);
954954

955955

956+
/// Compute per-pixel product `A * B`, returning the result image. At least
957+
/// one of `A` and `B` must be a single channel image, whose value is used to
958+
/// scale all channels of the other image.
959+
///
960+
/// @param options
961+
/// Optional ParamValue's that may control the reconstruction.
962+
/// (Reserved for future expansion.)
963+
///
964+
ImageBuf OIIO_API scale (const ImageBuf &A, const ImageBuf &B,
965+
KWArgs options = {}, ROI roi={}, int nthreads=0);
966+
/// Write to an existing image `dst` (allocating if it is uninitialized).
967+
bool OIIO_API scale (ImageBuf &dst, const ImageBuf &A, const ImageBuf &B,
968+
KWArgs options = {}, ROI roi={}, int nthreads=0);
969+
970+
956971
/// Compute per-pixel product `A * B`, returning the result image.
957972
///
958973
/// Either both `A` and `B` are images, or one is an image and the other is

src/libOpenImageIO/imagebufalgo_muldiv.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,65 @@
2525
OIIO_NAMESPACE_BEGIN
2626

2727

28+
template<class Rtype, class Atype, class Btype>
29+
static bool
30+
scale_impl(ImageBuf& R, const ImageBuf& A, const ImageBuf& B, ROI roi,
31+
int nthreads)
32+
{
33+
ImageBufAlgo::parallel_image(roi, nthreads, [&](ROI roi) {
34+
ImageBuf::Iterator<Rtype> r(R, roi);
35+
ImageBuf::ConstIterator<Atype> a(A, roi);
36+
ImageBuf::ConstIterator<Btype> b(B, roi);
37+
for (; !r.done(); ++r, ++a, ++b)
38+
for (int c = roi.chbegin; c < roi.chend; ++c)
39+
r[c] = a[c] * b[0];
40+
});
41+
return true;
42+
}
43+
44+
45+
46+
bool
47+
ImageBufAlgo::scale(ImageBuf& dst, const ImageBuf& A, const ImageBuf& B,
48+
KWArgs options, ROI roi, int nthreads)
49+
{
50+
pvt::LoggedTimer logtime("IBA::scale");
51+
bool ok = false;
52+
if (B.nchannels() == 1) {
53+
if (IBAprep(roi, &dst, &A, &B))
54+
OIIO_DISPATCH_COMMON_TYPES3(ok, "scale", scale_impl,
55+
dst.spec().format, A.spec().format,
56+
B.spec().format, dst, A, B, roi,
57+
nthreads);
58+
} else if (A.nchannels() == 1) {
59+
if (IBAprep(roi, &dst, &A, &B))
60+
OIIO_DISPATCH_COMMON_TYPES3(ok, "scale", scale_impl,
61+
dst.spec().format, B.spec().format,
62+
A.spec().format, dst, B, A, roi,
63+
nthreads);
64+
} else {
65+
dst.errorfmt(
66+
"ImageBufAlgo::scale(): one of the arguments must be a single channel image.");
67+
}
68+
69+
return ok;
70+
}
71+
72+
73+
74+
ImageBuf
75+
ImageBufAlgo::scale(const ImageBuf& A, const ImageBuf& B, KWArgs options,
76+
ROI roi, int nthreads)
77+
{
78+
ImageBuf result;
79+
bool ok = scale(result, A, B, options, roi, nthreads);
80+
if (!ok && !result.has_error())
81+
result.errorfmt("ImageBufAlgo::scale() error");
82+
return result;
83+
}
84+
85+
86+
2887
template<class Rtype, class Atype, class Btype>
2988
static bool
3089
mul_impl(ImageBuf& R, const ImageBuf& A, const ImageBuf& B, ROI roi,

src/oiiotool/oiiotool.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3090,6 +3090,7 @@ BINARY_IMAGE_OP(add, ImageBufAlgo::add); // --add
30903090
BINARY_IMAGE_OP(sub, ImageBufAlgo::sub); // --sub
30913091
BINARY_IMAGE_OP(mul, ImageBufAlgo::mul); // --mul
30923092
BINARY_IMAGE_OP(div, ImageBufAlgo::div); // --div
3093+
BINARY_IMAGE_OP(scale, ImageBufAlgo::scale); // --scale
30933094
BINARY_IMAGE_OP(absdiff, ImageBufAlgo::absdiff); // --absdiff
30943095

30953096
BINARY_IMAGE_COLOR_OP(addc, ImageBufAlgo::add, 0); // --addc
@@ -6644,6 +6645,9 @@ Oiiotool::getargs(int argc, char* argv[])
66446645
ap.arg("--csub %s:VAL")
66456646
.hidden() // Deprecated synonym
66466647
.OTACTION(action_subc);
6648+
ap.arg("--scale")
6649+
.help("Scale all channels of one image by the single channel of another image")
6650+
.OTACTION(action_scale);
66476651
ap.arg("--mul")
66486652
.help("Multiply two images")
66496653
.OTACTION(action_mul);

src/python/py_imagebufalgo.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,22 @@ IBA_abs_ret(const ImageBuf& A, ROI roi = ROI::All(), int nthreads = 0)
652652

653653

654654

655+
bool
656+
IBA_scale_images(ImageBuf& dst, const ImageBuf& A, const ImageBuf& B,
657+
ROI roi = ROI::All(), int nthreads = 0)
658+
{
659+
py::gil_scoped_release gil;
660+
return ImageBufAlgo::scale(dst, A, B, {}, roi, nthreads);
661+
}
662+
663+
ImageBuf
664+
IBA_scale_images_ret(const ImageBuf& A, const ImageBuf& B, ROI roi = ROI::All(),
665+
int nthreads = 0)
666+
{
667+
py::gil_scoped_release gil;
668+
return ImageBufAlgo::scale(A, B, {}, roi, nthreads);
669+
}
670+
655671
bool
656672
IBA_mul_color(ImageBuf& dst, const ImageBuf& A, py::object values_tuple,
657673
ROI roi = ROI::All(), int nthreads = 0)
@@ -2625,6 +2641,11 @@ declare_imagebufalgo(py::module& m)
26252641
.def_static("abs", &IBA_abs_ret, "A"_a, "roi"_a = ROI::All(),
26262642
"nthreads"_a = 0)
26272643

2644+
.def_static("scale", &IBA_scale_images, "dst"_a, "A"_a, "B"_a,
2645+
"roi"_a = ROI::All(), "nthreads"_a = 0)
2646+
.def_static("scale", &IBA_scale_images_ret, "A"_a, "B"_a,
2647+
"roi"_a = ROI::All(), "nthreads"_a = 0)
2648+
26282649
.def_static("mul", &IBA_mul_images, "dst"_a, "A"_a, "B"_a,
26292650
"roi"_a = ROI::All(), "nthreads"_a = 0)
26302651
.def_static("mul", &IBA_mul_color, "dst"_a, "A"_a, "B"_a,

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ example_add
3333
example_sub
3434
example_absdiff
3535
example_abs
36+
example_scale
3637
example_mul
3738
example_div
3839
example_fixNonFinite

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ example_add
3333
example_sub
3434
example_absdiff
3535
example_abs
36+
example_scale
3637
example_mul
3738
example_div
3839
example_fixNonFinite

0 commit comments

Comments
 (0)