Joe Maller: FXScript Reference: Building Joe's Radial DesaturateHow I used FXScript to build my Radial Desaturate filter for Final Cut Pro. 

Visit the New FXScript Reference and Joe's Filters sites. These pages will be phased out soon and may already be out of date. This page describes the FXScript concepts behind Joe's Radial Desaturate. If you're looking for the page about how to use the filter, click here. OverviewJoe's Radial Desaturate recreates an effect I've been creating in Photoshop with the channel mixer. A mix of the three color channels are combined to create a grayscale image specific to a given color. The effect is very similar to using a colored glass filter when shooting black and white film, different colors result in grayscale tonal ranges which might otherwise be missed. After Building Joe's RGB Desaturate, I realized that each channel could be increased relative to oneanother to create a grayscale image from any point around the hue wheel. When I started this, I had only the slightest understanding of Matrix Math and a hunch that the math would be simple. The hunch was right, but it took a long time to figure it all out. How it worksThe beginning of the script is standard, a definition, group and three inputs:
The Saturation slider indicates a range from complete color replacement to complete desaturation.
The angle selector value is transformed into three values with the foloowing equasion Because each color will return a value between 1 and 0, and will overlap one other color, depending on the color, the maximum combined value for each color is 2. A value of two would indicate a secondary color, Cyan, Magenta or Yellow. Values of 1 must be a primary color, Red Green or Blue. Playing around with Joe's 3x3 Matrix Fun filter shows that for an image's luminance to be preserved the total values must not exceed one for any of the three colors. The Color WheelWhile working out how the angle selector would work, I realised something that seems obvious to me now (and should have been obvious to begin with. Each of the three color primaries are each full intensity for 120° of the color wheel. Each then graduates off for another 60° on either side of that. I was initially mistaken in thinking the primaries faded immediately out from their pure state. + + = In looking at the color wheel dissected, it's very clear that each set of neighboring primary colors finish their gradiations at the full intensity point of whichever color is left over. Adjusting the desaturation about halfway and then subtly shifting the hue wheel can produce interesting tint effects Translating AnglesNow that I understood how the color wheel worked from a mathematical point of view, the script needed to convert a single angle value into three distinct color values. This was not as fast as I'd hoped. Early in the script, the value of r (the hue angle input selector) is adjusted: r = (r + 360 )mod 360 This is to compensate for the allowing the input to move 360° in both directions. Incidentally, this is also when I learned about the concept of Modulo.
if r < 180; gangle = (abs(r 120)60)/60 bangle = (abs(r  240)60)/60 This was the second filter I wrote, and this code is somewhat embarrassing. There are several errors here but unfortunately this page was not completed until after I released the filters. Instead of explaining how that works, I'm going to take this opportunity to show how that should work.
If the value returned by
othewise these fixes would have been corrected. This filter was written before I learned about Trinary Operators, which could have reduced the above code down to 6 lines. note: In the released version of the filters, there was a mysterious 120 after the r<180. This must have been a leftover from my trying to figure this out, but the real mystery is why this didn't cause everything to blow up? If you'd like to fix this in the paid version of Joe's Filters, just delete the 120, it has no effect.
I spent a long time fussing around with the angle input. I had trouble coming up with a simple way of getting the values into the channels. Originally I suspected there might be a very elegant way of moving using the angle value with no ifelse statements, but after spending most of a Saturday morning trying, I eventually gave in to one ifelse statement with a set of additional statements for capping the high and low values. It's probably not the most elegant solution, but it works.
The SolutionThe solution I came up with is based on this formula: In trying to work out how to get the colors to move across the matrix, I knew I had the following values to work with:
Those three values were then combined into the following formula:
How it worksI used two inputs, a popup named RGBTarget and labeled "Source"; and a slider named desat and labeled "Saturation". The slider has values go from 0 to 100. For the matrix, I decided to enter values as variables since it was easier for me to think about, so I declared the following floating point Variables:
See my 3x3 Matrix Fun filter for a more detailed explanation of how the 3x3 matrix works for RGB. r, g, and b variables refer to thwhich apply to the matix as follows:
The filter will take move data from one channel into another, depending on the selected method of desaturation. The clunkiness of the Blue channel is the result of compression in the YUV encoding. Read this page for more information: I built this filter with each of the 9 entries of the 3x3 matrix as searate variables. Partly I did this because it's easier for me to work with, partly because I don't understand 3x3 matrix math much at all. It seems to make sense, but it hasn't been in my head long enough to make use of it yet.

The FXScript ReferenceFXScripting Joe's FiltersJoe's Filters for Final Cut Pro Building Joe's Minimum Maximum Joe's FXScript ExplorersJoe's Debug and Explore Filters Joe's 3x3 Convolve Matrix Tester Joe's 3x3 Matrix Values Tester Other FCP Stuff
Film & VideoRecording the sound of PhotographyProjectsFinal Cut ProDesignWRITINGSite Notes Archive (weblog) Web ResourcesAbout Joe MallerPast Home Pages Etc.Search joemaller.comContact Me

