Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save fahied/8d0dcf09ef59836d08c087534fffc12b to your computer and use it in GitHub Desktop.
Save fahied/8d0dcf09ef59836d08c087534fffc12b to your computer and use it in GitHub Desktop.
// Don't forget to add to the project:
// 1. DeepLabV3 - https://developer.apple.com/machine-learning/models/
// 2. CoreMLHelpers - https://github.com/hollance/CoreMLHelpers
enum RemoveBackroundResult {
case background
case finalImage
}
extension UIImage {
func removeBackground(returnResult: RemoveBackroundResult) -> UIImage? {
guard let model = getDeepLabV3Model() else { return nil }
let width: CGFloat = 513
let height: CGFloat = 513
let resizedImage = resized(to: CGSize(width: height, height: height), scale: 1)
guard let pixelBuffer = resizedImage.pixelBuffer(width: Int(width), height: Int(height)),
let outputPredictionImage = try? model.prediction(image: pixelBuffer),
let outputImage = outputPredictionImage.semanticPredictions.image(min: 0, max: 1, axes: (0, 0, 1)),
let outputCIImage = CIImage(image: outputImage),
let maskImage = outputCIImage.removeWhitePixels(),
let maskBlurImage = maskImage.applyBlurEffect() else { return nil }
switch returnResult {
case .finalImage:
guard let resizedCIImage = CIImage(image: resizedImage),
let compositedImage = resizedCIImage.composite(with: maskBlurImage) else { return nil }
let finalImage = UIImage(ciImage: compositedImage)
.resized(to: CGSize(width: size.width, height: size.height))
return finalImage
case .background:
let finalImage = UIImage(
ciImage: maskBlurImage,
scale: scale,
orientation: self.imageOrientation
).resized(to: CGSize(width: size.width, height: size.height))
return finalImage
}
}
private func getDeepLabV3Model() -> DeepLabV3? {
do {
let config = MLModelConfiguration()
return try DeepLabV3(configuration: config)
} catch {
log("Error loading model: \(error)")
return nil
}
}
}
extension CIImage {
func removeWhitePixels() -> CIImage? {
let chromaCIFilter = chromaKeyFilter()
chromaCIFilter?.setValue(self, forKey: kCIInputImageKey)
return chromaCIFilter?.outputImage
}
func composite(with mask: CIImage) -> CIImage? {
return CIFilter(
name: "CISourceOutCompositing",
parameters: [
kCIInputImageKey: self,
kCIInputBackgroundImageKey: mask
]
)?.outputImage
}
func applyBlurEffect() -> CIImage? {
let context = CIContext(options: nil)
let clampFilter = CIFilter(name: "CIAffineClamp")!
clampFilter.setDefaults()
clampFilter.setValue(self, forKey: kCIInputImageKey)
guard let currentFilter = CIFilter(name: "CIGaussianBlur") else { return nil }
currentFilter.setValue(clampFilter.outputImage, forKey: kCIInputImageKey)
currentFilter.setValue(2, forKey: "inputRadius")
guard let output = currentFilter.outputImage,
let cgimg = context.createCGImage(output, from: extent) else { return nil }
return CIImage(cgImage: cgimg)
}
// modified from https://developer.apple.com/documentation/coreimage/applying_a_chroma_key_effect
private func chromaKeyFilter() -> CIFilter? {
let size = 64
var cubeRGB = [Float]()
for z in 0 ..< size {
let blue = CGFloat(z) / CGFloat(size - 1)
for y in 0 ..< size {
let green = CGFloat(y) / CGFloat(size - 1)
for x in 0 ..< size {
let red = CGFloat(x) / CGFloat(size - 1)
let brightness = getBrightness(red: red, green: green, blue: blue)
let alpha: CGFloat = brightness == 1 ? 0 : 1
cubeRGB.append(Float(red * alpha))
cubeRGB.append(Float(green * alpha))
cubeRGB.append(Float(blue * alpha))
cubeRGB.append(Float(alpha))
}
}
}
let data = Data(buffer: UnsafeBufferPointer(start: &cubeRGB, count: cubeRGB.count))
let colorCubeFilter = CIFilter(
name: "CIColorCube",
parameters: [
"inputCubeDimension": size,
"inputCubeData": data
]
)
return colorCubeFilter
}
// modified from https://developer.apple.com/documentation/coreimage/applying_a_chroma_key_effect
private func getBrightness(red: CGFloat, green: CGFloat, blue: CGFloat) -> CGFloat {
let color = UIColor(red: red, green: green, blue: blue, alpha: 1)
var brightness: CGFloat = 0
color.getHue(nil, saturation: nil, brightness: &brightness, alpha: nil)
return brightness
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment