bool ImageBufAlgo::compare (const ImageBuf &A, const ImageBuf &B, float failthresh, float warnthresh, ImageBufAlgo::CompareResults &result, ROI roi, int nthreads) { // If no ROI is defined, use the union of the data windows of the two // images. if (! roi.defined()) roi = roi_union (get_roi(A.spec()), get_roi(B.spec())); roi.chend = std::min (roi.chend, std::max(A.nchannels(), B.nchannels())); // Deep and non-deep images cannot be compared if (B.deep() != A.deep()) return false; bool ok; OIIO_DISPATCH_TYPES2 (ok, "compare", compare_, A.spec().format, B.spec().format, A, B, failthresh, warnthresh, result, roi, nthreads); // FIXME - The nthreads argument is for symmetry with the rest of // ImageBufAlgo and for future expansion. But for right now, we // don't actually split by threads. Maybe later. return ok; }
bool ImageBufAlgo::sub(ImageBuf& dst, Image_or_Const A_, Image_or_Const B_, ROI roi, int nthreads) { pvt::LoggedTimer logtime("IBA::sub"); if (A_.is_img() && B_.is_img()) { const ImageBuf &A(A_.img()), &B(B_.img()); if (!IBAprep(roi, &dst, &A, &B)) return false; ROI origroi = roi; roi.chend = std::min(roi.chend, std::min(A.nchannels(), B.nchannels())); bool ok; OIIO_DISPATCH_COMMON_TYPES3(ok, "sub", sub_impl, dst.spec().format, A.spec().format, B.spec().format, dst, A, B, roi, nthreads); if (roi.chend < origroi.chend && A.nchannels() != B.nchannels()) { // Edge case: A and B differed in nchannels, we allocated dst to be // the bigger of them, but adjusted roi to be the lesser. Now handle // the channels that got left out because they were not common to // all the inputs. ASSERT(roi.chend <= dst.nchannels()); roi.chbegin = roi.chend; roi.chend = origroi.chend; if (A.nchannels() > B.nchannels()) { // A exists copy(dst, A, dst.spec().format, roi, nthreads); } else { // B exists copy(dst, B, dst.spec().format, roi, nthreads); } } return ok; } if (A_.is_val() && B_.is_img()) // canonicalize to A_img, B_val A_.swap(B_); if (A_.is_img() && B_.is_val()) { const ImageBuf& A(A_.img()); cspan<float> b = B_.val(); if (!IBAprep(roi, &dst, &A, IBAprep_CLAMP_MUTUAL_NCHANNELS | IBAprep_SUPPORT_DEEP)) return false; IBA_FIX_PERCHAN_LEN_DEF(b, A.nchannels()); // Negate b (into a copy) int nc = A.nchannels(); float* vals = ALLOCA(float, nc); for (int c = 0; c < nc; ++c) vals[c] = -b[c]; b = cspan<float>(vals, nc); if (dst.deep()) { // While still serial, set up all the sample counts dst.deepdata()->set_all_samples(A.deepdata()->all_samples()); return add_impl_deep(dst, A, b, roi, nthreads); } bool ok; OIIO_DISPATCH_COMMON_TYPES2(ok, "sub", add_impl, dst.spec().format, A.spec().format, dst, A, b, roi, nthreads); return ok; } // Remaining cases: error dst.error("ImageBufAlgo::sub(): at least one argument must be an image"); return false; }
static bool compare_ (const ImageBuf &A, const ImageBuf &B, float failthresh, float warnthresh, ImageBufAlgo::CompareResults &result, ROI roi, int nthreads) { imagesize_t npels = roi.npixels(); imagesize_t nvals = npels * roi.nchannels(); int Achannels = A.nchannels(), Bchannels = B.nchannels(); // Compare the two images. // double totalerror = 0; double totalsqrerror = 0; result.maxerror = 0; result.maxx=0, result.maxy=0, result.maxz=0, result.maxc=0; result.nfail = 0, result.nwarn = 0; float maxval = 1.0; // max possible value ImageBuf::ConstIterator<Atype> a (A, roi, ImageBuf::WrapBlack); ImageBuf::ConstIterator<Btype> b (B, roi, ImageBuf::WrapBlack); bool deep = A.deep(); // Break up into batches to reduce cancelation errors as the error // sums become too much larger than the error for individual pixels. const int batchsize = 4096; // As good a guess as any for ( ; ! a.done(); ) { double batcherror = 0; double batch_sqrerror = 0; if (deep) { for (int i = 0; i < batchsize && !a.done(); ++i, ++a, ++b) { bool warned = false, failed = false; // For this pixel for (int c = roi.chbegin; c < roi.chend; ++c) for (int s = 0, e = a.deep_samples(); s < e; ++s) { compare_value (a, c, a.deep_value(c,s), b.deep_value(c,s), result, maxval, batcherror, batch_sqrerror, failed, warned, failthresh, warnthresh); } } } else { // non-deep for (int i = 0; i < batchsize && !a.done(); ++i, ++a, ++b) { bool warned = false, failed = false; // For this pixel for (int c = roi.chbegin; c < roi.chend; ++c) compare_value (a, c, c < Achannels ? a[c] : 0.0f, c < Bchannels ? b[c] : 0.0f, result, maxval, batcherror, batch_sqrerror, failed, warned, failthresh, warnthresh); } } totalerror += batcherror; totalsqrerror += batch_sqrerror; } result.meanerror = totalerror / nvals; result.rms_error = sqrt (totalsqrerror / nvals); result.PSNR = 20.0 * log10 (maxval / result.rms_error); return result.nfail == 0; }
bool ImageBufAlgo::div(ImageBuf& dst, Image_or_Const A_, Image_or_Const B_, ROI roi, int nthreads) { pvt::LoggedTimer logtime("IBA::div"); if (A_.is_img() && B_.is_img()) { const ImageBuf &A(A_.img()), &B(B_.img()); if (!IBAprep(roi, &dst, &A, &B, IBAprep_CLAMP_MUTUAL_NCHANNELS)) return false; bool ok; OIIO_DISPATCH_COMMON_TYPES3(ok, "div", div_impl, dst.spec().format, A.spec().format, B.spec().format, dst, A, B, roi, nthreads); return ok; } if (A_.is_val() && B_.is_img()) // canonicalize to A_img, B_val A_.swap(B_); if (A_.is_img() && B_.is_val()) { const ImageBuf& A(A_.img()); cspan<float> b = B_.val(); if (!IBAprep(roi, &dst, &A, IBAprep_CLAMP_MUTUAL_NCHANNELS | IBAprep_SUPPORT_DEEP)) return false; IBA_FIX_PERCHAN_LEN_DEF(b, dst.nchannels()); int nc = dst.nchannels(); float* binv = OIIO_ALLOCA(float, nc); for (int c = 0; c < nc; ++c) binv[c] = (b[c] == 0.0f) ? 0.0f : 1.0f / b[c]; b = cspan<float>(binv, nc); // re-wrap if (dst.deep()) { // While still serial, set up all the sample counts dst.deepdata()->set_all_samples(A.deepdata()->all_samples()); return mul_impl_deep(dst, A, b, roi, nthreads); } bool ok; OIIO_DISPATCH_COMMON_TYPES2(ok, "div", mul_impl, dst.spec().format, A.spec().format, dst, A, b, roi, nthreads); return ok; } // Remaining cases: error dst.error("ImageBufAlgo::div(): at least one argument must be an image"); return false; }
bool ImageBufAlgo::flatten (ImageBuf &dst, const ImageBuf &src, ROI roi, int nthreads) { if (! src.deep()) { // For some reason, we were asked to flatten an already-flat image. // So just copy it. return dst.copy (src); } // Construct an ideal spec for dst, which is like src but not deep. ImageSpec force_spec = src.spec(); force_spec.deep = false; force_spec.channelformats.clear(); if (! IBAprep (roi, &dst, &src, NULL, &force_spec, IBAprep_SUPPORT_DEEP)) return false; if (dst.spec().deep) { dst.error ("Cannot flatten to a deep image"); return false; } const ImageSpec &srcspec (src.spec()); int alpha_channel, RA_channel, GA_channel, BA_channel; int R_channel, G_channel, B_channel, Z_channel, Zback_channel; if (! find_deep_channels (srcspec, alpha_channel, RA_channel, GA_channel, BA_channel, R_channel, G_channel, B_channel, Z_channel, Zback_channel)) { dst.error ("No alpha channel could be identified"); return false; } bool ok; OIIO_DISPATCH_TYPES (ok, "flatten", flatten_, dst.spec().format, dst, src, roi, nthreads); return ok; }
static bool add_impl_deep(ImageBuf& R, const ImageBuf& A, cspan<float> b, ROI roi, int nthreads) { ASSERT(R.deep()); ImageBufAlgo::parallel_image(roi, nthreads, [&](ROI roi) { cspan<TypeDesc> channeltypes(R.deepdata()->all_channeltypes()); ImageBuf::Iterator<float> r(R, roi); ImageBuf::ConstIterator<float> a(A, roi); for (; !r.done(); ++r, ++a) { for (int samp = 0, samples = r.deep_samples(); samp < samples; ++samp) { for (int c = roi.chbegin; c < roi.chend; ++c) { if (channeltypes[c].basetype == TypeDesc::UINT32) r.set_deep_value(c, samp, a.deep_value_uint(c, samp)); else r.set_deep_value(c, samp, a.deep_value(c, samp) + b[c]); } } } }); return true; }
static void print_stats (Oiiotool &ot, const std::string &filename, const ImageSpec &originalspec, int subimage=0, int miplevel=0, bool indentmip=false) { const char *indent = indentmip ? " " : " "; ImageBuf input; if (! read_input (filename, input, subimage, miplevel)) { ot.error ("stats", input.geterror()); return; } PixelStats stats; if (! computePixelStats (stats, input)) { std::string err = input.geterror(); ot.error ("stats", Strutil::format ("unable to compute: %s", err.empty() ? "unspecified error" : err.c_str())); return; } // The original spec is used, otherwise the bit depth will // be reported incorrectly (as FLOAT) unsigned int maxval = (unsigned int)get_intsample_maxval (originalspec); printf ("%sStats Min: ", indent); for (unsigned int i=0; i<stats.min.size(); ++i) { print_stats_num (stats.min[i], maxval, true); printf (" "); } print_stats_footer (maxval); printf ("\n"); printf ("%sStats Max: ", indent); for (unsigned int i=0; i<stats.max.size(); ++i) { print_stats_num (stats.max[i], maxval, true); printf (" "); } print_stats_footer (maxval); printf ("\n"); printf ("%sStats Avg: ", indent); for (unsigned int i=0; i<stats.avg.size(); ++i) { print_stats_num (stats.avg[i], maxval, false); printf (" "); } print_stats_footer (maxval); printf ("\n"); printf ("%sStats StdDev: ", indent); for (unsigned int i=0; i<stats.stddev.size(); ++i) { print_stats_num (stats.stddev[i], maxval, false); printf (" "); } print_stats_footer (maxval); printf ("\n"); printf ("%sStats NanCount: ", indent); for (unsigned int i=0; i<stats.nancount.size(); ++i) { printf ("%llu ", (unsigned long long)stats.nancount[i]); } printf ("\n"); printf ("%sStats InfCount: ", indent); for (unsigned int i=0; i<stats.infcount.size(); ++i) { printf ("%llu ", (unsigned long long)stats.infcount[i]); } printf ("\n"); printf ("%sStats FiniteCount: ", indent); for (unsigned int i=0; i<stats.finitecount.size(); ++i) { printf ("%llu ", (unsigned long long)stats.finitecount[i]); } printf ("\n"); if (input.deep()) { const DeepData *dd (input.deepdata()); size_t npixels = dd->pixels(); size_t totalsamples = 0, emptypixels = 0; size_t maxsamples = 0, minsamples = std::numeric_limits<size_t>::max(); size_t maxsamples_npixels = 0; float mindepth = std::numeric_limits<float>::max(); float maxdepth = -std::numeric_limits<float>::max(); Imath::V3i maxsamples_pixel(-1,-1,-1), minsamples_pixel(-1,-1,-1); Imath::V3i mindepth_pixel(-1,-1,-1), maxdepth_pixel(-1,-1,-1); Imath::V3i nonfinite_pixel(-1,-1,-1); int nonfinite_pixel_samp(-1), nonfinite_pixel_chan(-1); size_t sampoffset = 0; int nchannels = dd->channels(); int depthchannel = -1; long long nonfinites = 0; for (int c = 0; c < nchannels; ++c) if (Strutil::iequals (originalspec.channelnames[c], "Z")) depthchannel = c; int xend = originalspec.x + originalspec.width; int yend = originalspec.y + originalspec.height; int zend = originalspec.z + originalspec.depth; size_t p = 0; std::vector<size_t> nsamples_histogram; for (int z = originalspec.z; z < zend; ++z) { for (int y = originalspec.y; y < yend; ++y) { for (int x = originalspec.x; x < xend; ++x, ++p) { size_t samples = input.deep_samples (x, y, z); totalsamples += samples; if (samples == maxsamples) ++maxsamples_npixels; if (samples > maxsamples) { maxsamples = samples; maxsamples_pixel.setValue (x, y, z); maxsamples_npixels = 1; } if (samples < minsamples) minsamples = samples; if (samples == 0) ++emptypixels; if (samples >= nsamples_histogram.size()) nsamples_histogram.resize (samples+1, 0); nsamples_histogram[samples] += 1; for (unsigned int s = 0; s < samples; ++s) { for (int c = 0; c < nchannels; ++c) { float d = input.deep_value (x, y, z, c, s); if (! isfinite(d)) { if (nonfinites++ == 0) { nonfinite_pixel.setValue (x, y, z); nonfinite_pixel_samp = s; nonfinite_pixel_chan = c; } } if (depthchannel == c) { if (d < mindepth) { mindepth = d; mindepth_pixel.setValue (x, y, z); } if (d > maxdepth) { maxdepth = d; maxdepth_pixel.setValue (x, y, z); } } } } sampoffset += samples; } } } printf ("%sMin deep samples in any pixel : %llu\n", indent, (unsigned long long)minsamples); printf ("%sMax deep samples in any pixel : %llu\n", indent, (unsigned long long)maxsamples); printf ("%s%llu pixel%s had the max of %llu samples, including (x=%d, y=%d)\n", indent, (unsigned long long)maxsamples_npixels, maxsamples_npixels > 1 ? "s" : "", (unsigned long long)maxsamples, maxsamples_pixel.x, maxsamples_pixel.y); printf ("%sAverage deep samples per pixel: %.2f\n", indent, double(totalsamples)/double(npixels)); printf ("%sTotal deep samples in all pixels: %llu\n", indent, (unsigned long long)totalsamples); printf ("%sPixels with deep samples : %llu\n", indent, (unsigned long long)(npixels-emptypixels)); printf ("%sPixels with no deep samples: %llu\n", indent, (unsigned long long)emptypixels); printf ("%sSamples/pixel histogram:\n", indent); size_t grandtotal = 0; for (size_t i = 0, e = nsamples_histogram.size(); i < e; ++i) grandtotal += nsamples_histogram[i]; size_t binstart = 0, bintotal = 0; for (size_t i = 0, e = nsamples_histogram.size(); i < e; ++i) { bintotal += nsamples_histogram[i]; if (i < 8 || i == (e-1) || OIIO::ispow2(i+1)) { // batch by powers of 2, unless it's a small number if (i == binstart) printf ("%s %3lld ", indent, (long long)i); else printf ("%s %3lld-%3lld", indent, (long long)binstart, (long long)i); printf (" : %8lld (%4.1f%%)\n", (long long)bintotal, (100.0*bintotal)/grandtotal); binstart = i+1; bintotal = 0; } } if (depthchannel >= 0) { printf ("%sMinimum depth was %g at (%d, %d)\n", indent, mindepth, mindepth_pixel.x, mindepth_pixel.y); printf ("%sMaximum depth was %g at (%d, %d)\n", indent, maxdepth, maxdepth_pixel.x, maxdepth_pixel.y); } if (nonfinites > 0) { printf ("%sNonfinite values: %lld, including (x=%d, y=%d, chan=%s, samp=%d)\n", indent, nonfinites, nonfinite_pixel.x, nonfinite_pixel.y, input.spec().channelnames[nonfinite_pixel_chan].c_str(), nonfinite_pixel_samp); } } else { std::vector<float> constantValues(input.spec().nchannels); if (isConstantColor(input, &constantValues[0])) { printf ("%sConstant: Yes\n", indent); printf ("%sConstant Color: ", indent); for (unsigned int i=0; i<constantValues.size(); ++i) { print_stats_num (constantValues[i], maxval, false); printf (" "); } print_stats_footer (maxval); printf ("\n"); } else { printf ("%sConstant: No\n", indent); } if( isMonochrome(input)) { printf ("%sMonochrome: Yes\n", indent); } else { printf ("%sMonochrome: No\n", indent); } } }
static void print_stats (const std::string &filename, const ImageSpec &originalspec, int subimage=0, int miplevel=0, bool indentmip=false) { const char *indent = indentmip ? " " : " "; ImageBuf input; if (! read_input (filename, input, subimage, miplevel)) { std::cerr << "Stats: read error: " << input.geterror() << "\n"; return; } PixelStats stats; if (! computePixelStats (stats, input)) { printf ("%sStats: (unable to compute)\n", indent); return; } // The original spec is used, otherwise the bit depth will // be reported incorrectly (as FLOAT) unsigned int maxval = (unsigned int)get_intsample_maxval (originalspec); printf ("%sStats Min: ", indent); for (unsigned int i=0; i<stats.min.size(); ++i) { print_stats_num (stats.min[i], maxval, true); printf (" "); } print_stats_footer (maxval); printf ("\n"); printf ("%sStats Max: ", indent); for (unsigned int i=0; i<stats.max.size(); ++i) { print_stats_num (stats.max[i], maxval, true); printf (" "); } print_stats_footer (maxval); printf ("\n"); printf ("%sStats Avg: ", indent); for (unsigned int i=0; i<stats.avg.size(); ++i) { print_stats_num (stats.avg[i], maxval, false); printf (" "); } print_stats_footer (maxval); printf ("\n"); printf ("%sStats StdDev: ", indent); for (unsigned int i=0; i<stats.stddev.size(); ++i) { print_stats_num (stats.stddev[i], maxval, false); printf (" "); } print_stats_footer (maxval); printf ("\n"); printf ("%sStats NanCount: ", indent); for (unsigned int i=0; i<stats.nancount.size(); ++i) { printf ("%llu ", (unsigned long long)stats.nancount[i]); } printf ("\n"); printf ("%sStats InfCount: ", indent); for (unsigned int i=0; i<stats.infcount.size(); ++i) { printf ("%llu ", (unsigned long long)stats.infcount[i]); } printf ("\n"); printf ("%sStats FiniteCount: ", indent); for (unsigned int i=0; i<stats.finitecount.size(); ++i) { printf ("%llu ", (unsigned long long)stats.finitecount[i]); } printf ("\n"); if (input.deep()) { const DeepData *dd (input.deepdata()); size_t npixels = dd->nsamples.size(); size_t totalsamples = 0, emptypixels = 0; size_t maxsamples = 0, minsamples = std::numeric_limits<size_t>::max(); for (size_t p = 0; p < npixels; ++p) { size_t c = size_t(dd->nsamples[p]); totalsamples += c; if (c > maxsamples) maxsamples = c; if (c < minsamples) minsamples = c; if (c == 0) ++emptypixels; } printf ("%sMin deep samples in any pixel : %llu\n", indent, (unsigned long long)minsamples); printf ("%sMax deep samples in any pixel : %llu\n", indent, (unsigned long long)maxsamples); printf ("%sAverage deep samples per pixel: %.2f\n", indent, double(totalsamples)/double(npixels)); printf ("%sTotal deep samples in all pixels: %llu\n", indent, (unsigned long long)totalsamples); printf ("%sPixels with deep samples : %llu\n", indent, (unsigned long long)(npixels-emptypixels)); printf ("%sPixels with no deep samples: %llu\n", indent, (unsigned long long)emptypixels); } else { std::vector<float> constantValues(input.spec().nchannels); if (isConstantColor(input, &constantValues[0])) { printf ("%sConstant: Yes\n", indent); printf ("%sConstant Color: ", indent); for (unsigned int i=0; i<constantValues.size(); ++i) { print_stats_num (constantValues[i], maxval, false); printf (" "); } print_stats_footer (maxval); printf ("\n"); } else { printf ("%sConstant: No\n", indent); } if( isMonochrome(input)) { printf ("%sMonochrome: Yes\n", indent); } else { printf ("%sMonochrome: No\n", indent); } } }
static bool computePixelStats_ (const ImageBuf &src, ImageBufAlgo::PixelStats &stats, ROI roi, int nthreads) { if (! roi.defined()) roi = get_roi (src.spec()); else roi.chend = std::min (roi.chend, src.nchannels()); int nchannels = src.spec().nchannels; // Use local storage for smaller batches, then merge the batches // into the final results. This preserves precision for large // images, where the running total may be too big to incorporate the // contributions of individual pixel values without losing // precision. // // This approach works best when the batch size is the sqrt of // numpixels, which makes the num batches roughly equal to the // number of pixels / batch. ImageBufAlgo::PixelStats tmp; reset (tmp, nchannels); reset (stats, nchannels); int PIXELS_PER_BATCH = std::max (1024, static_cast<int>(sqrt((double)src.spec().image_pixels()))); if (src.deep()) { // Loop over all pixels ... for (ImageBuf::ConstIterator<T> s(src, roi); ! s.done(); ++s) { int samples = s.deep_samples(); if (! samples) continue; for (int c = roi.chbegin; c < roi.chend; ++c) { for (int i = 0; i < samples; ++i) { float value = s.deep_value (c, i); val (tmp, c, value); if ((tmp.finitecount[c] % PIXELS_PER_BATCH) == 0) { merge (stats, tmp); reset (tmp, nchannels); } } } } } else { // Non-deep case // Loop over all pixels ... for (ImageBuf::ConstIterator<T> s(src, roi); ! s.done(); ++s) { for (int c = roi.chbegin; c < roi.chend; ++c) { float value = s[c]; val (tmp, c, value); if ((tmp.finitecount[c] % PIXELS_PER_BATCH) == 0) { merge (stats, tmp); reset (tmp, nchannels); } } } } // Merge anything left over merge (stats, tmp); // Compute final results finalize (stats); return ! src.has_error(); };
bool ImageBufAlgo::deepen (ImageBuf &dst, const ImageBuf &src, float zvalue, ROI roi, int nthreads) { if (src.deep()) { // For some reason, we were asked to deepen an already-deep image. // So just copy it. return dst.copy (src); // FIXME: once paste works for deep files, this should really be // return paste (dst, roi.xbegin, roi.ybegin, roi.zbegin, roi.chbegin, // src, roi, nthreads); } // Construct an ideal spec for dst, which is like src but deep. const ImageSpec &srcspec (src.spec()); int nc = srcspec.nchannels; int zback_channel = -1; ImageSpec force_spec = srcspec; force_spec.deep = true; force_spec.set_format (TypeDesc::FLOAT); force_spec.channelformats.clear(); for (int c = 0; c < nc; ++c) { if (force_spec.channelnames[c] == "Z") force_spec.z_channel = c; else if (force_spec.channelnames[c] == "Zback") zback_channel = c; } bool add_z_channel = (force_spec.z_channel < 0); if (add_z_channel) { // No z channel? Make one. force_spec.z_channel = force_spec.nchannels++; force_spec.channelnames.push_back ("Z"); } if (! IBAprep (roi, &dst, &src, NULL, &force_spec, IBAprep_SUPPORT_DEEP)) return false; if (! dst.deep()) { dst.error ("Cannot deepen to a flat image"); return false; } float *pixel = OIIO_ALLOCA (float, nc); // First, figure out which pixels get a sample and which do not for (int z = roi.zbegin; z < roi.zend; ++z) for (int y = roi.ybegin; y < roi.yend; ++y) for (int x = roi.xbegin; x < roi.xend; ++x) { bool has_sample = false; src.getpixel (x, y, z, pixel); for (int c = 0; c < nc; ++c) if (c != force_spec.z_channel && c != zback_channel && pixel[c] != 0.0f) { has_sample = true; break; } if (! has_sample && ! add_z_channel) for (int c = 0; c < nc; ++c) if ((c == force_spec.z_channel || c == zback_channel) && (pixel[c] != 0.0f && pixel[c] < 1e30)) { has_sample = true; break; } if (has_sample) dst.set_deep_samples (x, y, z, 1); } dst.deep_alloc (); // Now actually set the values for (int z = roi.zbegin; z < roi.zend; ++z) for (int y = roi.ybegin; y < roi.yend; ++y) for (int x = roi.xbegin; x < roi.xend; ++x) { if (dst.deep_samples (x, y, z) == 0) continue; for (int c = 0; c < nc; ++c) dst.set_deep_value (x, y, z, c, 0 /*sample*/, src.getchannel (x, y, z, c)); if (add_z_channel) dst.set_deep_value (x, y, z, nc, 0, zvalue); } bool ok = true; // FIXME -- the above doesn't split into threads. Someday, it should // be refactored like this: // OIIO_DISPATCH_COMMON_TYPES2 (ok, "deepen", deepen_, // dst.spec().format, srcspec.format, // dst, src, add_z_channel, z, roi, nthreads); return ok; }
static void print_stats (const std::string &filename, const ImageSpec &originalspec, int subimage=0, int miplevel=0, bool indentmip=false) { const char *indent = indentmip ? " " : " "; ImageBuf input; if (! read_input (filename, input, subimage, miplevel)) { std::cerr << "Stats: read error: " << input.geterror() << "\n"; return; } PixelStats stats; if (! computePixelStats (stats, input)) { printf ("%sStats: (unable to compute)\n", indent); return; } // The original spec is used, otherwise the bit depth will // be reported incorrectly (as FLOAT) unsigned int maxval = (unsigned int)get_intsample_maxval (originalspec); printf ("%sStats Min: ", indent); for (unsigned int i=0; i<stats.min.size(); ++i) { print_stats_num (stats.min[i], maxval, true); printf (" "); } print_stats_footer (maxval); printf ("\n"); printf ("%sStats Max: ", indent); for (unsigned int i=0; i<stats.max.size(); ++i) { print_stats_num (stats.max[i], maxval, true); printf (" "); } print_stats_footer (maxval); printf ("\n"); printf ("%sStats Avg: ", indent); for (unsigned int i=0; i<stats.avg.size(); ++i) { print_stats_num (stats.avg[i], maxval, false); printf (" "); } print_stats_footer (maxval); printf ("\n"); printf ("%sStats StdDev: ", indent); for (unsigned int i=0; i<stats.stddev.size(); ++i) { print_stats_num (stats.stddev[i], maxval, false); printf (" "); } print_stats_footer (maxval); printf ("\n"); printf ("%sStats NanCount: ", indent); for (unsigned int i=0; i<stats.nancount.size(); ++i) { printf ("%llu ", (unsigned long long)stats.nancount[i]); } printf ("\n"); printf ("%sStats InfCount: ", indent); for (unsigned int i=0; i<stats.infcount.size(); ++i) { printf ("%llu ", (unsigned long long)stats.infcount[i]); } printf ("\n"); printf ("%sStats FiniteCount: ", indent); for (unsigned int i=0; i<stats.finitecount.size(); ++i) { printf ("%llu ", (unsigned long long)stats.finitecount[i]); } printf ("\n"); if (input.deep()) { const DeepData *dd (input.deepdata()); size_t npixels = dd->nsamples.size(); size_t totalsamples = 0, emptypixels = 0; size_t maxsamples = 0, minsamples = std::numeric_limits<size_t>::max(); size_t maxsamples_npixels = 0; float mindepth = std::numeric_limits<float>::max(); float maxdepth = -std::numeric_limits<float>::max(); Imath::V3i maxsamples_pixel(-1,-1,-1), minsamples_pixel(-1,-1,-1); Imath::V3i mindepth_pixel(-1,-1,-1), maxdepth_pixel(-1,-1,-1); size_t sampoffset = 0; int depthchannel = -1; for (int c = 0; c < input.nchannels(); ++c) if (Strutil::iequals (originalspec.channelnames[c], "Z")) depthchannel = c; int xend = originalspec.x + originalspec.width; int yend = originalspec.y + originalspec.height; int zend = originalspec.z + originalspec.depth; size_t p = 0; for (int z = originalspec.z; z < zend; ++z) { for (int y = originalspec.y; y < yend; ++y) { for (int x = originalspec.x; x < xend; ++x, ++p) { size_t c = input.deep_samples (x, y, z); totalsamples += c; if (c == maxsamples) ++maxsamples_npixels; if (c > maxsamples) { maxsamples = c; maxsamples_pixel.setValue (x, y, z); maxsamples_npixels = 1; } if (c < minsamples) minsamples = c; if (c == 0) ++emptypixels; if (depthchannel >= 0) { for (unsigned int s = 0; s < c; ++s) { float d = input.deep_value (x, y, z, depthchannel, s); if (d < mindepth) { mindepth = d; mindepth_pixel.setValue (x, y, z); } if (d > maxdepth) { maxdepth = d; maxdepth_pixel.setValue (x, y, z); } } } sampoffset += c; } } } printf ("%sMin deep samples in any pixel : %llu\n", indent, (unsigned long long)minsamples); printf ("%sMax deep samples in any pixel : %llu\n", indent, (unsigned long long)maxsamples); printf ("%s%llu pixel%s had the max of %llu samples, including (x=%d, y=%d)\n", indent, (unsigned long long)maxsamples_npixels, maxsamples_npixels > 1 ? "s" : "", (unsigned long long)maxsamples, maxsamples_pixel.x, maxsamples_pixel.y); printf ("%sAverage deep samples per pixel: %.2f\n", indent, double(totalsamples)/double(npixels)); printf ("%sTotal deep samples in all pixels: %llu\n", indent, (unsigned long long)totalsamples); printf ("%sPixels with deep samples : %llu\n", indent, (unsigned long long)(npixels-emptypixels)); printf ("%sPixels with no deep samples: %llu\n", indent, (unsigned long long)emptypixels); printf ("%sMinimum depth was %g at (%d, %d)\n", indent, mindepth, mindepth_pixel.x, mindepth_pixel.y); printf ("%sMaximum depth was %g at (%d, %d)\n", indent, maxdepth, maxdepth_pixel.x, maxdepth_pixel.y); } else { std::vector<float> constantValues(input.spec().nchannels); if (isConstantColor(input, &constantValues[0])) { printf ("%sConstant: Yes\n", indent); printf ("%sConstant Color: ", indent); for (unsigned int i=0; i<constantValues.size(); ++i) { print_stats_num (constantValues[i], maxval, false); printf (" "); } print_stats_footer (maxval); printf ("\n"); } else { printf ("%sConstant: No\n", indent); } if( isMonochrome(input)) { printf ("%sMonochrome: Yes\n", indent); } else { printf ("%sMonochrome: No\n", indent); } } }