Cycles: tweak outlier detection, preparing for animation denoising.

Ref D3889.
This commit is contained in:
2019-02-06 14:42:32 +01:00
committed by Brecht Van Lommel
parent 405cacd4cd
commit c183ac73dc
+34 -9
View File
@@ -140,6 +140,7 @@ ccl_device void kernel_filter_detect_outliers(int x, int y,
int n = 0;
float values[25];
float pixel_variance, max_variance = 0.0f;
for(int y1 = max(y-2, rect.y); y1 < min(y+3, rect.w); y1++) {
for(int x1 = max(x-2, rect.x); x1 < min(x+3, rect.z); x1++) {
int idx = (y1-rect.y)*buffer_w + (x1-rect.x);
@@ -159,15 +160,31 @@ ccl_device void kernel_filter_detect_outliers(int x, int y,
/* Insert L. */
values[i] = L;
n++;
float3 pixel_var = make_float3(variance[idx], variance[idx+pass_stride], variance[idx+2*pass_stride]);
float var = average(pixel_var);
if((x1 == x) && (y1 == y)) {
pixel_variance = (pixel_var.x < 0.0f || pixel_var.y < 0.0f || pixel_var.z < 0.0f)? -1.0f : var;
}
else {
max_variance = max(max_variance, var);
}
}
}
max_variance += 1e-4f;
int idx = (y-rect.y)*buffer_w + (x-rect.x);
float3 color = make_float3(image[idx], image[idx+pass_stride], image[idx+2*pass_stride]);
color = max(color, make_float3(0.0f, 0.0f, 0.0f));
float L = average(color);
float ref = 2.0f*values[(int)(n*0.75f)];
/* Slightly offset values to avoid false positives in (almost) black areas. */
max_variance += 1e-5f;
ref -= 1e-5f;
if(L > ref) {
/* The pixel appears to be an outlier.
* However, it may just be a legitimate highlight. Therefore, it is checked how likely it is that the pixel
@@ -175,16 +192,24 @@ ccl_device void kernel_filter_detect_outliers(int x, int y,
* If the reference is within the 3-sigma interval, the pixel is assumed to be a statistical outlier.
* Otherwise, it is very unlikely that the pixel should be darker, which indicates a legitimate highlight.
*/
float stddev = sqrtf(average(make_float3(variance[idx], variance[idx+pass_stride], variance[idx+2*pass_stride])));
if(L - 3*stddev < ref) {
/* The pixel is an outlier, so negate the depth value to mark it as one.
* Also, scale its brightness down to the outlier threshold to avoid trouble with the NLM weights. */
if(pixel_variance < 0.0f || pixel_variance > 9.0f * max_variance) {
depth[idx] = -depth[idx];
float fac = ref/L;
color *= fac;
variance[idx ] *= fac*fac;
variance[idx + pass_stride] *= fac*fac;
variance[idx+2*pass_stride] *= fac*fac;
color *= ref/L;
variance[idx] = variance[idx + pass_stride] = variance[idx + 2*pass_stride] = max_variance;
}
else {
float stddev = sqrtf(pixel_variance);
if(L - 3*stddev < ref) {
/* The pixel is an outlier, so negate the depth value to mark it as one.
* Also, scale its brightness down to the outlier threshold to avoid trouble with the NLM weights. */
depth[idx] = -depth[idx];
float fac = ref/L;
color *= fac;
variance[idx ] *= fac*fac;
variance[idx + pass_stride] *= fac*fac;
variance[idx+2*pass_stride] *= fac*fac;
}
}
}
out[idx ] = color.x;