kernel IsolateColor < namespace: "com.bobs27"; vendor: "Todd Yard"; version: 1; description: "Isolates hue in image."; > { parameter int3 color < minValue: int3(0, 0, 0); maxValue: int3(255, 255, 255); defaultValue: int3(255, 0, 0); description: "The color to isolate."; >; parameter int hueThreshold < minValue: int(0); maxValue: int(360); defaultValue: int(10); description: "The amount off-hue to allow."; >; parameter int luminanceThreshold < minValue: int(0); maxValue: int(255); defaultValue: int(100); description: "The amount off-luminance to allow."; >; parameter int hideNonIsolated < minValue: int(0); maxValue: int(1); defaultValue: int(0); description: "Whether alpha of 0 should be applied to non-isolated pixels."; >; const float3 grayValues = float3(0.3, 0.59, 0.11); input image4 source; output pixel4 result; void evaluatePixel() { float4 px = sampleNearest(source, outCoord()); // determine hue of color to isolate, between 0 and 360 int hue = 0; int r = color.r; int g = color.g; int b = color.b; if (r == g && g == b) { hue = 0; } else if (r >= g && g >= b) { hue = 60 * (g - b)/(r - b); } else if (g >= r && r >= b) { hue = 60 + 60*(g - r)/(g - b); } else if (g >= b && b >= r) { hue = 120 + 60*(b - r)/(g - r); } else if (b >= g && g >= r) { hue = 180 + 60*(b - g)/(b - r); } else if (b >= r && r >= g){ hue = 240 + 60*(r - g)/(b - g); } else if (r >= b && b >= g) { hue = 300 + 60*(r - b)/(r - g); } float isolateHue = float(hue); // determine hue of color current pixel being evaluated, between 0 and 360 hue = 0; r = int(px.r * 255.0); g = int(px.g * 255.0); b = int(px.b * 255.0); if (r == g && g == b) { hue = 0; } else if (r >= g && g >= b) { hue = 60 * (g - b)/(r - b); } else if (g >= r && r >= b) { hue = 60 + 60*(g - r)/(g - b); } else if (g >= b && b >= r) { hue = 120 + 60*(b - r)/(g - r); } else if (b >= g && g >= r) { hue = 180 + 60*(b - g)/(b - r); } else if (b >= r && r >= g){ hue = 240 + 60*(r - g)/(b - g); } else if (r >= b && b >= g) { hue = 300 + 60*(r - b)/(r - g); } float pixelHue = float(hue); // since hue "wraps" around the 360 degrees, do some manipulation so that // values can be more easily evaluated when too close to end of spectrum if (pixelHue - float(hueThreshold) < 0.0 && isolateHue + float(hueThreshold) > 360.0) { pixelHue = 360.0 - float(hueThreshold); } else if (pixelHue + float(hueThreshold) > 360.0 && isolateHue - float(hueThreshold) < 0.0) { pixelHue = float(hueThreshold) - 360.0; } // determine the luminance/brightness/value of colors float pixelLuminance = px.r * 0.3 + px.g * 0.59 + px.b * 0.11; float isolateLuminance = float(color.r)/255.0 * 0.3 + float(color.g)/255.0 * 0.59 + float(color.b)/255.0 * 0.11; // if luminance and hue are NOT within thresholds... if (abs(pixelHue - isolateHue) > float(hueThreshold) || abs(pixelLuminance - isolateLuminance) > float(luminanceThreshold)/255.0 ) { // either hide pixel completely by setting alpha to 0 if (hideNonIsolated == 1) { px.a = 0.0; // or recolor pixel to grayscale } else { float distanceToDesaturatedValues = dot(px.rgb, grayValues); px.rgb = float3(distanceToDesaturatedValues); } } result = px; } }