I implemented @Sasha's answer to be used in a custom camera. Below is my function to create the mask.
func createOverlay() -> UIView {
let overlayView = UIView(frame: view.frame)
overlayView.backgroundColor = UIColor.black.withAlphaComponent(0.7)
let path = CGMutablePath()
path.addRoundedRect(in: CGRect(x: 50, y: 100, width: overlayView.frame.width-100, height: overlayView.frame.height - 300), cornerWidth: 5, cornerHeight: 5)
path.closeSubpath()
let shape = CAShapeLayer()
shape.path = path
shape.lineWidth = 5.0
shape.strokeColor = UIColor.white.cgColor
shape.fillColor = UIColor.white.cgColor
overlayView.layer.addSublayer(shape)
path.addRect(CGRect(origin: .zero, size: overlayView.frame.size))
let maskLayer = CAShapeLayer()
maskLayer.backgroundColor = UIColor.black.cgColor
maskLayer.path = path
maskLayer.fillRule = CAShapeLayerFillRule.evenOdd
overlayView.layer.mask = maskLayer
overlayView.clipsToBounds = true
return overlayView
}
And I add it in to my custom camera preview layer using this function:
func setupPreviewLayer() {
self.cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
self.cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
self.cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
self.cameraPreviewLayer?.frame = self.view.bounds
self.view.layer.insertSublayer(cameraPreviewLayer!, at: 0)
let overlay = createOverlay()
self.view.addSubview(overlay)
}
The final product looks like this: Object Detection Frame
For my convenience, I've implemented this inside a viewDidLoad method and used a circle but not a rectangle. Also I'm addressing your issue mentioned;
However I can't figure out how to add that rectangle as a transparent mask inside camera layer.
Here is my full code.
import UIKit
import AVFoundation
class ViewController: UIViewController {
@IBOutlet weak var cameraPreviewView: UIView!
@IBOutlet weak var overlayView: UIView!
var session: AVCaptureSession?
var stillImageOutput: AVCapturePhotoOutput?
var videoPreviewLayer: AVCaptureVideoPreviewLayer?
override func viewDidLoad() {
super.viewDidLoad()
session = AVCaptureSession()
session?.sessionPreset = AVCaptureSession.Preset.photo
let backCamera = AVCaptureDevice.default(for: AVMediaType.video)
var error: NSError?
var input: AVCaptureDeviceInput!
do {
input = try AVCaptureDeviceInput(device: backCamera!)
} catch let error1 as NSError {
error = error1
input = nil
}
if error == nil && (session?.canAddInput(input))! {
session?.addInput(input)
stillImageOutput = AVCapturePhotoOutput()
}
if (session?.canAddOutput(stillImageOutput!))! {
session?.addOutput(stillImageOutput!)
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: session!)
videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspect
videoPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
cameraPreviewView.layer.addSublayer(videoPreviewLayer!)
session?.startRunning()
// I'm adding a circle not a rectangle. Make that adjustment in your code.
let radius : CGFloat = 50.0
let xOffset : CGFloat = 100 // Position according to your wish
let yOffset : CGFloat = 100 // Position according to your wish
let path = CGMutablePath()
path.addArc(center: CGPoint(x: xOffset, y: yOffset),
radius: radius,
startAngle: 0.0,
endAngle: 2.0 * .pi,
clockwise: false)
path.addRect(CGRect(origin: .zero, size: overlayView.frame.size))
let maskLayer = CAShapeLayer()
maskLayer.backgroundColor = UIColor.black.cgColor
maskLayer.path = path
maskLayer.fillRule = .evenOdd
overlayView.layer.mask = maskLayer
overlayView.clipsToBounds = true
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
videoPreviewLayer?.frame = cameraPreviewView.bounds
}
}
Make sure to add Privacy - Camera Usage Description inside your info.plist file.
Here is rectangle mask with rounded corners with borders
var overlay: UIView = UIView()
func createOverlay() -> UIView {
let overlayView = UIView(frame: view.frame)
overlayView.backgroundColor = UIColor.black.withAlphaComponent(0.4)
let path = CGMutablePath()
path.addRoundedRect(in: CGRect(x: 15, y: overlayView.center.y-100, width: overlayView.frame.width-30, height: 200), cornerWidth: 5, cornerHeight: 5)
path.closeSubpath()
let shape = CAShapeLayer()
shape.path = path
shape.lineWidth = 3.0
shape.strokeColor = UIColor.blue.cgColor
shape.fillColor = UIColor.blue.cgColor
overlayView.layer.addSublayer(shape)
path.addRect(CGRect(origin: .zero, size: overlayView.frame.size))
let maskLayer = CAShapeLayer()
maskLayer.backgroundColor = UIColor.black.cgColor
maskLayer.path = path
maskLayer.fillRule = CAShapeLayerFillRule.evenOdd
overlayView.layer.mask = maskLayer
overlayView.clipsToBounds = true
return overlayView
}
func addTransparentOverlayWithCirlce(){
overlay = createOverlay()
view.addSubview(overlay)
self.view.sendSubviewToBack(overlay)
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.