Dealing with NaN pixels
Here's an approach to dealing with the occasional NaN pixel that can for example crop up when outputting through the ScanlineRender node.
So what does it look like and why is it bad? On the left, the pixel sampler has selected a single NaN pixel being output through the ScanlineRender node and you can see that the information being displayed for that pixel is "nan" in each channel. And on the right is with VectorBlur added:
As you can see any kind of filtering will turn up as nasty blocky artefacts (in this case blocky motion blur) and suddenly the effect of the NaN pixel is much more apparent. Luckily Nuke has some handy expressions for dealing with them in an elegant way:
1 |
isnan(r)
|
The Expression node shown on the right is using the expression isnan(r), adjusted accordingly for rgba channels, to show us the NaN pixels:
Now that the pixel is isolated, we need to do that in the context of the original image. By using a conditional statement we can say that if there is a NaN pixel then make it black, otherwise keep the existing pixel value for that channel:
1 |
isnan(r)?0:r
|
The conditional takes the form of if?then:else so in this case we are saying "if the pixel is a NaN then make it black, or else just leave it at its current value".
So now we get our image back and the problematic NaN is neutralised to a black value which is not going to blow out when filtered. But ideally we want to procedurally clone the colour from an adjacent pixel. We can use an expression to tell a pixel to grab its colour from a given xy coordinate offset like this:
1 |
r(x+1, y)
|
This will pull the pixel in the red channel from the current xy position but with an offset of +1 in x. Once that's wrapped into our existing conditional it looks like this:
1 |
isnan(r)?r(x+1,y):r
|
To abstract the expressions a bit for the sake of usability we can create x and y offset knobs (xo and yo) as shown in the image on the left and then modify the expressions to take advantage of that (as shown in the image on the right):
1 |
isnan(r)?r(x+xo,y+yo):r
|
Comments
I tried using your isNaN expression this weekend, but it didn't isolate the pixels that were nan. Instead it just gave me back a black image. My image wasn't clamped and the nan pixels were floating well above the 1 rgba pixel value, around 22 in fact. And of course I'm using Nuke 6.0v3. I've double checked my expressions and they're identical to the ones you used in your tutorial. So do you have any ideas? What am I missing here?
Thanks,
Doug
Also, if the pixels have a value of 22 then they aren't nan.
Thanks,
Doug
"DeepExpression1: Nothing named 'isnan' in 'isnan(r)0:r
Is deepexpression different in that it doesn't understand this function? How can i get this to work when still dealing in deep?
http://forums.thefoundry.co.uk/phpBB2/viewtopic.php?t=7057&sid=353b7e9a17d6ab4bd749955a56a89a28
I tend to avoid using recolors and deep merges if i can, and just use image mattes created from deep renders to cut my beauty. But just trying to find solutions for the recolor deepmerge route for others that use them.
thanks, again
I can recommend to use ColorLookup to isolate all bad pixels and create a matte + TransformMasked to offset , it is very flexible in how sharp you want cut, and it is very fast to calculate.
Off course for every case different solution, but this way worth to be considered too
Thank you!
But, does anyone have a solution for pixels with a "3.2e-06" type of value ? Thanks !
That method works great with pixels with RGB with NAN...
But what if I have pixels where the NAN value is only in one of the values randomly?.
I mean, one pixel with 0.9, 0.8, nan, and another pixel with nan, 0.5, 0.6...
I did run into the funny situation where I had two nan pixels side by side, so the expression just copied the nan value over to the left and I still ended up with one nan pixel (down from two). To fix it I simply duplicated the node so it would run twice - FYI if anyone else runs into that...
r=4.3e-06
g=7.5e-06
b=9.4e-06
e-06 is the amount of zeros after the comma
according to the documentation (https://www.tcl.tk/man/tcl/TclCmd/expr.htm#M21)
x ? y : z basically means : if confition(x), then do (y), else do (z)
for instance :
isnan(r) ? (r(x+1,y) + r(x-1,y))/2 : r
means :
for each pixel of the picture :
isnan(r) -> checks if the pixel has has no valid value
(r(x+1,y) + r(x-1,y))/2 - > gives the average value of the pixel on the left and and the right of the current pixel
r -> the current red value of the pixel
in a nutshell :
if r is not a number, then get the average value of the pixels around, else keep the current value.
You can then replace the condition with anything you need, for instance :
r < 0.0001 ? (do something here) : r
a != 0 ? 1 : 0
the possibilities are endless :)
First off, thanks for this. I first came across this thread years ago, used it, and then never actually saved the tool. Today I came back to it and did make this an accessible tool out of the box that wouldn't need to be made from scratch each time.
@Mehul - This is a custom tab you have to make by right clicking the tabs and using "Manage User Knobs...". This doesn't exist in a native expression node. For you, and anyone else having issues or looking to utilize this approach to NaN pixels, just download this .nk script and import into your script and you'll have a fully functional custom Expression node to accomplish this with the additional attributes to input the offset values outside of the expression. I hope this helps some of you.
https://drive.google.com/file/d/1aDBVGnZsqNiuwad6yLlaJQ-Dr4NFE2x6/view?usp=sharing
RSS feed for comments to this post