Skip to content

Commit 77b63cd

Browse files
lgritzscott-wilson
authored andcommitted
feat(oiiotool): Allow decision making about fixnan (AcademySoftwareFoundation#4171)
Added a new bit of pseudo-metadata that can be retrieved by oiiotool's expression substitution: `{TOP.NONFINITE_COUNT}` will be replaced by the count of inf and nan values present in the top image. Also, the `-fixnan` command now has the side effect of setting a user variable called `NONFINITE_COUNT` to the number of nonfinite values that were detected or repaired. Between the two of these, it's now easy to solve the following problem that actually came up in production for us. Sometimes, nans creep into images, and it's easier to repair them than to fix the complicated process that produced them in the first place. For some process in the studio, we had a script that was doing this preemptively on every image it encountered: oiiotool image.exr -fixnan black -o image.exr It was very expensive to repair every image whether it needed it or not, when actually it's only needed once every many-thousands-of-images. Most of the expense was in outputting the repaired file overtop the original. Now we can do this oiiotool image.exr -if "{TOP.NONFINITE_COUNT}" -fixnan black -o image.exr -endif It still has to read the image and look for NaN values, but since there are almost never any actual NaN's, now for the usual case, it can skip writing the output -- which was the vast majority of time. Signed-off-by: Larry Gritz <[email protected]> Signed-off-by: Scott Wilson <[email protected]>
1 parent bc6ef29 commit 77b63cd

File tree

2 files changed

+19
-5
lines changed

2 files changed

+19
-5
lines changed

src/doc/oiiotool.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ contents of an expression may be any of:
145145
(channels are comma-separated)
146146
* `AVGCOLOR` : the average pixel value of the image (channels are
147147
comma-separated)
148+
* `NONFINITE_COUNT` : the number of pixel values in the image that are
149+
either NaN or Inf values. (Added in OIIO 2.5.10.)
148150
* `META` : a multi-line string containing the full metadata of the image,
149151
similar to what would be printed with `oiiotool -info -v`.
150152
* `METABRIEF` : a string containing the brief one-line description,

src/oiiotool/oiiotool.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <iostream>
1212
#include <iterator>
1313
#include <map>
14+
#include <numeric>
1415
#include <regex>
1516
#include <sstream>
1617
#include <string>
@@ -1942,6 +1943,13 @@ Oiiotool::express_parse_atom(const string_view expr, string_view& s,
19421943
for (size_t i = 0; i < pixstat.avg.size(); ++i)
19431944
out << (i ? "," : "") << pixstat.avg[i];
19441945
result = out.str();
1946+
} else if (metadata == "NONFINITE_COUNT") {
1947+
auto pixstat = ImageBufAlgo::computePixelStats((*img)(0, 0));
1948+
imagesize_t sum = std::accumulate(pixstat.nancount.begin(),
1949+
pixstat.nancount.end(), 0)
1950+
+ std::accumulate(pixstat.infcount.begin(),
1951+
pixstat.infcount.end(), 0);
1952+
result = Strutil::to_string(sum);
19451953
} else if (metadata == "META" || metadata == "METANATIVE") {
19461954
std::stringstream out;
19471955
print_info_options opt;
@@ -4878,19 +4886,23 @@ action_fixnan(Oiiotool& ot, cspan<const char*> argv)
48784886
ImageRecRef A = ot.pop();
48794887
ot.push(new ImageRec(*A, allsubimages ? -1 : 0, allsubimages ? -1 : 0, true,
48804888
false));
4881-
int subimages = allsubimages ? A->subimages() : 1;
4889+
imagesize_t total_nonfinite = 0;
4890+
int subimages = allsubimages ? A->subimages() : 1;
48824891
for (int s = 0; s < subimages; ++s) {
48834892
int miplevels = ot.curimg->miplevels(s);
48844893
for (int m = 0; m < miplevels; ++m) {
48854894
const ImageBuf& Aib((*A)(s, m));
48864895
ImageBuf& Rib((*ot.curimg)(s, m));
4887-
bool ok = ImageBufAlgo::fixNonFinite(Rib, Aib, mode);
4888-
if (!ok) {
4896+
int num_nonfinite = 0;
4897+
bool ok = ImageBufAlgo::fixNonFinite(Rib, Aib, mode,
4898+
&num_nonfinite);
4899+
if (!ok)
48894900
ot.error(command, Rib.geterror());
4890-
return;
4891-
}
4901+
total_nonfinite += num_nonfinite;
48924902
}
48934903
}
4904+
// Set user variable NONFINITE_COUNT to the number of pixels modified.
4905+
ot.uservars["NONFINITE_COUNT"] = int(total_nonfinite);
48944906
}
48954907

48964908

0 commit comments

Comments
 (0)