Skip to content

Instantly share code, notes, and snippets.

@sushihangover
Last active November 16, 2017 21:32
Show Gist options
  • Save sushihangover/e94ab75592e21d990df7466f95bfd8e1 to your computer and use it in GitHub Desktop.
Save sushihangover/e94ab75592e21d990df7466f95bfd8e1 to your computer and use it in GitHub Desktop.
Xamarin iOS CIFilter / CIColorKernel Replace one color with another color (with threshold parameter to catch those stray variants)
public class ColorReplaceFilter : CIFilter
{
const string filterName = "colorReplace";
const int numArgs = 4;
const string coreIageShaderProgram =
@"
kernel vec4 main(__sample s, __color o, __color r, float threshold) {
vec4 diff = s.rgba - o;
float distance = length( diff );
float alpha = compare( distance - threshold, 0.0, 1.0 );
if (alpha == 0.0)
return r;
return s;
}
";
NSObject[] arguments;
CIColorKernel colorKernel;
public ColorReplaceFilter() { Initializer(); }
public ColorReplaceFilter(NSCoder coder) : base(coder) { Initializer(); }
public ColorReplaceFilter(NSObjectFlag t) : base(t) { Initializer(); }
public ColorReplaceFilter(IntPtr handle) : base(handle) { Initializer(); }
public CIImage InputImage { get; set; }
public CIColor MatchColor { get; set; }
public CIColor ReplaceWithColor { get; set; }
NSNumber _threshold;
public nfloat Threshold
{
get { return _threshold.NFloatValue; }
set { _threshold = NSNumber.FromNFloat(value); }
}
void Initializer()
{
arguments = new NSObject[numArgs];
colorKernel = CIColorKernel.FromProgramSingle(coreIageShaderProgram);
MatchColor = CIColor.BlackColor;
ReplaceWithColor = CIColor.WhiteColor;
_threshold = new NSNumber(0.0f);
}
public override string Name
{
get => filterName;
}
public override CIImage OutputImage
{
get => CreateOutputImage();
}
CIImage CreateOutputImage()
{
if (InputImage != null) // Avoid object creation to allow fast filter chaining
{
arguments[0] = InputImage as NSObject;
arguments[1] = MatchColor as NSObject;
arguments[2] = ReplaceWithColor as NSObject;
arguments[3] = _threshold as NSObject;
var ciImage = colorKernel.ApplyWithExtent(InputImage.Extent, arguments);
return ciImage;
}
return null;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
arguments = null;
InputImage = null;
MatchColor = null;
ReplaceWithColor = null;
colorKernel.Dispose();
}
}
var inputImage = inputVIew.Image; // Some UIImage as input;
var replaceFilter = new ColorReplaceFilter
{
InputImage = new CIImage(inputImage)
};
replaceFilter.MatchColor = CIColor.FromRgba(red: 0.019f, green: 0.235f, blue: 0.458f, alpha: 1);
replaceFilter.ReplaceWithColor = CIColor.FromRgb(255, 0, 0);
thresholdSlider.ValueChanged += (sender, e) =>
{
replaceFilter.Threshold = thresholdSlider.Value;
var image = replaceFilter.OutputImage;
outputView.Image = UIImage.FromImage(image);
};
@sushihangover
Copy link
Author

screen shot 2017-11-15 at 5 02 08 pm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment