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::rotate180 (ImageBuf &dst, const ImageBuf &src, ROI roi, int nthreads) { if (&dst == &src) { // Handle in-place operation ImageBuf tmp; tmp.swap (const_cast<ImageBuf&>(src)); return rotate180 (dst, tmp, roi, nthreads); } ROI src_roi = roi.defined() ? roi : src.roi(); ROI src_roi_full = src.roi_full(); int xoffset = src_roi.xbegin - src_roi_full.xbegin; int xstart = src_roi_full.xend - xoffset - src_roi.width(); int yoffset = src_roi.ybegin - src_roi_full.ybegin; int ystart = src_roi_full.yend - yoffset - src_roi.height(); ROI dst_roi (xstart, xstart+src_roi.width(), ystart, ystart+src_roi.height(), src_roi.zbegin, src_roi.zend, src_roi.chbegin, src_roi.chend); ASSERT (dst_roi.width() == src_roi.width() && dst_roi.height() == src_roi.height()); // Compute the destination ROI, it's the source ROI reflected across // the midline of the display window. IBAprep (dst_roi, &dst, &src); bool ok; OIIO_DISPATCH_TYPES2 (ok, "rotate180", rotate180_, dst.spec().format, src.spec().format, dst, src, dst_roi, nthreads); return ok; }
bool ImageBufAlgo::flop (ImageBuf &dst, const ImageBuf &src, ROI roi, int nthreads) { IBAprep (roi, &dst); OIIO_DISPATCH_TYPES2 ("flop", flop_, dst.spec().format, src.spec().format, dst, src, roi, nthreads); return false; }
bool ImageBufAlgo::mul (ImageBuf &dst, const ImageBuf &A, const float *b, ROI roi, int nthreads) { if (! IBAprep (roi, &dst, &A)) return false; OIIO_DISPATCH_TYPES2 ("mul", mul_impl, dst.spec().format, A.spec().format, dst, A, b, roi, nthreads); return true; }
bool ImageBufAlgo::resize (ImageBuf &dst, const ImageBuf &src, const std::string &filtername_, float fwidth, ROI roi, int nthreads) { if (! IBAprep (roi, &dst, &src)) return false; const ImageSpec &srcspec (src.spec()); const ImageSpec &dstspec (dst.spec()); if (dstspec.nchannels != srcspec.nchannels) { dst.error ("channel number mismatch: %d vs. %d", dst.spec().nchannels, src.spec().nchannels); return false; } if (dstspec.depth > 1 || srcspec.depth > 1) { dst.error ("ImageBufAlgo::resize does not support volume images"); return false; } // Resize ratios float wratio = float(dstspec.full_width) / float(srcspec.full_width); float hratio = float(dstspec.full_height) / float(srcspec.full_height); // Set up a shared pointer with custom deleter to make sure any // filter we allocate here is properly destroyed. boost::shared_ptr<Filter2D> filter ((Filter2D*)NULL, Filter2D::destroy); std::string filtername = filtername_; if (filtername.empty()) { // No filter name supplied -- pick a good default if (wratio > 1.0f || hratio > 1.0f) filtername = "blackman-harris"; else filtername = "lanczos3"; } for (int i = 0, e = Filter2D::num_filters(); i < e; ++i) { FilterDesc fd; Filter2D::get_filterdesc (i, &fd); if (fd.name == filtername) { float w = fwidth > 0.0f ? fwidth : fd.width * std::max (1.0f, wratio); float h = fwidth > 0.0f ? fwidth : fd.width * std::max (1.0f, hratio); filter.reset (Filter2D::create (filtername, w, h)); break; } } if (! filter) { dst.error ("Filter \"%s\" not recognized", filtername); return false; } OIIO_DISPATCH_TYPES2 ("resize", resize_, dstspec.format, srcspec.format, dst, src, filter.get(), roi, nthreads); return false; }
bool ImageBufAlgo::crop (ImageBuf &dst, const ImageBuf &src, ROI roi, int nthreads) { dst.clear (); roi.chend = std::min (roi.chend, src.nchannels()); IBAprep (roi, &dst, &src); OIIO_DISPATCH_TYPES2 ("crop", crop_, dst.spec().format, src.spec().format, dst, src, roi, nthreads); return false; }
bool ImageBufAlgo::circular_shift (ImageBuf &dst, const ImageBuf &src, int xshift, int yshift, int zshift, ROI roi, int nthreads) { IBAprep (roi, &dst, &src); OIIO_DISPATCH_TYPES2 ("circular_shift", circular_shift_, dst.spec().format, src.spec().format, dst, src, xshift, yshift, zshift, roi, roi, nthreads); return false; }
bool ImageBufAlgo::pow (ImageBuf &dst, const ImageBuf &A, const float *b, ROI roi, int nthreads) { if (! IBAprep (roi, &dst, &A)) return false; bool ok; OIIO_DISPATCH_TYPES2 (ok, "pow", pow_impl, dst.spec().format, A.spec().format, dst, A, b, roi, nthreads); return ok; }
bool ImageBufAlgo::mul (ImageBuf &dst, const ImageBuf &A, float b, ROI roi, int nthreads) { if (! IBAprep (roi, &dst, &A)) return false; int nc = A.nchannels(); float *vals = ALLOCA (float, nc); for (int c = 0; c < nc; ++c) vals[c] = b; OIIO_DISPATCH_TYPES2 ("mul", mul_impl, dst.spec().format, A.spec().format, dst, A, vals, roi, nthreads); }
bool ImageBufAlgo::sub (ImageBuf &dst, const ImageBuf &A, const float *b, ROI roi, int nthreads) { if (! IBAprep (roi, &dst, &A)) return false; int nc = A.nchannels(); float *vals = ALLOCA (float, nc); for (int c = 0; c < nc; ++c) vals[c] = -b[c]; OIIO_DISPATCH_TYPES2 ("sub", add_impl, dst.spec().format, A.spec().format, dst, A, vals, roi, nthreads); return true; }
bool ImageBufAlgo::transpose (ImageBuf &dst, const ImageBuf &src, ROI roi, int nthreads) { if (! roi.defined()) roi = get_roi (src.spec()); roi.chend = std::min (roi.chend, src.nchannels()); ROI dst_roi (roi.ybegin, roi.yend, roi.xbegin, roi.xend, roi.zbegin, roi.zend, roi.chbegin, roi.chend); IBAprep (dst_roi, &dst); OIIO_DISPATCH_TYPES2 ("transpose", transpose_, dst.spec().format, src.spec().format, dst, src, roi, nthreads); return false; }
bool ImageBufAlgo::convolve (ImageBuf &dst, const ImageBuf &src, const ImageBuf &kernel, bool normalize, ROI roi, int nthreads) { if (! IBAprep (roi, &dst, &src)) return false; if (dst.nchannels() != src.nchannels()) { dst.error ("channel number mismatch: %d vs. %d", dst.spec().nchannels, src.spec().nchannels); return false; } OIIO_DISPATCH_TYPES2 ("convolve", convolve_, dst.spec().format, src.spec().format, dst, src, kernel, normalize, roi, nthreads); return false; }
bool ImageBufAlgo::paste (ImageBuf &dst, int xbegin, int ybegin, int zbegin, int chbegin, const ImageBuf &src, ROI srcroi, int nthreads) { if (! srcroi.defined()) srcroi = get_roi(src.spec()); ROI dstroi (xbegin, xbegin+srcroi.width(), ybegin, ybegin+srcroi.height(), zbegin, zbegin+srcroi.depth(), chbegin, chbegin+srcroi.nchannels()); ROI dstroi_save = dstroi; // save the original IBAprep (dstroi, &dst); // do the actual copying OIIO_DISPATCH_TYPES2 ("paste", paste_, dst.spec().format, src.spec().format, dst, dstroi_save, src, srcroi, nthreads); return false; }
bool ImageBufAlgo::resample (ImageBuf &dst, const ImageBuf &src, bool interpolate, ROI roi, int nthreads) { if (! IBAprep (roi, &dst, &src)) return false; if (dst.nchannels() != src.nchannels()) { dst.error ("channel number mismatch: %d vs. %d", dst.spec().nchannels, src.spec().nchannels); return false; } if (dst.spec().depth > 1 || src.spec().depth > 1) { dst.error ("ImageBufAlgo::resample does not support volume images"); return false; } OIIO_DISPATCH_TYPES2 ("resample", resample_, dst.spec().format, src.spec().format, dst, src, interpolate, roi, nthreads); return false; }
bool ImageBufAlgo::clamp (ImageBuf &dst, const ImageBuf &src, const float *min, const float *max, bool clampalpha01, ROI roi, int nthreads) { if (! IBAprep (roi, &dst, &src)) return false; std::vector<float> minvec, maxvec; if (! min) { minvec.resize (dst.nchannels(), -std::numeric_limits<float>::max()); min = &minvec[0]; } if (! max) { maxvec.resize (dst.nchannels(), std::numeric_limits<float>::max()); max = &maxvec[0]; } OIIO_DISPATCH_TYPES2 ("clamp", clamp_, dst.spec().format, src.spec().format, dst, src, min, max, clampalpha01, roi, nthreads); return false; }
bool ImageBufAlgo::rotate270 (ImageBuf &dst, const ImageBuf &src, ROI roi, int nthreads) { if (&dst == &src) { // Handle in-place operation ImageBuf tmp; tmp.swap (const_cast<ImageBuf&>(src)); return rotate270 (dst, tmp, roi, nthreads); } ROI src_roi = roi.defined() ? roi : src.roi(); ROI src_roi_full = src.roi_full(); // Rotated full ROI swaps width and height, and keeps its origin // where the original origin was. ROI dst_roi_full (src_roi_full.xbegin, src_roi_full.xbegin+src_roi_full.height(), src_roi_full.ybegin, src_roi_full.ybegin+src_roi_full.width(), src_roi_full.zbegin, src_roi_full.zend, src_roi_full.chbegin, src_roi_full.chend); ROI dst_roi (src_roi.ybegin, src_roi.yend, src_roi_full.xend-src_roi.xend, src_roi_full.xend-src_roi.xbegin, src_roi.zbegin, src_roi.zend, src_roi.chbegin, src_roi.chend); ASSERT (dst_roi.width() == src_roi.height() && dst_roi.height() == src_roi.width()); bool dst_initialized = dst.initialized(); IBAprep (dst_roi, &dst, &src); if (! dst_initialized) dst.set_roi_full (dst_roi_full); bool ok; OIIO_DISPATCH_TYPES2 (ok, "rotate270", rotate270_, dst.spec().format, src.spec().format, dst, src, dst_roi, nthreads); return ok; }
bool ImageBufAlgo::transpose (ImageBuf &dst, const ImageBuf &src, ROI roi, int nthreads) { if (! roi.defined()) roi = get_roi (src.spec()); roi.chend = std::min (roi.chend, src.nchannels()); ROI dst_roi (roi.ybegin, roi.yend, roi.xbegin, roi.xend, roi.zbegin, roi.zend, roi.chbegin, roi.chend); bool dst_initialized = dst.initialized(); IBAprep (dst_roi, &dst); if (! dst_initialized) { ROI r = src.roi_full(); ROI dst_roi_full (r.ybegin, r.yend, r.xbegin, r.xend, r.zbegin, r.zend, r.chbegin, r.chend); dst.set_roi_full (dst_roi_full); } bool ok; OIIO_DISPATCH_TYPES2 (ok, "transpose", transpose_, dst.spec().format, src.spec().format, dst, src, roi, nthreads); return ok; }
bool ImageBufAlgo::resize (ImageBuf &dst, const ImageBuf &src, Filter2D *filter, ROI roi, int nthreads) { if (! IBAprep (roi, &dst, &src)) return false; if (dst.nchannels() != src.nchannels()) { dst.error ("channel number mismatch: %d vs. %d", dst.spec().nchannels, src.spec().nchannels); return false; } if (dst.spec().depth > 1 || src.spec().depth > 1) { dst.error ("ImageBufAlgo::resize does not support volume images"); return false; } // Set up a shared pointer with custom deleter to make sure any // filter we allocate here is properly destroyed. boost::shared_ptr<Filter2D> filterptr ((Filter2D*)NULL, Filter2D::destroy); bool allocfilter = (filter == NULL); if (allocfilter) { // If no filter was provided, punt and just linearly interpolate. const ImageSpec &srcspec (src.spec()); const ImageSpec &dstspec (dst.spec()); float wratio = float(dstspec.full_width) / float(srcspec.full_width); float hratio = float(dstspec.full_height) / float(srcspec.full_height); float w = 2.0f * std::max (1.0f, wratio); float h = 2.0f * std::max (1.0f, hratio); filter = Filter2D::create ("triangle", w, h); filterptr.reset (filter); } OIIO_DISPATCH_TYPES2 ("resize", resize_, dst.spec().format, src.spec().format, dst, src, filter, roi, nthreads); return false; }