bool ImageBufAlgo::make_kernel (ImageBuf &dst, const char *name, float width, float height, float depth, bool normalize) { int w = std::max (1, (int)ceilf(width)); int h = std::max (1, (int)ceilf(height)); int d = std::max (1, (int)ceilf(depth)); // Round up size to odd w |= 1; h |= 1; d |= 1; ImageSpec spec (w, h, 1 /*channels*/, TypeDesc::FLOAT); spec.depth = d; spec.x = -w/2; spec.y = -h/2; spec.z = -d/2; spec.full_x = spec.x; spec.full_y = spec.y; spec.full_z = spec.z; spec.full_width = spec.width; spec.full_height = spec.height; spec.full_depth = spec.depth; dst.alloc (spec); if (Filter2D *filter = Filter2D::create (name, width, height)) { // Named continuous filter from filter.h for (ImageBuf::Iterator<float> p (dst); ! p.done(); ++p) p[0] = (*filter)((float)p.x(), (float)p.y()); delete filter; } else if (!strcmp (name, "binomial")) { // Binomial filter float *wfilter = ALLOCA (float, width); for (int i = 0; i < width; ++i) wfilter[i] = binomial (width-1, i); float *hfilter = (height == width) ? wfilter : ALLOCA (float, height); if (height != width) for (int i = 0; i < height; ++i) hfilter[i] = binomial (height-1, i); float *dfilter = ALLOCA (float, depth); if (depth == 1) dfilter[0] = 1; else for (int i = 0; i < depth; ++i) dfilter[i] = binomial (depth-1, i); for (ImageBuf::Iterator<float> p (dst); ! p.done(); ++p) p[0] = wfilter[p.x()-spec.x] * hfilter[p.y()-spec.y] * dfilter[p.z()-spec.z]; } else {
// DEPRECATED version bool ImageBufAlgo::add (ImageBuf &dst, const ImageBuf &A, const ImageBuf &B, int options) { // Sanity checks // dst must be distinct from A and B if ((const void *)&A == (const void *)&dst || (const void *)&B == (const void *)&dst) { dst.error ("destination image must be distinct from source"); return false; } // all three images must have the same number of channels if (A.spec().nchannels != B.spec().nchannels) { dst.error ("channel number mismatch: %d vs. %d", A.spec().nchannels, B.spec().nchannels); return false; } // If dst has not already been allocated, set it to the right size, // make it unconditinally float if (! dst.pixels_valid()) { ImageSpec dstspec = A.spec(); dstspec.set_format (TypeDesc::TypeFloat); dst.alloc (dstspec); } // Clear dst pixels if instructed to do so if (options & ADD_CLEAR_DST) { zero (dst); } ASSERT (A.spec().format == TypeDesc::FLOAT && B.spec().format == TypeDesc::FLOAT && dst.spec().format == TypeDesc::FLOAT); ImageBuf::ConstIterator<float,float> a (A); ImageBuf::ConstIterator<float,float> b (B); ImageBuf::Iterator<float> d (dst); int nchannels = A.nchannels(); // Loop over all pixels in A for ( ; a.valid(); ++a) { // Point the iterators for B and dst to the corresponding pixel if (options & ADD_RETAIN_WINDOWS) { b.pos (a.x(), a.y()); } else { // ADD_ALIGN_WINDOWS: make B line up with A b.pos (a.x()-A.xbegin()+B.xbegin(), a.y()-A.ybegin()+B.ybegin()); } d.pos (a.x(), b.y()); if (! b.valid() || ! d.valid()) continue; // Skip pixels that don't align // Add the pixel for (int c = 0; c < nchannels; ++c) d[c] = a[c] + b[c]; } return true; }
bool setNbChannels(ImageBuf &dst, const ImageBuf &src, int numChannels) { // Not intended to create 0-channel images. if (numChannels <= 0) return false; // If we dont have a single source channel, // hard to know how big to make the additional channels if (src.spec().nchannels == 0) return false; if (numChannels == src.spec().nchannels) { dst = src; return true; } // Update the ImageSpec // (should this be moved to a helper function in the imagespec.h? ImageSpec dst_spec = src.spec(); dst_spec.nchannels = numChannels; if (numChannels < src.spec().nchannels) { // Reduce the number of formats, and names, if needed if (static_cast<int>(dst_spec.channelformats.size()) == src.spec().nchannels) dst_spec.channelformats.resize(numChannels); if (static_cast<int>(dst_spec.channelnames.size()) == src.spec().nchannels) dst_spec.channelnames.resize(numChannels); if (dst_spec.alpha_channel < numChannels-1) { dst_spec.alpha_channel = -1; } if (dst_spec.z_channel < numChannels-1) { dst_spec.z_channel = -1; } } else { // Increase the number of formats, and names, if needed if (static_cast<int>(dst_spec.channelformats.size()) == src.spec().nchannels) { for (int c = dst_spec.channelnames.size(); c < numChannels; ++c) { dst_spec.channelformats.push_back(dst_spec.format); } } if (static_cast<int>(dst_spec.channelnames.size()) == src.spec().nchannels) { for (int c = dst_spec.channelnames.size(); c < numChannels; ++c) { dst_spec.channelnames.push_back (Strutil::format("channel%d", c)); } } } // Update the image (realloc with the new spec) dst.alloc (dst_spec); std::vector<float> pixel(numChannels, 0.0f); // Walk though the data window. I.e., the crop window in a small image // or the overscanned area in a large image. for (int k = dst_spec.z; k < dst_spec.z+dst_spec.depth; k++) { for (int j = dst_spec.y; j < dst_spec.y+dst_spec.height; j++) { for (int i = dst_spec.x; i < dst_spec.x+dst_spec.width; i++) { src.getpixel (i, j, k, &pixel[0], numChannels); dst.setpixel (i, j, k, &pixel[0], numChannels); } } } return true; }