Fix for interpolation errors on lower-left borders in compositor image
inputs. http://wiki.blender.org/uploads/4/4c/Compo_image_interpolation_borders.png Problem is that all image buffer reader nodes (RenderLayer, Image, MovieClip) were clipping pixel coordinates to 0..N range (N being width or height respectively). Bilinear interpolation works ok then on the upper-right borders (x, N) and (N, y), since the last (N-1) pixel fades out to N (background). But the lower-left (x, 0) and (0, y) borders are not correctly interpolated because the nodes cut off the negative pixels before the interpolation function can calculate their value. To fix this, the interpolation functions are now entirely responsible for handling "out of range" cases, i.e. setting (0,0,0,0) results for invalid pixels, while also handling interpolation for borders. Callers should not do pixel range checks themselves, which also makes the code simpler. Should not have any real performance penalty, the interpolation functions do this check anyway, so is probably even slightly faster.
This commit is contained in:
@@ -105,6 +105,10 @@ BLI_INLINE void bicubic_interpolation(const unsigned char *byte_buffer, const fl
|
|||||||
|
|
||||||
/* sample area entirely outside image? */
|
/* sample area entirely outside image? */
|
||||||
if (ceil(u) < 0 || floor(u) > width - 1 || ceil(v) < 0 || floor(v) > height - 1) {
|
if (ceil(u) < 0 || floor(u) > width - 1 || ceil(v) < 0 || floor(v) > height - 1) {
|
||||||
|
if (float_output)
|
||||||
|
float_output[0] = float_output[1] = float_output[2] = float_output[3] = 0.0f;
|
||||||
|
if (byte_output)
|
||||||
|
byte_output[0] = byte_output[1] = byte_output[2] = byte_output[3] = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,15 +267,16 @@ BLI_INLINE void bilinear_interpolation(const unsigned char *byte_buffer, const f
|
|||||||
y1 = (int)floor(v);
|
y1 = (int)floor(v);
|
||||||
y2 = (int)ceil(v);
|
y2 = (int)ceil(v);
|
||||||
|
|
||||||
/* sample area entirely outside image? */
|
|
||||||
if (x2 < 0 || x1 > width - 1 || y2 < 0 || y1 > height - 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (float_output) {
|
if (float_output) {
|
||||||
const float *row1, *row2, *row3, *row4;
|
const float *row1, *row2, *row3, *row4;
|
||||||
float empty[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
float empty[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||||
|
|
||||||
|
/* sample area entirely outside image? */
|
||||||
|
if (x2 < 0 || x1 > width - 1 || y2 < 0 || y1 > height - 1) {
|
||||||
|
float_output[0] = float_output[1] = float_output[2] = float_output[3] = 0.0f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* sample including outside of edges of image */
|
/* sample including outside of edges of image */
|
||||||
if (x1 < 0 || y1 < 0) row1 = empty;
|
if (x1 < 0 || y1 < 0) row1 = empty;
|
||||||
else row1 = float_buffer + width * y1 * components + components * x1;
|
else row1 = float_buffer + width * y1 * components + components * x1;
|
||||||
@@ -308,6 +313,12 @@ BLI_INLINE void bilinear_interpolation(const unsigned char *byte_buffer, const f
|
|||||||
const unsigned char *row1, *row2, *row3, *row4;
|
const unsigned char *row1, *row2, *row3, *row4;
|
||||||
unsigned char empty[4] = {0, 0, 0, 0};
|
unsigned char empty[4] = {0, 0, 0, 0};
|
||||||
|
|
||||||
|
/* sample area entirely outside image? */
|
||||||
|
if (x2 < 0 || x1 > width - 1 || y2 < 0 || y1 > height - 1) {
|
||||||
|
byte_output[0] = byte_output[1] = byte_output[2] = byte_output[3] = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* sample including outside of edges of image */
|
/* sample including outside of edges of image */
|
||||||
if (x1 < 0 || y1 < 0) row1 = empty;
|
if (x1 < 0 || y1 < 0) row1 = empty;
|
||||||
else row1 = byte_buffer + width * y1 * components + components * x1;
|
else row1 = byte_buffer + width * y1 * components + components * x1;
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ static void sampleImageAtLocation(ImBuf *ibuf, float x, float y, PixelSampler sa
|
|||||||
|
|
||||||
void ImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
|
void ImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
|
||||||
{
|
{
|
||||||
if ((this->m_imageFloatBuffer == NULL && this->m_imageByteBuffer == NULL) || x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight() ) {
|
if (this->m_imageFloatBuffer == NULL && this->m_imageByteBuffer == NULL) {
|
||||||
zero_v4(output);
|
zero_v4(output);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -160,7 +160,7 @@ void ImageAlphaOperation::executePixelSampled(float output[4], float x, float y,
|
|||||||
{
|
{
|
||||||
float tempcolor[4];
|
float tempcolor[4];
|
||||||
|
|
||||||
if ((this->m_imageFloatBuffer == NULL && this->m_imageByteBuffer == NULL) || x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight() ) {
|
if (this->m_imageFloatBuffer == NULL && this->m_imageByteBuffer == NULL) {
|
||||||
output[0] = 0.0f;
|
output[0] = 0.0f;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -172,11 +172,15 @@ void ImageAlphaOperation::executePixelSampled(float output[4], float x, float y,
|
|||||||
|
|
||||||
void ImageDepthOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
|
void ImageDepthOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
|
||||||
{
|
{
|
||||||
if (this->m_depthBuffer == NULL || x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight() ) {
|
if (this->m_depthBuffer == NULL) {
|
||||||
output[0] = 0.0f;
|
output[0] = 0.0f;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int offset = y * this->m_width + x;
|
if (x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight())
|
||||||
output[0] = this->m_depthBuffer[offset];
|
output[0] = 0.0f;
|
||||||
|
else {
|
||||||
|
int offset = y * this->m_width + x;
|
||||||
|
output[0] = this->m_depthBuffer[offset];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ void MovieClipBaseOperation::executePixelSampled(float output[4], float x, float
|
|||||||
{
|
{
|
||||||
ImBuf *ibuf = this->m_movieClipBuffer;
|
ImBuf *ibuf = this->m_movieClipBuffer;
|
||||||
|
|
||||||
if (ibuf == NULL || x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight() ) {
|
if (ibuf == NULL) {
|
||||||
zero_v4(output);
|
zero_v4(output);
|
||||||
}
|
}
|
||||||
else if (ibuf->rect == NULL && ibuf->rect_float == NULL) {
|
else if (ibuf->rect == NULL && ibuf->rect_float == NULL) {
|
||||||
|
|||||||
@@ -44,9 +44,7 @@ ImBuf *MultilayerBaseOperation::getImBuf()
|
|||||||
|
|
||||||
void MultilayerColorOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
|
void MultilayerColorOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
|
||||||
{
|
{
|
||||||
int yi = y;
|
if (this->m_imageFloatBuffer == NULL) {
|
||||||
int xi = x;
|
|
||||||
if (this->m_imageFloatBuffer == NULL || xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight() ) {
|
|
||||||
zero_v4(output);
|
zero_v4(output);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -64,34 +62,48 @@ void MultilayerColorOperation::executePixelSampled(float output[4], float x, flo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int offset = (yi * this->getWidth() + xi) * 3;
|
int yi = y;
|
||||||
copy_v3_v3(output, &this->m_imageFloatBuffer[offset]);
|
int xi = x;
|
||||||
|
if (xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight())
|
||||||
|
zero_v4(output);
|
||||||
|
else {
|
||||||
|
int offset = (yi * this->getWidth() + xi) * 3;
|
||||||
|
copy_v3_v3(output, &this->m_imageFloatBuffer[offset]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MultilayerValueOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
|
void MultilayerValueOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
|
||||||
{
|
{
|
||||||
int yi = y;
|
if (this->m_imageFloatBuffer == NULL) {
|
||||||
int xi = x;
|
|
||||||
if (this->m_imageFloatBuffer == NULL || xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight() ) {
|
|
||||||
output[0] = 0.0f;
|
output[0] = 0.0f;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
float result = this->m_imageFloatBuffer[yi * this->getWidth() + xi];
|
int yi = y;
|
||||||
output[0] = result;
|
int xi = x;
|
||||||
|
if (xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight())
|
||||||
|
output[0] = 0.0f;
|
||||||
|
else {
|
||||||
|
float result = this->m_imageFloatBuffer[yi * this->getWidth() + xi];
|
||||||
|
output[0] = result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MultilayerVectorOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
|
void MultilayerVectorOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
|
||||||
{
|
{
|
||||||
int yi = y;
|
if (this->m_imageFloatBuffer == NULL) {
|
||||||
int xi = x;
|
|
||||||
if (this->m_imageFloatBuffer == NULL || xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight() ) {
|
|
||||||
output[0] = 0.0f;
|
output[0] = 0.0f;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int offset = (yi * this->getWidth() + xi) * 3;
|
int yi = y;
|
||||||
copy_v3_v3(output, &this->m_imageFloatBuffer[offset]);
|
int xi = x;
|
||||||
|
if (xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight())
|
||||||
|
output[0] = 0.0f;
|
||||||
|
else {
|
||||||
|
int offset = (yi * this->getWidth() + xi) * 3;
|
||||||
|
copy_v3_v3(output, &this->m_imageFloatBuffer[offset]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,13 +75,15 @@ void RenderLayersBaseProg::initExecution()
|
|||||||
void RenderLayersBaseProg::doInterpolation(float output[4], float x, float y, PixelSampler sampler)
|
void RenderLayersBaseProg::doInterpolation(float output[4], float x, float y, PixelSampler sampler)
|
||||||
{
|
{
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
int ix, iy;
|
|
||||||
int width = this->getWidth(), height = this->getHeight();
|
int width = this->getWidth(), height = this->getHeight();
|
||||||
|
|
||||||
switch (sampler) {
|
switch (sampler) {
|
||||||
case COM_PS_NEAREST:
|
case COM_PS_NEAREST: {
|
||||||
ix = x;
|
int ix = x;
|
||||||
iy = y;
|
int iy = y;
|
||||||
|
if (ix < 0 || iy < 0 || ix >= width || iy >= height)
|
||||||
|
break;
|
||||||
|
|
||||||
offset = (iy * width + ix) * this->m_elementsize;
|
offset = (iy * width + ix) * this->m_elementsize;
|
||||||
|
|
||||||
if (this->m_elementsize == 1)
|
if (this->m_elementsize == 1)
|
||||||
@@ -90,8 +92,8 @@ void RenderLayersBaseProg::doInterpolation(float output[4], float x, float y, Pi
|
|||||||
copy_v3_v3(output, &this->m_inputBuffer[offset]);
|
copy_v3_v3(output, &this->m_inputBuffer[offset]);
|
||||||
else
|
else
|
||||||
copy_v4_v4(output, &this->m_inputBuffer[offset]);
|
copy_v4_v4(output, &this->m_inputBuffer[offset]);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case COM_PS_BILINEAR:
|
case COM_PS_BILINEAR:
|
||||||
BLI_bilinear_interpolation_fl(this->m_inputBuffer, output, width, height, this->m_elementsize, x, y);
|
BLI_bilinear_interpolation_fl(this->m_inputBuffer, output, width, height, this->m_elementsize, x, y);
|
||||||
@@ -137,7 +139,7 @@ void RenderLayersBaseProg::executePixelSampled(float output[4], float x, float y
|
|||||||
int iy = y;
|
int iy = y;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (this->m_inputBuffer == NULL || ix < 0 || iy < 0 || ix >= (int)this->getWidth() || iy >= (int)this->getHeight() ) {
|
if (this->m_inputBuffer == NULL) {
|
||||||
zero_v4(output);
|
zero_v4(output);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -232,6 +232,10 @@ void nearest_interpolation_color(struct ImBuf *in, unsigned char outI[4], float
|
|||||||
|
|
||||||
/* sample area entirely outside image? */
|
/* sample area entirely outside image? */
|
||||||
if (x1 < 0 || x1 > in->x - 1 || y1 < 0 || y1 > in->y - 1) {
|
if (x1 < 0 || x1 > in->x - 1 || y1 < 0 || y1 > in->y - 1) {
|
||||||
|
if (outI)
|
||||||
|
outI[0] = outI[1] = outI[2] = outI[3] = 0;
|
||||||
|
if (outF)
|
||||||
|
outF[0] = outF[1] = outF[2] = outF[3] = 0.0f;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user