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; }
bool ImageBufAlgo::absdiff (ImageBuf &dst, const ImageBuf &A, const ImageBuf &B, ROI roi, int nthreads) { 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, "absdiff", absdiff_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 abs (dst, A, roi, nthreads); } else { // B exists abs (dst, B, roi, nthreads); } } 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::transpose (ImageBuf &dst, const ImageBuf &src, ROI roi, int nthreads) { pvt::LoggedTimer logtime("IBA::transpose"); 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(); if (! IBAprep (dst_roi, &dst)) return false; 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; if (dst.spec().format == src.spec().format) { OIIO_DISPATCH_TYPES (ok, "transpose", transpose_, dst.spec().format, dst, src, roi, nthreads); } else { OIIO_DISPATCH_COMMON_TYPES2 (ok, "transpose", transpose_, dst.spec().format, src.spec().format, dst, src, roi, nthreads); } return ok; }
bool ImageBufAlgo::colorconvert (ImageBuf &dst, const ImageBuf &src, const ColorProcessor* processor, bool unpremult, ROI roi, int nthreads) { // If the processor is NULL, return false (error) if (!processor) { dst.error ("Passed NULL ColorProcessor to colorconvert() [probable application bug]"); return false; } // If the processor is a no-op and the conversion is being done // in place, no work needs to be done. Early exit. if (processor->isNoOp() && (&dst == &src)) return true; if (! IBAprep (roi, &dst, &src)) return false; // If the processor is a no-op (and it's not an in-place conversion), // use paste() to simplify the operation. if (processor->isNoOp()) { roi.chend = std::max (roi.chbegin+4, roi.chend); return ImageBufAlgo::paste (dst, roi.xbegin, roi.ybegin, roi.zbegin, roi.chbegin, src, roi, nthreads); } bool ok = true; OIIO_DISPATCH_COMMON_TYPES2 (ok, "colorconvert", colorconvert_impl, dst.spec().format, src.spec().format, dst, src, processor, unpremult, roi, nthreads); return ok; }
bool ImageBufAlgo::flip(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 flip (dst, tmp, roi, nthreads); } pvt::LoggedTimer logtime("IBA::flip"); ROI src_roi = roi.defined() ? roi : src.roi(); ROI src_roi_full = src.roi_full(); int offset = src_roi.ybegin - src_roi_full.ybegin; int start = src_roi_full.yend - offset - src_roi.height(); ROI dst_roi (src_roi.xbegin, src_roi.xend, start, start+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. if (! IBAprep (dst_roi, &dst, &src)) return false; bool ok; OIIO_DISPATCH_COMMON_TYPES2 (ok, "flip", flip_, dst.spec().format, src.spec().format, dst, src, dst_roi, nthreads); return ok; }
bool ImageBufAlgo::mul (ImageBuf &dst, const float *val, ROI roi, int nthreads) { IBAprep (roi, &dst); OIIO_DISPATCH_TYPES ("mul", mul_impl, dst.spec().format, dst, val, roi, nthreads); return true; }
bool ImageBufAlgo::add (ImageBuf &dst, const float *val, ROI roi, int nthreads) { IBAprep (roi, &dst); OIIO_DISPATCH_TYPES ("add", add_inplace, dst.spec().format, dst, val, roi, nthreads); return true; }
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::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::zero (ImageBuf &dst, ROI roi, int nthreads) { if (! IBAprep (roi, &dst)) return false; float *zero = ALLOCA(float,roi.chend); memset (zero, 0, roi.chend*sizeof(float)); return fill (dst, zero, roi, nthreads); }
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::sub (ImageBuf &dst, const ImageBuf &A, const ImageBuf &B, ROI roi, int nthreads) { IBAprep (roi, &dst, &A, &B); OIIO_DISPATCH_COMMON_TYPES3 ("sub", sub_impl, dst.spec().format, A.spec().format, B.spec().format, dst, A, B, roi, nthreads); return true; }
bool ImageBufAlgo::fill (ImageBuf &dst, const float *pixel, ROI roi, int nthreads) { ASSERT (pixel && "fill must have a non-NULL pixel value pointer"); if (! IBAprep (roi, &dst)) return false; OIIO_DISPATCH_TYPES ("fill", fill_, dst.spec().format, dst, pixel, 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::mul (ImageBuf &dst, const ImageBuf &A, const ImageBuf &B, ROI roi, int nthreads) { if (! IBAprep (roi, &dst, &A, &B)) return false; OIIO_DISPATCH_COMMON_TYPES3 ("mul", mul_impl, dst.spec().format, A.spec().format, B.spec().format, dst, A, B, roi, nthreads); return true; }
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::mul (ImageBuf &dst, const ImageBuf &A, const float *b, ROI roi, int nthreads) { if (! IBAprep (roi, &dst, &A, IBAprep_CLAMP_MUTUAL_NCHANNELS)) return false; bool ok; OIIO_DISPATCH_COMMON_TYPES2 (ok, "mul", mul_impl, dst.spec().format, A.spec().format, dst, A, b, roi, nthreads); return ok; }
bool ImageBufAlgo::premult (ImageBuf &dst, ROI roi, int nthreads) { if (dst.spec().alpha_channel < 0) return true; IBAprep (roi, &dst); OIIO_DISPATCH_TYPES ("premult", premult_, dst.spec().format, dst, roi, nthreads); return true; }
bool ImageBufAlgo::clamp (ImageBuf &dst, float min, float max, bool clampalpha01, ROI roi, int nthreads) { IBAprep (roi, &dst); std::vector<float> minvec (dst.nchannels(), min); std::vector<float> maxvec (dst.nchannels(), max); OIIO_DISPATCH_TYPES ("clamp", clamp_, dst.spec().format, dst, &minvec[0], &maxvec[0], clampalpha01, 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::sub (ImageBuf &dst, const ImageBuf &A, const ImageBuf &B, ROI roi, int nthreads) { if (! IBAprep (roi, &dst, &A, &B)) return false; bool ok; OIIO_DISPATCH_COMMON_TYPES3 (ok, "sub", sub_impl, dst.spec().format, A.spec().format, B.spec().format, dst, A, B, roi, nthreads); return ok; }
bool ImageBufAlgo::div (ImageBuf &dst, const ImageBuf &A, const ImageBuf &B, ROI roi, int nthreads) { if (! IBAprep (roi, &dst, &A, &B, NULL, 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; }
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::checker (ImageBuf &dst, int width, int height, int depth, const float *color1, const float *color2, int xoffset, int yoffset, int zoffset, ROI roi, int nthreads) { if (! IBAprep (roi, &dst)) return false; OIIO_DISPATCH_TYPES ("checker", checker_, dst.spec().format, dst, Dim3(width, height, depth), color1, color2, Dim3(xoffset, yoffset, zoffset), 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::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::pow (ImageBuf &dst, const ImageBuf &A, float b, ROI roi, int nthreads) { if (! IBAprep (roi, &dst, &A, IBAprep_CLAMP_MUTUAL_NCHANNELS)) return false; int nc = A.nchannels(); float *vals = ALLOCA (float, nc); for (int c = 0; c < nc; ++c) vals[c] = b; bool ok; OIIO_DISPATCH_COMMON_TYPES2 (ok, "pow", pow_impl, dst.spec().format, A.spec().format, dst, A, vals, roi, nthreads); return ok; }
bool ImageBufAlgo::div (ImageBuf &dst, const ImageBuf &A, const float *b, ROI roi, int nthreads) { if (! IBAprep (roi, &dst, &A, IBAprep_CLAMP_MUTUAL_NCHANNELS)) return false; int nc = dst.nchannels(); float *binv = OIIO_ALLOCA (float, nc); for (int c = 0; c < nc; ++c) binv[c] = (b[c] == 0.0f) ? 1.0f : 1.0f/b[c]; bool ok; OIIO_DISPATCH_COMMON_TYPES2 (ok, "div", mul_impl, dst.spec().format, A.spec().format, dst, A, binv, roi, nthreads); return ok; }