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::zover (ImageBuf &R, const ImageBuf &A, const ImageBuf &B, bool z_zeroisinf, ROI roi, int nthreads) { const ImageSpec &specR = R.spec(); const ImageSpec &specA = A.spec(); const ImageSpec &specB = B.spec(); int nchannels_R, nchannels_A, nchannels_B; int alpha_R, alpha_A, alpha_B; int z_R, z_A, z_B; int colors_R, colors_A, colors_B; bool initialized_R = decode_over_channels (R, nchannels_R, alpha_R, z_R, colors_R); bool initialized_A = decode_over_channels (A, nchannels_A, alpha_A, z_A, colors_A); bool initialized_B = decode_over_channels (B, nchannels_B, alpha_B, z_B, colors_B); if (! initialized_A || ! initialized_B) { R.error ("Can't 'zover' uninitialized images"); return false; } // Fail if the input images don't have a Z channel. if (z_A < 0 || z_B < 0 || (initialized_R && z_R < 0)) { R.error ("'zover' requires Z channels"); return false; } // Fail if the input images don't have an alpha channel. if (alpha_A < 0 || alpha_B < 0 || (initialized_R && alpha_R < 0)) { R.error ("'zover' requires alpha channels"); return false; } // Fail for mismatched channel counts if (colors_A != colors_B || colors_A < 1) { R.error ("Can't 'zover' images with mismatched color channel counts (%d vs %d)", colors_A, colors_B); return false; } // Fail for unaligned alpha or z channels if (alpha_A != alpha_B || z_A != z_B || (initialized_R && alpha_R != alpha_A) || (initialized_R && z_R != z_A)) { R.error ("Can't 'zover' images with mismatched channel order", colors_A, colors_B); return false; } // At present, this operation only supports ImageBuf's containing // float pixel data. if ((initialized_R && specR.format != TypeDesc::TypeFloat) || specA.format != TypeDesc::TypeFloat || specB.format != TypeDesc::TypeFloat) { R.error ("Unsupported pixel data format combination '%s = %s zover %s'", specR.format, specA.format, specB.format); return false; } // Uninitialized R -> size it to the union of A and B. if (! initialized_R) { ImageSpec newspec = specA; set_roi (newspec, roi_union (get_roi(specA), get_roi(specB))); R.reset ("zover", newspec); } // Specified ROI -> use it. Unspecified ROI -> initialize from R. if (! roi.defined()) roi = get_roi (R.spec()); parallel_image (boost::bind (over_impl<float,float,float>, boost::ref(R), boost::cref(A), boost::cref(B), _1, true, z_zeroisinf), roi, nthreads); return ! R.has_error(); }
OIIO_NAMESPACE_BEGIN bool ImageBufAlgo::IBAprep (ROI &roi, ImageBuf *dst, const ImageBuf *A, const ImageBuf *B, const ImageBuf *C, ImageSpec *force_spec, int prepflags) { if ((A && !A->initialized()) || (B && !B->initialized()) || (C && !C->initialized())) { if (dst) dst->error ("Uninitialized input image"); return false; } int maxchans = 10000; if (prepflags & IBAprep_CLAMP_MUTUAL_NCHANNELS) { // Instructions to clamp chend to the highest of the inputs if (dst && dst->initialized()) maxchans = std::min (maxchans, dst->spec().nchannels); if (A && A->initialized()) maxchans = std::min (maxchans, A->spec().nchannels); if (B && B->initialized()) maxchans = std::min (maxchans, B->spec().nchannels); if (C && C->initialized()) maxchans = std::min (maxchans, C->spec().nchannels); } if (dst->initialized()) { // Valid destination image. Just need to worry about ROI. if (roi.defined()) { // Shrink-wrap ROI to the destination (including chend) roi = roi_intersection (roi, get_roi(dst->spec())); } else { // No ROI? Set it to all of dst's pixel window. roi = get_roi (dst->spec()); } // If the dst is initialized but is a cached image, we'll need // to fully read it into allocated memory so that we're able // to write to it subsequently. dst->make_writeable (true); } else { // Not an initialized destination image! ASSERT ((A || roi.defined()) && "ImageBufAlgo without any guess about region of interest"); ROI full_roi; if (! roi.defined()) { // No ROI -- make it the union of the pixel regions of the inputs roi = A->roi(); full_roi = A->roi_full(); if (B) { roi = roi_union (roi, B->roi()); full_roi = roi_union (full_roi, B->roi_full()); } if (C) { roi = roi_union (roi, C->roi()); full_roi = roi_union (full_roi, C->roi_full()); } } else { if (A) { roi.chend = std::min (roi.chend, A->nchannels()); if (! (prepflags & IBAprep_NO_COPY_ROI_FULL)) full_roi = A->roi_full(); } else { full_roi = roi; } } // Now we allocate space for dst. Give it A's spec, but adjust // the dimensions to match the ROI. ImageSpec spec; if (A) { // If there's an input image, give dst A's spec (with // modifications detailed below...) spec = force_spec ? (*force_spec) : A->spec(); // For multiple inputs, if they aren't the same data type, punt and // allocate a float buffer. If the user wanted something else, // they should have pre-allocated dst with their desired format. if (B && A->spec().format != B->spec().format) spec.set_format (TypeDesc::FLOAT); if (C && (A->spec().format != C->spec().format || B->spec().format != C->spec().format)) spec.set_format (TypeDesc::FLOAT); // No good can come from automatically polluting an ImageBuf // with some other ImageBuf's tile sizes. spec.tile_width = 0; spec.tile_height = 0; spec.tile_depth = 0; } else if (force_spec) { spec = *force_spec; } else { spec.set_format (TypeDesc::FLOAT); spec.nchannels = roi.chend; spec.default_channel_names (); } // Set the image dimensions based on ROI. set_roi (spec, roi); if (full_roi.defined()) set_roi_full (spec, full_roi); else set_roi_full (spec, roi); if (prepflags & IBAprep_NO_COPY_METADATA) spec.extra_attribs.clear(); else if (! (prepflags & IBAprep_COPY_ALL_METADATA)) { // Since we're altering pixels, be sure that any existing SHA // hash of dst's pixel values is erased. spec.erase_attribute ("oiio:SHA-1"); static boost::regex regex_sha ("SHA-1=[[:xdigit:]]*[ ]*"); std::string desc = spec.get_string_attribute ("ImageDescription"); if (desc.size()) spec.attribute ("ImageDescription", boost::regex_replace (desc, regex_sha, "")); } dst->reset (spec); } roi.chend = std::min (roi.chend, maxchans); if (prepflags & IBAprep_REQUIRE_ALPHA) { if (dst->spec().alpha_channel < 0 || (A && A->spec().alpha_channel < 0) || (B && B->spec().alpha_channel < 0) || (C && C->spec().alpha_channel < 0)) { dst->error ("images must have alpha channels"); return false; } } if (prepflags & IBAprep_REQUIRE_Z) { if (dst->spec().z_channel < 0 || (A && A->spec().z_channel < 0) || (B && B->spec().z_channel < 0) || (C && C->spec().z_channel < 0)) { dst->error ("images must have depth channels"); return false; } } if (prepflags & IBAprep_REQUIRE_SAME_NCHANNELS) { int n = dst->spec().nchannels; if ((A && A->spec().nchannels != n) || (B && B->spec().nchannels != n) || (C && C->spec().nchannels != n)) { dst->error ("images must have the same number of channels"); return false; } } if (prepflags & IBAprep_NO_SUPPORT_VOLUME) { if (dst->spec().depth > 1 || (A && A->spec().depth > 1) || (B && B->spec().depth > 1) || (C && C->spec().depth > 1)) { dst->error ("volumes not supported"); return false; } } if (! (prepflags & IBAprep_SUPPORT_DEEP) && ((dst && dst->deep()) || (A && A->deep()) || (B && B->deep()) || (C && C->deep()))) { dst->error ("deep data not supported"); return false; } return true; }