This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/compositor/intern/COM_SocketReader.h
Lukas Tönne 67134a7bf6 Fix for EWA (elliptical weighted average) sampling in the compositor.
EWA sampling is designed for downsampling images, i.e. scaling down the size of
input image pixels, which happens regularly in compositing. While the standard
sampling methods (linear, cubic) work reasonably well for linear
transformations, they don't yield good results in non-linear cases like
perspective projection or arbitrary displacement. EWA sampling is comparable to
mipmapping, but avoids problems with discontinuities.

To work correctly the EWA algorithm needs partial derivatives of the mapping
functions which convert output pixel coordinates back into the input image
space (2x2 Jacobian matrix). With these derivatives the EWA algorithm
projects ellipses into the input space and accumulates colors over their
area. This calculation was not done correctly in the compositor, only the
derivatives du/dx and dv/dy were calculation, basically this means it only
worked for non-rotated input images.

The patch introduces full derivative calculations du/dx, du/dy, dv/dx, dv/dy for
the 3 nodes which use EWA sampling currently: PlaneTrackWarp, MapUV and
Displace. In addition the calculation of ellipsis area and axis-aligned
bounding boxes has been fixed.

For the MapUV and Displace nodes the derivatives have to be estimated by
evaluating the UV/displacement inputs with 1-pixel offsets, which can still have
problems on discontinuities and sub-pixel variations. These potential problems
can only be alleviated by more radical design changes in the compositor
functions, which are out of scope for now. Basically the values passed to the
UV/Displacement inputs would need to be associated with their 1st order
derivatives, which requires a general approach to derivatives in all nodes.
2013-12-04 16:05:56 +01:00

120 lines
3.9 KiB
C++

/*
* Copyright 2011, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor:
* Jeroen Bakker
* Monique Dewanchand
*/
#ifndef _COM_SocketReader_h
#define _COM_SocketReader_h
#include "BLI_rect.h"
#include "COM_defines.h"
#ifdef WITH_CXX_GUARDEDALLOC
#include "MEM_guardedalloc.h"
#endif
typedef enum PixelSampler {
COM_PS_NEAREST = 0,
COM_PS_BILINEAR = 1,
COM_PS_BICUBIC = 2
} PixelSampler;
class MemoryBuffer;
/**
* @brief Helper class for reading socket data.
* Only use this class for dispatching (un-ary and n-ary) executions.
* @ingroup Execution
*/
class SocketReader {
private:
protected:
/**
* @brief Holds the width of the output of this operation.
*/
unsigned int m_width;
/**
* @brief Holds the height of the output of this operation.
*/
unsigned int m_height;
/**
* @brief calculate a single pixel
* @note this method is called for non-complex
* @param result is a float[4] array to store the result
* @param x the x-coordinate of the pixel to calculate in image space
* @param y the y-coordinate of the pixel to calculate in image space
* @param inputBuffers chunks that can be read by their ReadBufferOperation.
*/
virtual void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) {}
/**
* @brief calculate a single pixel
* @note this method is called for complex
* @param result is a float[4] array to store the result
* @param x the x-coordinate of the pixel to calculate in image space
* @param y the y-coordinate of the pixel to calculate in image space
* @param inputBuffers chunks that can be read by their ReadBufferOperation.
* @param chunkData chunk specific data a during execution time.
*/
virtual void executePixel(float output[4], int x, int y, void *chunkData) {
executePixelSampled(output, x, y, COM_PS_NEAREST);
}
/**
* @brief calculate a single pixel using an EWA filter
* @note this method is called for complex
* @param result is a float[4] array to store the result
* @param x the x-coordinate of the pixel to calculate in image space
* @param y the y-coordinate of the pixel to calculate in image space
* @param dx
* @param dy
* @param inputBuffers chunks that can be read by their ReadBufferOperation.
*/
virtual void executePixelFiltered(float output[4], float x, float y, float dx[2], float dy[2], PixelSampler sampler) {}
public:
inline void readSampled(float result[4], float x, float y, PixelSampler sampler) {
executePixelSampled(result, x, y, sampler);
}
inline void read(float result[4], int x, int y, void *chunkData) {
executePixel(result, x, y, chunkData);
}
inline void readFiltered(float result[4], float x, float y, float dx[2], float dy[2], PixelSampler sampler) {
executePixelFiltered(result, x, y, dx, dy, sampler);
}
virtual void *initializeTileData(rcti *rect) { return 0; }
virtual void deinitializeTileData(rcti *rect, void *data) {}
virtual ~SocketReader() {}
virtual MemoryBuffer *getInputMemoryBuffer(MemoryBuffer **memoryBuffers) { return 0; }
inline const unsigned int getWidth() const { return this->m_width; }
inline const unsigned int getHeight() const { return this->m_height; }
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:SocketReader")
#endif
};
#endif /* _COM_SocketReader_h */