Cycles: Mark pixels with negative values as outliers

If a pixel has negative components, something already went wrong, so the best option is to just ignore it.

Should be good for 2.79.
This commit is contained in:
Lukas Stockner 2017-08-24 23:15:30 +02:00 committed by Bastien Montagne
parent fc26280bcb
commit 6f4a0c23cc
1 changed files with 47 additions and 40 deletions

View File

@ -120,49 +120,56 @@ ccl_device void kernel_filter_detect_outliers(int x, int y,
{
int buffer_w = align_up(rect.z - rect.x, 4);
int n = 0;
float values[25];
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);
float L = average(make_float3(image[idx], image[idx+pass_stride], image[idx+2*pass_stride]));
/* Find the position of L. */
int i;
for(i = 0; i < n; i++) {
if(values[i] > L) break;
}
/* Make space for L by shifting all following values to the right. */
for(int j = n; j > i; j--) {
values[j] = values[j-1];
}
/* Insert L. */
values[i] = L;
n++;
}
}
int idx = (y-rect.y)*buffer_w + (x-rect.x);
float L = average(make_float3(image[idx], image[idx+pass_stride], image[idx+2*pass_stride]));
float3 color = make_float3(image[idx], image[idx+pass_stride], image[idx+2*pass_stride]);
float ref = 2.0f*values[(int)(n*0.75f)];
float fac = 1.0f;
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
* should actually be at the reference value:
* 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. */
depth[idx] = -depth[idx];
fac = ref/L;
variance[idx ] *= fac*fac;
variance[idx + pass_stride] *= fac*fac;
variance[idx+2*pass_stride] *= fac*fac;
if(color.x < 0.0f || color.y < 0.0f || color.z < 0.0f) {
depth[idx] = -depth[idx];
fac = 0.0f;
}
else {
float L = average(color);
int n = 0;
float values[25];
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);
float L = average(make_float3(image[idx], image[idx+pass_stride], image[idx+2*pass_stride]));
/* Find the position of L. */
int i;
for(i = 0; i < n; i++) {
if(values[i] > L) break;
}
/* Make space for L by shifting all following values to the right. */
for(int j = n; j > i; j--) {
values[j] = values[j-1];
}
/* Insert L. */
values[i] = L;
n++;
}
}
float ref = 2.0f*values[(int)(n*0.75f)];
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
* should actually be at the reference value:
* 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. */
depth[idx] = -depth[idx];
fac = ref/L;
variance[idx ] *= fac*fac;
variance[idx + pass_stride] *= fac*fac;
variance[idx+2*pass_stride] *= fac*fac;
}
}
}
out[idx ] = fac*image[idx];