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 识别的元素周围绘制矩形的主要内容,如果未能解决你的问题,请参考以下文章