Created
February 4, 2016 20:00
-
-
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!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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