[Bf-blender-cvs] [45fc801] master: Fix for interpolation errors on lower-left borders in compositor image inputs.

Lukas Tönne noreply at git.blender.org
Wed Dec 4 12:13:56 CET 2013


Commit: 45fc80153a40fb01db6b1e25b4ab575a06a331b8
Author: Lukas Tönne
Date:   Wed Dec 4 11:56:36 2013 +0100
http://developer.blender.org/rB45fc80153a40fb01db6b1e25b4ab575a06a331b8

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.

===================================================================

M	source/blender/blenlib/intern/math_interp.c
M	source/blender/compositor/operations/COM_ImageOperation.cpp
M	source/blender/compositor/operations/COM_MovieClipOperation.cpp
M	source/blender/compositor/operations/COM_MultilayerImageOperation.cpp
M	source/blender/compositor/operations/COM_RenderLayersProg.cpp
M	source/blender/imbuf/intern/imageprocess.c

===================================================================

diff --git a/source/blender/blenlib/intern/math_interp.c b/source/blender/blenlib/intern/math_interp.c
index d1acd45..35a763c 100644
--- a/source/blender/blenlib/intern/math_interp.c
+++ b/source/blender/blenlib/intern/math_interp.c
@@ -105,6 +105,10 @@ BLI_INLINE void bicubic_interpolation(const unsigned char *byte_buffer, const fl
 
 	/* sample area entirely outside image? */
 	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;
 	}
 
@@ -263,15 +267,16 @@ BLI_INLINE void bilinear_interpolation(const unsigned char *byte_buffer, const f
 	y1 = (int)floor(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) {
 		const float *row1, *row2, *row3, *row4;
 		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 */
 		if (x1 < 0 || y1 < 0) row1 = empty;
 		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;
 		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 */
 		if (x1 < 0 || y1 < 0) row1 = empty;
 		else row1 = byte_buffer + width * y1 * components + components * x1;
diff --git a/source/blender/compositor/operations/COM_ImageOperation.cpp b/source/blender/compositor/operations/COM_ImageOperation.cpp
index adc325d..353d6e8 100644
--- a/source/blender/compositor/operations/COM_ImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_ImageOperation.cpp
@@ -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)
 {
-	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);
 	}
 	else {
@@ -160,7 +160,7 @@ void ImageAlphaOperation::executePixelSampled(float output[4], float x, float y,
 {
 	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;
 	}
 	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)
 {
-	if (this->m_depthBuffer == NULL || x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight() ) {
+	if (this->m_depthBuffer == NULL) {
 		output[0] = 0.0f;
 	}
 	else {
-		int offset = y * this->m_width + x;
-		output[0] = this->m_depthBuffer[offset];
+		if (x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight())
+			output[0] = 0.0f;
+		else {
+			int offset = y * this->m_width + x;
+			output[0] = this->m_depthBuffer[offset];
+		}
 	}
 }
diff --git a/source/blender/compositor/operations/COM_MovieClipOperation.cpp b/source/blender/compositor/operations/COM_MovieClipOperation.cpp
index 5b75113..dcb5ca0 100644
--- a/source/blender/compositor/operations/COM_MovieClipOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieClipOperation.cpp
@@ -90,7 +90,7 @@ void MovieClipBaseOperation::executePixelSampled(float output[4], float x, float
 {
 	ImBuf *ibuf = this->m_movieClipBuffer;
 
-	if (ibuf == NULL || x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight() ) {
+	if (ibuf == NULL) {
 		zero_v4(output);
 	}
 	else if (ibuf->rect == NULL && ibuf->rect_float == NULL) {
diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp
index 84c1fdf..ffa319f 100644
--- a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp
@@ -44,9 +44,7 @@ ImBuf *MultilayerBaseOperation::getImBuf()
 
 void MultilayerColorOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
 {
-	int yi = y;
-	int xi = x;
-	if (this->m_imageFloatBuffer == NULL || xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight() ) {
+	if (this->m_imageFloatBuffer == NULL) {
 		zero_v4(output);
 	}
 	else {
@@ -64,34 +62,48 @@ void MultilayerColorOperation::executePixelSampled(float output[4], float x, flo
 			}
 		}
 		else {
-			int offset = (yi * this->getWidth() + xi) * 3;
-			copy_v3_v3(output, &this->m_imageFloatBuffer[offset]);
+			int yi = y;
+			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)
 {
-	int yi = y;
-	int xi = x;
-	if (this->m_imageFloatBuffer == NULL || xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight() ) {
+	if (this->m_imageFloatBuffer == NULL) {
 		output[0] = 0.0f;
 	}
 	else {
-		float result = this->m_imageFloatBuffer[yi * this->getWidth() + xi];
-		output[0] = result;
+		int yi = y;
+		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)
 {
-	int yi = y;
-	int xi = x;
-	if (this->m_imageFloatBuffer == NULL || xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight() ) {
+	if (this->m_imageFloatBuffer == NULL) {
 		output[0] = 0.0f;
 	}
 	else {
-		int offset = (yi * this->getWidth() + xi) * 3;
-		copy_v3_v3(output, &this->m_imageFloatBuffer[offset]);
+		int yi = y;
+		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]);
+		}
 	}
 }
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
index 2c2a4c6..f72af27 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
@@ -75,13 +75,15 @@ void RenderLayersBaseProg::initExecution()
 void RenderLayersBaseProg::doInterpolation(float output[4], float x, float y, PixelSampler sampler)
 {
 	unsigned int offset;
-	int ix, iy;
 	int width = this->getWidth(), height = this->getHeight();
 
 	switch (sampler) {
-		case COM_PS_NEAREST:
-			ix = x;
-			iy = y;
+		case COM_PS_NEAREST: {
+			int ix = x;
+			int iy = y;
+			if (ix < 0 || iy < 0 || ix >= width || iy >= height)
+				break;
+
 			offset = (iy * width + ix) * this->m_elementsize;
 
 			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]);
 			else
 				copy_v4_v4(output, &this->m_inputBuffer[offset]);
-
 			break;
+		}
 
 		case COM_PS_BILINEAR:
 			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;
 #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);
 	}
 	else {
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index bde17e1..71d5f51 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -232,6 +232,10 @@ void nearest_interpolation_color(struct ImBuf *in, unsigned char outI[4], float
 
 	/* sample area entirely outside image? */
 	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;
 	}




More information about the Bf-blender-cvs mailing list