Rendering the Final Image

Episode #301 | 15 minutes | published on September 8, 2017 | Uses Xcode-9.0-beta3, swift-4
Subscribers Only
In this episode we take the captured image and run the perspective correction filter on it in order to turn a skewed rect back into a flat rectangle. We then display the image on the screen for a few seconds as a preview mechanism.

Episode Links

Perspective Correction

private func perspectiveCorrect(_ image: CIImage, rectFeature: CIRectangleFeature) -> CIImage? {

        let perspectiveFilter = CIFilter(name: kCIPerspectiveCorrection)!
        perspectiveFilter.setValue(image, forKey: kCIInputImageKey)

        let corners = [
            (rectFeature.topLeft, "inputTopLeft"),
            (rectFeature.topRight, "inputTopRight"),
            (rectFeature.bottomRight, "inputBottomRight"),
            (rectFeature.bottomLeft, "inputBottomLeft"),

        for (point, key) in corners {
            let vector = CIVector(cgPoint: point)
            perspectiveFilter.setValue(vector, forKey: key)

        guard let correctedImage = perspectiveFilter.outputImage else { return nil }

        return correctedImage

Displaying the image on screen

    private func displayImage(ciImage: CIImage) {
        guard let cgImage = ciContext.createCGImage(ciImage, from: ciImage.extent) else {

        let image = UIImage(cgImage: cgImage, scale: UIScreen.main.scale, orientation: .up)
        let imageView = UIImageView(image: image)
        imageView.frame = view.bounds
        imageView.backgroundColor = UIColor(white: 0, alpha: 0.8)
        imageView.contentMode = .scaleAspectFit
        imageView.alpha = 0

        UIView.animate(withDuration: 0.3) {
            imageView.alpha = 1

        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            UIView.animate(withDuration: 0.3, animations: {
                imageView.alpha = 0
            }, completion: { completed in
                self.detectRectangles = true


Fixing the rotation of the image

Running the application, we can see that if we capture the image, it is displayed in a rotated fashion. To fix this, we can chain another filter to our perspective correction method in order to rotate the image to the proper orientation.

        let extent = correctedImage.extent

        let transformFilter = CIFilter(name: kCIAffineTransform)!
         |    |

        var transform = CGAffineTransform(translationX: extent.midX, y: -extent.midY)
        transform = transform.rotated(by: -.pi/2)
        transform = transform.translatedBy(x: -extent.midX, y: extent.midY)
        transformFilter.setValue(correctedImage, forKey: kCIInputImageKey)
        transformFilter.setValue(transform, forKey: kCIInputTransformKey)

        return transformFilter.outputImage
blog comments powered by Disqus