I write SplitMirror filter like in Apple Motion app or Snapchat lenses by using UIGraphics
to use it with real time camera feed or video processing, with single image request it works well like in attached image in the question but for multiple filtering request not. I think it's code must be changed from UIGraphics
to Core Image & CIContext
for better performance and less memory usage like CIFilters
and actually I don't know how to do it.
I tried several ways to convert it but I stuck on merging left and right, this can be done with `CICategoryCompositeOperations filters but which one is fit this case I o have idea, so need some help with this issue.
Filter code using UIGraphics
:
//
// SplitMirror filter.swift
// Image Editor
//
// Created by Coder ACJHP on 25.02.2022.
//
// SnapChat & Tiktok & Motion App like image filter
// Inspired from 'https://support.apple.com/tr-tr/guide/motion/motn169f94ea/mac'
// Splits an image in half vertically and reverses the left remaining half to create a reflection.
final func splitMirrorFilter(processingImage image: UIImage) -> UIImage {
// Image size
let imageSize = image.size
// Left half
let leftHalfRect = CGRect(
origin: .zero,
size: CGSize(
width: imageSize.width/2,
height: imageSize.height
)
)
// Right half
let rightHalfRect = CGRect(
origin: CGPoint(
x: imageSize.width - (imageSize.width/2).rounded(),
y: 0
),
size: CGSize(
width: imageSize.width - (imageSize.width/2).rounded(),
height: imageSize.height
)
)
// Split image into two parts
guard let cgRightHalf = image.cgImage?.cropping(to: rightHalfRect) else { return image }
// Flip right side to be used as left side
let flippedLeft = UIImage(cgImage: cgRightHalf, scale: image.scale, orientation: .upMirrored)
let unFlippedRight = UIImage(cgImage: cgRightHalf, scale: image.scale, orientation: image.imageOrientation)
UIGraphicsBeginImageContextWithOptions(imageSize, false, image.scale)
flippedLeft.draw(at: leftHalfRect.origin)
unFlippedRight.draw(at: rightHalfRect.origin)
guard let splitMirroredImage = UIGraphicsGetImageFromCurrentImageContext() else { return image }
UIGraphicsEndImageContext()
return splitMirroredImage
}
Here is what it tried with Core Image
// Splits an image in half vertically and reverses the left remaining half to create a reflection.
final func splitMirrorFilterCIImageVersion(processingImage image: UIImage) -> CIImage? {
guard let ciImageCopy = CIImage(image: image) else { return image.ciImage }
// Image size
let imageSize = ciImageCopy.extent.size
let imageRect = CGRect(origin: .zero, size: imageSize)
// Left half
let leftHalfRect = CGRect(
origin: .zero,
size: CGSize(
width: imageSize.width/2,
height: imageSize.height
)
)
// Right half
let rightHalfRect = CGRect(
origin: CGPoint(
x: imageSize.width - (imageSize.width/2).rounded(),
y: 0
),
size: CGSize(
width: imageSize.width - (imageSize.width/2).rounded(),
height: imageSize.height
)
)
// Split image into two parts
let cgRightHalf = ciImageCopy.cropped(to: rightHalfRect)
context.draw(cgRightHalf.oriented(.upMirrored), in: leftHalfRect, from: imageRect)
context.draw(cgRightHalf, in: rightHalfRect, from: imageRect)
// I'm stuck here
// Merge two images into one
// Here I don't know which filter can be used to merge op
// CICategoryCompositeOperation filters may fits
}
CodePudding user response:
I think you are on the right track.
You can create the left half from the right half by applying transformations to it using let leftHalf = rightHalf.transformed(by: transformation)
. The transformation should mirror it and translate it to the correct position, i.e., next to the right half.
You can them combine the two into one image using let result = leftHalf.composited(over: rightHalf)
and render that result using a CIContext
.
CodePudding user response:
After getting the correct idea from Frank Schlegel 's answer I rewrote filter code and now works well.
// Splits an image in half vertically and reverses the left remaining half to create a reflection.
final func splitMirrorFilterCIImageVersion(processingImage image: UIImage) -> CIImage? {
guard let ciImageCopy = CIImage(image: image) else { return image.ciImage }
// Image size
let imageSize = ciImageCopy.extent.size
// Right half
let rightHalfRect = CGRect(
origin: CGPoint(
x: imageSize.width - (imageSize.width/2).rounded(),
y: 0
),
size: CGSize(
width: imageSize.width - (imageSize.width/2).rounded(),
height: imageSize.height
)
)
// Split image into two parts
let ciRightHalf = ciImageCopy.cropped(to: rightHalfRect)
// Make transform to move right part to left
let transform = CGAffineTransform(translationX: -rightHalfRect.size.width, y: -rightHalfRect.origin.y)
// Create left part and apply transform then flip it
let ciLeftHalf = ciRightHalf.transformed(by: transform).oriented(.upMirrored)
// Merge two images into one
return ciLeftHalf.composited(over: ciRightHalf)
}