简体   繁体   中英

How to draw a line at the corner of a square with CAShapeLayer in Swift

I am developing a face recognition application of Vision library, and I am having trouble drawing lines with CAShapeLayer

here is the code after getting camera output:

func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
        guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
            return
        }
        
        let imageRequestHandler = VNImageRequestHandler(cvPixelBuffer: imageBuffer, orientation: .leftMirrored, options: [:])
        
        let faceDetectionRequest = VNDetectFaceLandmarksRequest(completionHandler: { (request: VNRequest, error: Error?) in
            DispatchQueue.main.async {
                self.faceLayers.forEach({ drawing in drawing.removeFromSuperlayer() })
                
                if let observations = request.results as? [VNFaceObservation] {
                    for observation in observations {
                        let faceRectConverted = self.videoPreviewLayer.layerRectConverted(fromMetadataOutputRect: observation.boundingBox)
                        let faceRectanglePath = CGPath(rect: faceRectConverted, transform: nil)
                        
                        let faceLayer = CAShapeLayer()
                        faceLayer.path = faceRectanglePath
                        faceLayer.fillColor = UIColor.clear.cgColor
                        faceLayer.strokeColor = UIColor.systemPink.cgColor
                        
                        self.faceLayers.append(faceLayer)
                        self.cameraView.layer.addSublayer(faceLayer)
                    }
                }
            }
        })
        
        do {
            try imageRequestHandler.perform([faceDetectionRequest])
        } catch {
            print(error.localizedDescription)
        }
    }

result

在此处输入图像描述

the problem I am facing when I want to draw a short line at the corner of the square

在此处输入图像描述

Thanks for all the support!

You can use this:

let thinLayer = CAShapeLayer()
thinLayer.path = CGPath(rect: rect, transform: nil)
thinLayer.strokeColor = UIColor.purple.cgColor
thinLayer.fillColor = UIColor.clear.cgColor
thinLayer.lineWidth = 1.0
view.layer.addSublayer(thinLayer)

let cornerWidth: CGFloat = 20.0

let topLeftBezierPath = UIBezierPath()
topLeftBezierPath.move(to: CGPoint(x: rect.origin.x, y: rect.origin.y + cornerWidth))
topLeftBezierPath.addLine(to: CGPoint(x: rect.origin.x, y: rect.origin.y))
topLeftBezierPath.addLine(to: CGPoint(x: rect.origin.x + cornerWidth, y: rect.origin.y))

let topRightBezierPath = UIBezierPath()
topRightBezierPath.move(to: CGPoint(x: rect.maxX, y: rect.origin.y + cornerWidth))
topRightBezierPath.addLine(to: CGPoint(x: rect.maxX, y: rect.origin.y))
topRightBezierPath.addLine(to: CGPoint(x: rect.maxX - cornerWidth, y: rect.origin.y))


let bottomRightBezierPath = UIBezierPath()
bottomRightBezierPath.move(to: CGPoint(x: rect.maxX, y: rect.maxY - cornerWidth))
bottomRightBezierPath.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
bottomRightBezierPath.addLine(to: CGPoint(x: rect.maxX - cornerWidth, y: rect.maxY))


let bottomLeftBezierPath = UIBezierPath()
bottomLeftBezierPath.move(to: CGPoint(x: rect.origin.x, y: rect.maxY - cornerWidth))
bottomLeftBezierPath.addLine(to: CGPoint(x: rect.origin.x, y: rect.maxY))
bottomLeftBezierPath.addLine(to: CGPoint(x: rect.origin.x + cornerWidth, y: rect.maxY))


func cornerLayer(with bezierPath: UIBezierPath) -> CAShapeLayer {
    let shape = CAShapeLayer()
    shape.path = bezierPath.cgPath
    shape.lineWidth = 4.0
    shape.strokeColor = UIColor.purple.cgColor
    shape.fillColor = UIColor.clear.cgColor
    shape.lineCap = .round
    return shape
}


let topLeftShape = cornerLayer(with: topLeftBezierPath)
view.layer.addSublayer(topLeftShape)

let topRightShape = cornerLayer(with: topRightBezierPath)
view.layer.addSublayer(topRightShape)

let bottomRightShape = cornerLayer(with: bottomRightBezierPath)
view.layer.addSublayer(bottomRightShape)

let bottomLeftShape = cornerLayer(with: bottomLeftBezierPath)
view.layer.addSublayer(bottomLeftShape)

Where:

  • view is the UIView on which to add the layer, in your case it's cameraView .
  • rect is the full rect of the face, in your case it's faceRectConverted
  • customize to fulfill your needs ( lineWidh , strokeColor , cornerWidth which might me proportional to the size of the rect?)

Sample in Playground:

func drawing() -> UIView {
    let view = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
    view.backgroundColor = .orange

    let rect = CGRect(x: 50, y: 50, width: 200, height: 200)

    let thinLayer = CAShapeLayer()
    thinLayer.path = CGPath(rect: rect, transform: nil)
    thinLayer.strokeColor = UIColor.purple.cgColor
    thinLayer.fillColor = UIColor.clear.cgColor
    thinLayer.lineWidth = 1.0
    view.layer.addSublayer(thinLayer)

    let cornerWidth: CGFloat = 20.0

    let topLeftBezierPath = UIBezierPath()
    topLeftBezierPath.move(to: CGPoint(x: rect.origin.x, y: rect.origin.y + cornerWidth))
    topLeftBezierPath.addLine(to: CGPoint(x: rect.origin.x, y: rect.origin.y))
    topLeftBezierPath.addLine(to: CGPoint(x: rect.origin.x + cornerWidth, y: rect.origin.y))

    let topRightBezierPath = UIBezierPath()
    topRightBezierPath.move(to: CGPoint(x: rect.maxX, y: rect.origin.y + cornerWidth))
    topRightBezierPath.addLine(to: CGPoint(x: rect.maxX, y: rect.origin.y))
    topRightBezierPath.addLine(to: CGPoint(x: rect.maxX - cornerWidth, y: rect.origin.y))


    let bottomRightBezierPath = UIBezierPath()
    bottomRightBezierPath.move(to: CGPoint(x: rect.maxX, y: rect.maxY - cornerWidth))
    bottomRightBezierPath.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
    bottomRightBezierPath.addLine(to: CGPoint(x: rect.maxX - cornerWidth, y: rect.maxY))


    let bottomLeftBezierPath = UIBezierPath()
    bottomLeftBezierPath.move(to: CGPoint(x: rect.origin.x, y: rect.maxY - cornerWidth))
    bottomLeftBezierPath.addLine(to: CGPoint(x: rect.origin.x, y: rect.maxY))
    bottomLeftBezierPath.addLine(to: CGPoint(x: rect.origin.x + cornerWidth, y: rect.maxY))


    func cornerLayer(with bezierPath: UIBezierPath) -> CAShapeLayer {
        let shape = CAShapeLayer()
        shape.path = bezierPath.cgPath
        shape.lineWidth = 4.0
        shape.strokeColor = UIColor.purple.cgColor
        shape.fillColor = UIColor.clear.cgColor
        shape.lineCap = .round
        return shape
    }


    let topLeftShape = cornerLayer(with: topLeftBezierPath)
    view.layer.addSublayer(topLeftShape)

    let topRightShape = cornerLayer(with: topRightBezierPath)
    view.layer.addSublayer(topRightShape)

    let bottomRightShape = cornerLayer(with: bottomRightBezierPath)
    view.layer.addSublayer(bottomRightShape)

    let bottomLeftShape = cornerLayer(with: bottomLeftBezierPath)
    view.layer.addSublayer(bottomLeftShape)

    return view
}

let drawn = drawing()

drawn

Output:

在此处输入图像描述

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM