Skip to content

Instantly share code, notes, and snippets.

@FlexMonkey
Created February 4, 2016 20:00
Show Gist options
  • Save FlexMonkey/eb95719f73cd2b6380b4 to your computer and use it in GitHub Desktop.
Save FlexMonkey/eb95719f73cd2b6380b4 to your computer and use it in GitHub Desktop.
UnrolledKuwaharaFilter - replace a GLSL loop with a Swift one. Performance is rubbish, this is here for reference only!
class UnrolledKuwaharaFilter: CIFilter
{
var inputImage: CIImage?
var inputRadius: CGFloat = 15
{
didSet
{
if Int(inputRadius) != Int(oldValue)
{
kuwaharaKernel = nil
}
}
}
override var attributes: [String : AnyObject]
{
return [
kCIAttributeFilterDisplayName: "Kuwahara Filter (Unrolled)",
"inputImage": [kCIAttributeIdentity: 0,
kCIAttributeClass: "CIImage",
kCIAttributeDisplayName: "Image",
kCIAttributeType: kCIAttributeTypeImage],
"inputRadius": [kCIAttributeIdentity: 0,
kCIAttributeClass: "NSNumber",
kCIAttributeDefault: 15,
kCIAttributeDisplayName: "Radius",
kCIAttributeMin: 0,
kCIAttributeSliderMin: 0,
kCIAttributeSliderMax: 30,
kCIAttributeType: kCIAttributeTypeScalar]
]
}
override func setDefaults()
{
inputRadius = 15
}
var kuwaharaKernel: CIKernel?
func createKuwaharaKernel() -> CIKernel?
{
var kernelString: String =
"kernel vec4 kuwahara(sampler image, float r) \n" +
"{" +
" vec2 d = destCoord();" +
" int radius = int(r); " +
" float n = float((radius + 1) * (radius + 1)); " +
" vec3 means[4]; " +
" vec3 stdDevs[4]; " +
" for (int i = 0; i < 4; i++) " +
" { " +
" means[i] = vec3(0.0); " +
" stdDevs[i] = vec3(0.0); " +
" } "
for x in -Int(inputRadius) ... Int(inputRadius)
{
for y in -Int(inputRadius) ... Int(inputRadius)
{
let suffix = "\(Int(inputRadius) + x)_\(Int(inputRadius) + y)"
kernelString +=
"vec3 color\(suffix) = sample(image, samplerTransform(image, d + vec2(\(x),\(y)))).rgb; \n" +
"vec3 colorA\(suffix) = vec3(float(\(x) <= 0 && \(y) <= 0)) * color\(suffix); \n" +
"means[0] += colorA\(suffix); \n" +
"stdDevs[0] += colorA\(suffix) * colorA\(suffix); \n" +
"vec3 colorB\(suffix) = vec3(float(\(x) >= 0 && \(y) <= 0)) * color\(suffix); \n" +
"means[1] += colorB\(suffix); \n" +
"stdDevs[1] += colorB\(suffix) * colorB\(suffix); \n" +
"vec3 colorC\(suffix) = vec3(float(\(x) <= 0 && \(y) >= 0)) * color\(suffix); \n" +
"means[2] += colorC\(suffix); \n" +
"stdDevs[2] += colorC\(suffix) * colorC\(suffix); \n" +
"vec3 colorD\(suffix) = vec3(float(\(x) >= 0 && \(y) >= 0)) * color\(suffix); \n" +
"means[3] += colorD\(suffix); \n" +
"stdDevs[3] += colorD\(suffix) * colorD\(suffix); \n"
}
}
kernelString +=
" float minSigma2 = 1e+2;" +
" vec3 returnColor = vec3(0.0); " +
" for (int j = 0; j < 4; j++) " +
" { " +
" means[j] /= n; " +
" stdDevs[j] = abs(stdDevs[j] / n - means[j] * means[j]);" +
" float sigma2 = stdDevs[j].r + stdDevs[j].g + stdDevs[j].b;" +
" returnColor = (sigma2 < minSigma2) ? means[j] : returnColor; " +
" minSigma2 = (sigma2 < minSigma2) ? sigma2 : minSigma2; " +
" } " +
" return vec4(returnColor, 1.0); " +
"}"
return CIKernel(string: kernelString)
}
override var outputImage : CIImage!
{
if kuwaharaKernel == nil
{
kuwaharaKernel = createKuwaharaKernel()
}
if let inputImage = inputImage
{
let arguments = [inputImage, inputRadius]
let extent = inputImage.extent
return kuwaharaKernel!.applyWithExtent(extent,
roiCallback:
{
(index, rect) in
return rect
},
arguments: arguments)
}
return nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment