void Convolve(CImageOf<T> src, CImageOf<T>& dst, CFloatImage kernel, float scale, float offset) { // Determine the shape of the kernel and row buffer CShape kShape = kernel.Shape(); CShape sShape = src.Shape(); CShape bShape(sShape.width + kShape.width, kShape.height, sShape.nBands); int bWidth = bShape.width * bShape.nBands; // Allocate the result, if necessary, and the row buffer dst.ReAllocate(sShape, false); CFloatImage buffer(bShape); if (sShape.width * sShape.height * sShape.nBands == 0) return; CFloatImage output(CShape(sShape.width, 1, sShape.nBands)); // Fill up the row buffer initially for (int k = 0; k < kShape.height; k++) FillRowBuffer(&buffer.Pixel(0, k, 0), src, kernel, k, bWidth); // Determine if clipping is required // (we assume up-conversion to float never requires clipping, i.e., // floats have the highest dynamic range) T minVal = dst.MinVal(); T maxVal = dst.MaxVal(); if (minVal <= buffer.MinVal() && maxVal >= buffer.MaxVal()) minVal = maxVal = 0; // Process each row for (int y = 0; y < sShape.height; y++) { // Do the convolution ConvolveRow2D(buffer, kernel, &output.Pixel(0, 0, 0), sShape.width); // Scale, offset, and type convert ScaleAndOffsetLine(&output.Pixel(0, 0, 0), &dst.Pixel(0, y, 0), sShape.width * sShape.nBands, scale, offset, minVal, maxVal); // Shift up the row buffer and fill the last line if (y < sShape.height-1) { int k; for (k = 0; k < kShape.height-1; k++) memcpy(&buffer.Pixel(0, k, 0), &buffer.Pixel(0, k+1, 0), bWidth * sizeof(float)); FillRowBuffer(&buffer.Pixel(0, k, 0), src, kernel, y+k+1, bWidth); } } }
extern void InverseWarp(CImageOf<T>& src, CImageOf<T>& dst, CFloatImage& disp, float d_scale, float disp_gap, int order) { // Warps src into dst using disparities disp. // Each disparity is scaled by d_scale // Note that "empty" pixels are left at their original value CShape sh = src.Shape(); int w = sh.width, h = sh.height, n_bands = sh.nBands; int n = w * n_bands; if (! sh.SameIgnoringNBands(disp.Shape())) throw CError("InverseWarp: disparity image has wrong size"); if (sh != dst.Shape()) dst.ReAllocate(sh); // Optional forward warped depth map if checking for visibility CFloatImage fwd, fwd_tmp; if (disp_gap > 0.0f) { ScaleAndOffset(disp, fwd_tmp, d_scale, 0.0f); fwd.ReAllocate(disp.Shape()); fwd.FillPixels(-9999.0f); ForwardWarp(fwd_tmp, fwd, disp, d_scale, true, disp_gap); } // Allocate line buffers std::vector<float> src_buf, dst_buf, dsp_buf; src_buf.resize(n); dst_buf.resize(n); dsp_buf.resize(n); CFloatImage fimg; // dummy, used for MinVal(), MaxVal() for (int y = 0; y < h; y++) { // Set up (copy) the line buffers ScaleAndOffsetLine(&src .Pixel(0, y, 0), &src_buf[0], n, 1.0f, 0.0f, fimg.MinVal(), fimg.MaxVal()); ScaleAndOffsetLine(&disp.Pixel(0, y, 0), &dsp_buf[0], w, d_scale, 0.0f, 0.0f, 0.0f); ScaleAndOffsetLine(&dst .Pixel(0, y, 0), &dst_buf[0], n, 1.0f, 0.0f, fimg.MinVal(), fimg.MaxVal()); // Forward warp the depth map float *fwd_buf = (disp_gap > 0.0f) ? &fwd.Pixel(0, y, 0) : 0; // Process (warp) the line InverseWarpLine(&src_buf[0], &dst_buf[0], &dsp_buf[0], w, n_bands, order, fwd_buf, disp_gap); // Convert back to native type T minVal = dst.MinVal(); T maxVal = dst.MaxVal(); float offset = (typeid(T) == typeid(float)) ? 0.0f : 0.5; // rounding if (minVal <= fimg.MinVal() && maxVal >= fimg.MaxVal()) minVal = maxVal = 0; ScaleAndOffsetLine(&dst_buf[0], &dst.Pixel(0, y, 0), n, 1.0f, offset, minVal, maxVal); } }