SwiftUI:在 Firebase ML Kit 识别的元素周围绘制矩形

Posted

技术标签:

【中文标题】SwiftUI:在 Firebase ML Kit 识别的元素周围绘制矩形【英文标题】:SwiftUI: Drawing rectangles around elements recognized with Firebase ML Kit 【发布时间】:2020-02-17 17:02:27 【问题描述】:

我目前正在尝试在图像顶部绘制用 Firebase ML Kit 识别的文本框。 目前,我还没有成功,我根本看不到任何框,因为它们都显示在屏幕外。我正在查看这篇文章作为参考:https://medium.com/swlh/how-to-draw-bounding-boxes-with-swiftui-d93d1414eb00 以及该项目:https://github.com/firebase/quickstart-ios/blob/master/mlvision/MLVisionExample/ViewController.swift

这是应该显示框的视图:

struct ImageScanned: View 
var image: UIImage
@Binding var rectangles: [CGRect]
@State var viewSize: CGSize = .zero

var body: some View 
    // TODO: fix scaling
       ZStack 
           Image(uiImage: image)
               .resizable()
               .scaledToFit()
               .overlay(
                   GeometryReader  geometry in
                    ZStack 
                        ForEach(self.transformRectangles(geometry: geometry))  rect in
                            Rectangle()
                            .path(in: CGRect(
                                x: rect.x,
                                y: rect.y,
                                width: rect.width,
                                height: rect.height))
                            .stroke(Color.red, lineWidth: 2.0)
                        
                    
                
           )
       

private func transformRectangles(geometry: GeometryProxy) -> [DetectedRectangle] 
    var rectangles: [DetectedRectangle] = []

    let imageViewWidth = geometry.frame(in: .global).size.width
    let imageViewHeight = geometry.frame(in: .global).size.height
    let imageWidth = image.size.width
    let imageHeight = image.size.height

    let imageViewAspectRatio = imageViewWidth / imageViewHeight
    let imageAspectRatio = imageWidth / imageHeight
    let scale = (imageViewAspectRatio > imageAspectRatio)
      ? imageViewHeight / imageHeight : imageViewWidth / imageWidth

    let scaledImageWidth = imageWidth * scale
    let scaledImageHeight = imageHeight * scale
    let xValue = (imageViewWidth - scaledImageWidth) / CGFloat(2.0)
    let yValue = (imageViewHeight - scaledImageHeight) / CGFloat(2.0)

    var transform = CGAffineTransform.identity.translatedBy(x: xValue, y: yValue)
    transform = transform.scaledBy(x: scale, y: scale)

    for rect in self.rectangles 
        let rectangle = rect.applying(transform)
        rectangles.append(DetectedRectangle(width: rectangle.width, height: rectangle.height, x: rectangle.minX, y: rectangle.minY))
    
    return rectangles

struct DetectedRectangle: Identifiable 
    var id = UUID()
    var width: CGFloat = 0
    var height: CGFloat = 0
    var x: CGFloat = 0
    var y: CGFloat = 0


这是该视图嵌套的视图:

struct StartScanView: View 
@State var showCaptureImageView: Bool = false
@State var image: UIImage? = nil
@State var rectangles: [CGRect] = []

var body: some View 
    ZStack 
        if showCaptureImageView 
            CaptureImageView(isShown: $showCaptureImageView, image: $image)
         else 
            VStack 

                Button(action: 
                    self.showCaptureImageView.toggle()
                ) 
                    Text("Start Scanning")
                

                // show here View with rectangles on top of image
                if self.image != nil 
                    ImageScanned(image: self.image ?? UIImage(), rectangles: $rectangles)
                


                Button(action: 
                    self.processImage()
                ) 
                    Text("Process Image")
                
            
        
    


func processImage() 
    let scaledImageProcessor = ScaledElementProcessor()
    if image != nil 
        scaledImageProcessor.process(in: image!)  text in
            for block in text.blocks 
                for line in block.lines 
                    for element in line.elements 
                        self.rectangles.append(element.frame)
                    
                
            
        
    

教程的计算导致矩形太大而示例项目之一太小。 (身高类似) 不幸的是,我找不到 Firebase 决定元素大小的大小。 这是它的样子: 根本不计算宽度和高度,矩形似乎具有它们应该具有的大小(不完全是),所以这给了我一个假设,即 ML Kit 的大小计算与 image.size 不成比例。高度/宽度。

【问题讨论】:

【参考方案1】:

这就是我改变 foreach 循环的方式

Image(uiImage: uiimage!).resizable().scaledToFit().overlay(
                     GeometryReader (geometry: GeometryProxy) in
                        ForEach(self.blocks , id: \.self) (block:VisionTextBlock) in
                            Rectangle().path(in: block.frame.applying(self.transformMatrix(geometry: geometry, image: self.uiimage!))).stroke(Color.purple, lineWidth: 2.0)
                        
                    

            )

我没有传递 x、y、宽度和高度,而是将 transformMatrix 函数的返回值传递给路径函数。

我的transformMatrix 函数是

    private func transformMatrix(geometry:GeometryProxy, image:UIImage) -> CGAffineTransform 

      let imageViewWidth = geometry.size.width
      let imageViewHeight = geometry.size.height
      let imageWidth = image.size.width
      let imageHeight = image.size.height

      let imageViewAspectRatio = imageViewWidth / imageViewHeight
      let imageAspectRatio = imageWidth / imageHeight
      let scale = (imageViewAspectRatio > imageAspectRatio) ?
        imageViewHeight / imageHeight :
        imageViewWidth / imageWidth

      // Image view's `contentMode` is `scaleAspectFit`, which scales the image to fit the size of the
      // image view by maintaining the aspect ratio. Multiple by `scale` to get image's original size.
      let scaledImageWidth = imageWidth * scale
      let scaledImageHeight = imageHeight * scale
      let xValue = (imageViewWidth - scaledImageWidth) / CGFloat(2.0)
      let yValue = (imageViewHeight - scaledImageHeight) / CGFloat(2.0)

      var transform = CGAffineTransform.identity.translatedBy(x: xValue, y: yValue)
      transform = transform.scaledBy(x: scale, y: scale)
      return transform
    

输出是

【讨论】:

【参考方案2】:

ML Kit 有一个 QuickStart 应用程序,它可以准确地显示您要执行的操作:识别文本并在文本周围绘制一个矩形。这是 Swift 代码:

https://github.com/firebase/quickstart-ios/tree/master/mlvision/MLVisionExample

【讨论】:

如果我尝试他们的方法,我得到的结果与我的修改版本相同 - 矩形变得很小。 (大约是他们假定大小的 1/6)。此外,他们使用的是 UIKit 而不是 SwiftUI... 我刚刚编辑了我的问题,因此可以看到我是如何修改它的。

以上是关于SwiftUI:在 Firebase ML Kit 识别的元素周围绘制矩形的主要内容,如果未能解决你的问题,请参考以下文章

通过 Firebase ML Kit 人脸检测检测多张人脸的轮廓

如何避免在 firebase ML Kit 的人脸检测 API 中捕获模糊图像

如何在 Firebase ML kit Android 中正确绘制检测到的人脸边界框?

无法使用 Firebase ML Kit Vision 文本检测器编译 iOS React Native 应用程序

Firebase ML套件:预训练模型

无法使用 firebase ML 套件检测眨眼事件