Episode #301

Rendering the Final Image

Series: Camera Capture and Detection

15 minutes
Published on September 8, 2017

This video is only available to subscribers. Get access to this video and 572 others.

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 {
            fatalError()
        }

        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
        view.addSubview(imageView)

        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
                imageView.removeFromSuperview()
                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

This episode uses Xcode 9.0-beta3, Swift 4.