简体   繁体   English

使用 Vision 扫描照片库中的图像

[英]Using Vision to scan images from photo library

Is there a way that I can use the Vision framework to scan an existing image from the user's photo library?有没有办法可以使用Vision框架扫描用户照片库中的现有图像? As in, not taking a new picture using the camera, but just choosing an image that the user already has?例如,不使用相机拍摄新照片,而只是选择用户已有的图像?

Yes, you can.是的你可以。 First, take an instance of UIImagePickerController & present it.首先,获取 UIImagePickerController 的一个实例并呈现它。

let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .photoLibrary
present(picker, animated: true, completion: nil)

Then implement the delegate method take the desired image然后实现委托方法获取所需的图像

extension YourViewController: UIImagePickerControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    if let pickedImage = info[.originalImage] as? UIImage {
        
        ## here start your request & request handler
    }
    
    picker.dismiss(animated: true, completion: nil)
    
    }
}

Yes, you can.是的你可以。 Adding on to @Zulqarnayn 's answer, here's a working example to detect and draw a bounding box on rectangles.添加到@Zulqarnayn的答案,这是一个检测和绘制矩形边界框的工作示例。

1. Set up the image view where the image will be displayed 1.设置要显示图像的图像视图

在此处输入图像描述

@IBOutlet weak var imageView: UIImageView!

@IBAction func pickImage(_ sender: Any) {
    let picker = UIImagePickerController()
    picker.delegate = self
    self.present(picker, animated: true)
}

override func viewDidLoad() {
    super.viewDidLoad()
    
    imageView.layer.borderWidth = 4
    imageView.layer.borderColor = UIColor.blue.cgColor
    imageView.contentMode = .scaleAspectFill
    
    imageView.backgroundColor = UIColor.green.withAlphaComponent(0.3)
    imageView.layer.masksToBounds = false /// allow image to overflow, for testing purposes
    
}

2. Get the image from the image picker 2.从图像选择器中获取图像

extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        guard let image = info[.originalImage] as? UIImage else { return }

        /// set the imageView's image
        imageView.image = image

        /// start the request & request handler
        detectCard()

        /// dismiss the picker
        dismiss(animated: true)
    }
}

3. Start the vision request 3.启动视觉请求

func detectCard() {
    guard let cgImage = imageView.image?.cgImage else { return }

    /// perform on background thread, so the main screen is not frozen
    DispatchQueue.global(qos: .userInitiated).async {
        
        let request = VNDetectRectanglesRequest { request, error in

            /// this function will be called when the Vision request finishes
            self.handleDetectedRectangle(request: request, error: error)
        }
        
        request.minimumAspectRatio = 0.0
        request.maximumAspectRatio = 1.0
        request.maximumObservations = 1 /// only look for 1 rectangle
        
        let imageRequestHandler = VNImageRequestHandler(cgImage: cgImage, orientation: .up)
        
        do {
            try imageRequestHandler.perform([request])
        } catch let error {
            print("Error: \(error)")
        }
    }
}

4. Get the result from the Vision request 4. 从 Vision 请求中获取结果

func handleDetectedRectangle(request: VNRequest?, error: Error?) {
    if let results = request?.results {
        if let observation = results.first as? VNRectangleObservation {
            
            /// get back to the main thread
            DispatchQueue.main.async {
                guard let image = self.imageView.image else { return }
                
                let convertedRect = self.getConvertedRect(
                    boundingBox: observation.boundingBox,
                    inImage: image.size,
                    containedIn: self.imageView.bounds.size
                )
                self.drawBoundingBox(rect: convertedRect)
            }
        }
    }
}

5. Convert observation.boundingBox to the UIKit coordinates of the image view, then draw a border around the detected rectangle 5.将observation.boundingBox转换为image view的UIKit坐标,然后在检测到的矩形周围画一个边框

I explain this more in detail in this answer .我在这个答案中更详细地解释了这一点。

func getConvertedRect(boundingBox: CGRect, inImage imageSize: CGSize, containedIn containerSize: CGSize) -> CGRect {
    
    let rectOfImage: CGRect
    
    let imageAspect = imageSize.width / imageSize.height
    let containerAspect = containerSize.width / containerSize.height
    
    if imageAspect > containerAspect { /// image extends left and right
        let newImageWidth = containerSize.height * imageAspect /// the width of the overflowing image
        let newX = -(newImageWidth - containerSize.width) / 2
        rectOfImage = CGRect(x: newX, y: 0, width: newImageWidth, height: containerSize.height)
        
    } else { /// image extends top and bottom
        let newImageHeight = containerSize.width * (1 / imageAspect) /// the width of the overflowing image
        let newY = -(newImageHeight - containerSize.height) / 2
        rectOfImage = CGRect(x: 0, y: newY, width: containerSize.width, height: newImageHeight)
    }
    
    let newOriginBoundingBox = CGRect(
    x: boundingBox.origin.x,
    y: 1 - boundingBox.origin.y - boundingBox.height,
    width: boundingBox.width,
    height: boundingBox.height
    )
    
    var convertedRect = VNImageRectForNormalizedRect(newOriginBoundingBox, Int(rectOfImage.width), Int(rectOfImage.height))
    
    /// add the margins
    convertedRect.origin.x += rectOfImage.origin.x
    convertedRect.origin.y += rectOfImage.origin.y
    
    return convertedRect
}

/// draw an orange frame around the detected rectangle, on top of the image view
func drawBoundingBox(rect: CGRect) {
    let uiView = UIView(frame: rect)
    imageView.addSubview(uiView)
    
    uiView.backgroundColor = UIColor.clear
    uiView.layer.borderColor = UIColor.orange.cgColor
    uiView.layer.borderWidth = 3
}

Result |结果 | Demo repo演示回购

Input image输入图像 Result结果
在此处输入图像描述
在此处输入图像描述
在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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