美文网首页
iOS视觉框架教程:轮廓检测

iOS视觉框架教程:轮廓检测

作者: iOS丶lant | 来源:发表于2022-05-18 16:44 被阅读0次

    入门

    本教程中,您将学习如何使用Vision 框架

    • 创建请求以执行肖像检测。
    • 以不同的方式。
    • 头像以创造艺术效果。

    获取底部的项目文件启动项目包括一些扩展、文件和 UI。

    01.png

    如果您现在并运行,您将看到屏幕点击和功能设置图标的说明。

    您可能会注意到现在点击屏幕不会做任何事情,但在您进入本教程的视觉部分之前,您需要在屏幕上显示图像。

    显示图像

    在浏览启动项目时,您可能已经注意到ImageView连接image到了ContentViewModel。您打开ContentViewModel.swift,您的属性会看到这image是一个已发布的,但没有任何分配内容。

    你需要做的第一个就是改变它!

    首先在ContentViewModel.swift中直接定义的三个已发布属性之后添加以下代码:

    在里面(){
      让 uiImage =  UIImage (named: "sample" )
      让 cgImage = uiImage ?.cgImage
      自我.image = cgImage  
    }
    

    从资产代码加载目录名为this.pngCGImage的图像并获得已经给出的一个,然后将其分配image发布的属性。

    通过这个小作品,继续并重新运行应用程序,您将在上面看到下面的图像:

    02.png

    现在,当您点击上面的屏幕时,它应该在您最初看到的空白屏幕的图像和之间切换。

    空白屏幕最终将包含您使用 Vision 框架检测到的剪影。

    视觉 API 管道

    在开始编写一些代码时,你很容易在这个场景中发现视觉 API 管道会很有帮助。如果你知道它是如何工作的,你就可以很容易地在未来的项目中包含任何视觉;漂亮。

    Vision API管道由三部分组成:

    1. 第一个是请求,它是VNRequest所有分析请求的子类。随后的请求传递给处理程序
    2. 处理程序可以是一种VNImageRequestHandler或一种类型VNSequenceRequestHandler
    3. 最后,作为原始请求对象的属性返回的结果是子类。VNObservation
    03.png

    通常,很容易判断出结果类型,例如与您的请求,因为它们的名称相似,如果您的请求是一个VNDetectFaceRectanglesRequest,那么返回的结果类型是一个VNFaceObservation

    对于这个项目,它的请求将VNDetectContoursRequest作为结果VNContoursObservation

    当处理图像时,图像是序列中的帧,而不是您将使用的图像VNImageRequestHandler。在VNSequenceRequestHandler处理序列中,您将使用来自请求项目中的请求时使用的相关图像,例如,您将使用该图像来处理图像。

    现在你已经掌握了背景理论,是时候将其付诸实践了!

    影像检测

    为了使项目井井有条,请创作项目导航器中的轮廓艺术组,然后选择新组。将新组命名为视觉

    点击新的Vision组并选择New File…。选择
    Swift File并将其命名为ContourDetector

    用下面的代码替换文件的内容:

    进口愿景
    
    类检测器{
      静态让共享=  ContourDetector ()
      
      所有权(){}
    }
    

    一个新的实例设置您的只是将ContourDetector设置为单例模式。确保中运行不是绝对必要的,但它只有ContourDetector在应用程序中的实例。

    执行视觉请求

    现在是时候让检测器类做点什么了。

    将以下属性添加到ContourDetector类:

    { Convar请求:VNDetecttoursRequest = 
      让 req =  VNDetectContoursRequest ()
      返回请求
    }()
    

    VNDetectContoursRequestSingleton结构还确保只有一个 Vision 请求,可以在应用程序的整个生命周期中重复使用。

    现在添加以下方法:

    函数执行(:VNRequest,
                         在图像上:CGImage)抛出 -> VNRequest {
       // 1
      让 requestHandler =  VNImageRequestHandler (cgImage: image, options: [:])
      
      // 2
      试用 requestHandler.perform([request])
      
      // 3
      回复请求
    }
    

    你在这里:方法简单但功能强大。

    1. 创建请求的处理程序并将其提交给提供CGImage
    2. 使用处理程序执行请求。
    3. 返回请求,现在已经附加了结果。

    为了使用请求的结果,您需要进行一些处理。在下面的上一个方法中,添加以下方法来处理返回的请求:

    func  postProcess ( request : VNRequest ) -> [ Contour ] {
       // 1守卫
      让结果= request.results 为?[ VNContoursObservation ] 其他{
        返回 []
      }
        
      // 2
      让 vnContours = results.flatMap { 姿态在
        ( 0 ..< contour.contourCount).compactMap {试试? } 轮廓.contour(at: $0 ) }
      }
          
      // 3
      返回 vnContours.map { Contour (vnContour: $0 ) }
    }
    

    在这种方法中,您:

    1. 检查结果是一个VNContoursObservation对象。
    2. 将每一个结果转换为的商品VNContour
      • flatMap将导致结果以各种方式计算。
      • contour在使用中简单的值以确保仅保留非零。compactMap
      • 检索contour(at:)索引指定处的可爱对象。
    3. 将目录映射VNContour到自定义Contour目录中。

    注意从的原因很容易发生一些转换VNContourSwiftUI的Contour代码。Contour因此Identifiable,相应的。查看ContoursView 。查看ContoursView。查看实际情况。

    在检测器中处理图像

    现在您只需要将这几种方法用于绑定到某个地方

    func 过程(图像:CGImage?)抛出-> [轮廓] {
      守卫让图像=图像否则{
        返回 []
      }
        
      let contourRequest =  try perform(request: request, on: image)
      返回 postProcess(请求:contourRequest)
    }
    

    在这里,您正在检查是否有图像,然后使用perform(request:on:)来创建请求,最后使用postProcess(request:)。这将您的图像视图模型将调用以使用轮廓的方法,这正是您接下来要做的。

    打开ContentViewModel.swift并在下面的方法中添加到类的方法:

    func  asyncUpdateContours () async -> [轮廓] {
      让检测器=  ContourDetector .shared
      返回(试用?检测器过程。(图像:self .image))?[]
    }
    

    在此代码中,您将通过一个异步方法来检测。但为什么是异步的?虽然检测到通常比较快,但您仍然不想在创建 API 调用时调用结果 UI。电视剧返回的方法是空空的。另外,透出警报,在这里添加了更多的逻辑,您将在这部剧中给您带来一个后果。]

    方法,你还需要从某个地方调用这个方法。updateContours

    函数更新轮廓(){
       // 1
      守卫!计算其他{返回}
      计算=真
      
      // 2
      任务{
        // 3让视线=等待
        asyncUpdateContours ()
        
        // 4 
        DispatchQueue .main.async {
           self .contours =风景
          自我计算=假
        }
      }
    }
    

    使用此代码,您可以:

    1. 如果已经在您计算头像,什么也不做。否则设置一个标志性指示以我们正在计算的通知。然后,用户界面将能够用户,因此他们也不要做原型。
    2. 创建一个大概需要这个运行的工具。对于工作来说是的。
    3. 启动检测方法并等待其结果。
    4. 由于都是已经发布的,因此只能在主线程上分配它们calculatingcontours``calculating

    此更新方法需要从以下地方调用,并且底部init任何地方都好init

    更新完美()
    

    现在正在构建和运行您的应用程序的时间。显示应用程序并看到后,单击程序以使用默认设置将其检测到的图像。

    04.png

    VNContoursObservation 和 VNContour

    在多个本文中,一个看起来从结果列表中VNDetectContoursObservation返回VNContoursObservation相反,您不会看到的所有观点(在上一个屏幕截图中共有 43 个)都由您完成VNContoursObservation

    注意:您编写的代码处理VNContoursObservation结果,以防 Apple 决定更改其工作方式。

    单独的画面由一个描述VNContour并按层次组织。一个VNContour可以有子视图要访问它们,您可以选择:选择:

    1. childContours属性,它是索引VNContour的索引。
    2. 结合使用childContourCount属性和childContour(at: Int)方法来循环访问对象。

    任何人VNContour都可以有任何孩子VNContour,如果您需要保留一个级别的信息,则必须让他们访问。

    如果您VNContoursObservation提供了一种数据属性和访问所有所有微笑的方法,VNContoursObservation就好像是平面结构一样。contourCount``contour(at: Int)

    如果您的头像结构对您很重要,您需要访问topLevelContours属性,它是一个VNContours。从那里,您可以访问各个头像的子轮廓。

    您编写的代码来计算笑脸和可爱子,会发现示例图像有 4 个要看起来像和下 39 个,如果有几个简单的设置 33 个。

    VNDetectContoursRequest 设置

    ,您已经创建了一个VNDetectContoursRequest没有对您启用的设置进行试验的。目前,您可以更改四个属性以实现不同的结果 -

    1. 对比该算法在执行前使能的暗暗调整图像调整组合的方法。调整范围调整范围会改变并减轻图像亮部它们的差异。以这个大的。以这个大的。从00到30的默认值。为 2.0 ,对这个值的值就比较合适了,确实更容易检测到一些图像。
    2. contrastPivot:算法如何如何的哪一个部分应该是被暗与亮?任何该将设定的值都将变暗,而确定此值的任何值都将变亮。您还可以将属性设置为“让Vision自动设置”的任何值。NSNumber``nil
    3. detectDarkOnLight布尔属性是对模特检测算法的提示,意味着true它应该在浅色背景上寻找这个场景。
    4. 最大图像尺寸:由于您可以将任何尺寸的图像提交给请求处理程序,因此允许图像属性设置使用的最大尺寸。如果您的图像的尺寸大于此值,API 会缩放图像,中值中这个处理maximumImageDimension的默认属性是512。 要更改它的检测能力?允许您根据需要改进此属性。

    改变信号

    现在您了解代码的设置,您将编写一些默认的来更改两种协议设置detectsDarkOnLight和可用的值。在本属性中,您将不会理会maximumImageDimension,只使用它们的值。

    打开ContourDetector.swift将以下方法添加到底部ContourDetector

    函数集(对比枢轴:CGFloat?) {
      request.contrastPivot = contrastPivot.map {
         NSNumber(价值:$0)
      }
    }
    
    函数集(调整:CGFloat) {
      request.stAdjustment =调整(对比度调整)
    }
    

    这些方法分别更改contrastPivotcontrastAdjustmentVNDetectContoursRequest并使用一些额外的逻辑来允许您设置contrastPivotnil

    您会记得它request是一个lazy var,这意味着如果在您调用这些方法时它还没有被实例化,那么它就是现在。

    ,打开ContentViewModel 。并找到输出asyncUpdateContours。更新方法,迅速看起来像这样:

    func  asyncUpdateContours () async -> [轮廓] {
      让检测器=  ContourDetector .shared
    
      // 新逻辑    
      检测器.set(手机轴5) : 0.
      检测器.set(调整调整:2.0)
        
      返回(试用?检测器过程。(图像:self .image))?[]
    }
    

    这是新行硬编码contrastPivot和的两个值contrastAdjustment

    并运行应用程序并为设置这些不同的值(需要更改这些值,然后为您制造不同的值并运行)。以下是制造这些值的一些截图:

    05.png 06.png 07.png 08.png

    ,,得到了一些有趣的结果。但是,有点令人烦恼的是,没有神奇的设置图像从它们中获取所有结果,然后你现在组合成一个结果。

    ……有一个解决方案但是。

    在项目中,可能点击了角的设置图标。如果您探索下它,请点击它,然后点击它,然后您会看到用于显示和主画面时您的最合适的选择。

    您将使用对这些图像中的所有对象,并将它们设置为更多设置创建它们。

    请注意:每个设置的范围,它运行的视觉请求都有很多。这可能是一个缓慢的过程,您使用非常有帮助,否则不建议在旧设备上使用较新的 iPhone、iPad 。和基于M1的Mac上运行良好。

    如果您还没有打开ContentViewModel.swift,请继续打开它。删除所有内容asyncUpdateContours并替换以下代码:

    // 1个
    微笑:[微笑] = []
    
    // 2
    让pivotStride =步幅(
      来自:UserDefaults .standard.minPivot,
      至:UserDefaults .standard.maxPivot,
      由:0.1 )
    让步幅=步幅(
      来自:UserDefaults .standard.minAdjust,
      至:UserDefaults .standard.maxAdjust,
      由:0.2 )
    
    // 3
    让检测器=  ContourDetector .shared
    
    // 4
    对于 pivotStride {
      调整调整步幅{
        
        // 5
        检测器.set(对比枢轴:枢轴)
        检测器.set(调整:调整)
        
        // 6
        让 newContours = ( try ? detector.process(image: self .image)) ?? []
        
        // 7
        风景.append(contentsOf:newContours)
      }
    }
    
    // 8
    返回 满意
    

    在这个新版本中asyncUpdateContours,您:

    1. 创建一个Contour很酷的名字。
    2. 设置contourPivotcontourAdjustment值循环遍历的步幅。
    3. 获取对ContourDetector单例的引用。
    4. 请注意,这是一个将每个循环的每个环节,通过每个步骤contourPivot与与价值。请注意contourAdjustment
    5. VNDetectContoursRequest使用您创建的访问器方法更改设置。
    6. 通过视觉图像检测器API运行。
    7. 将结果附加到Contour列表中并...
    8. 返回这个Contour列表。

    呸那是很多或,更改其会是值得的。继续制造并运行应用程序设置中的选项。通过关闭菜单列表后,外部开始点击重新计算设置外观。

    下面的屏幕截图中使用的范围是:

    • 双轴轴:0.2 -0.7
    • 亮度:0.5 - 3.0
    09.png

    细化微笑

    这是一个很酷的但是,你可以研究出更好的效果!

    你可能会注意到一些现在看起来很厚,而却很薄。

    如果您可以检测到重复的轮廓,您可以删除它们,这应该会看起来更细。

    确定它们两个不同但是否相同的一种方法是查看它们有多少重叠。并不是完全是 100% 准确的要简单,它是一个相对较快的您的近似值。确定重叠,可以计算它的相似框的交集。

    Intersection over union 或 IoU 是两个地方的交集形状除以他们的并集形状。

    10.png

    当 IoU 为 1.0 时,则任何地方。如果 IoU为 0.0,则两个边框之间没有重叠。

    你可以将它的类似价值来看起来像“附近”的地方。

    返回ContentViewModel.swiftasyncUpdateContours,在语句之前添加以下代码:return

    // 1
    低轮廓.count <  9000 {
       // 2
      让 iouThreshold =  UserDefaults .standard.iouThresh
      
      // 3
      肤色位置=  0
      而 pos <微笑.count {
         // 4
        微笑=肖像 [pos]
         // 5肖像
        =肖像[ 微笑... pos] +肖像 [(pos + 10 ) ... ]。筛选 {
          contour.intersectionOverUnion(with: $0 ) < iouThreshold
        }
        // 6 个
        位置+=  1
      }
    }
    

    使用此代码,您可以:

    1. 只是当我看着这整整9,000时运行。
    2. 可以在设置屏幕中的设置中更改。
    3. 您在此循环使用图标。while
    4. 指标精确度以获取精确度。
    5. 如果只保留您的当前头像头像,则如果她的头像像我一样。
    6. 增加索引位置。

    注意:可能有一种更有效的操作来完成这个,但这是解释这个概念最简单的方法。

    继续构建并运行应用程序。

    11.png

    注意有几分厚现在明显变薄了!

    凝视

    您可以另外使用一种技巧为您的头像艺术天赋。您可以添加头像。

    VNC有一个名字叫成员的方法polygonApproximation(epsilon:),它就是在上面的。这个方法的目的是返回一个相似点的相似的相似值。

    epsilon 的选择将最终返回蓝色的高度。

    打开 ContourDetector.swift。在的顶部ContourDetector,添加以下属性:

    属性 epsilon 数字:0 =  0.0
    

    在的底部ContourDetector,添加以下方法:

    函数集(epsilon:CGFloat
       )il on =数(epsilon)
    }
    

    仍然在同一个类中,找到方法底部的语句postProcess(request:)并将其替换为以下代码:return

    让Contours {
      试用?$0 .polygonApproximation(epsilon: self .epsilon)
    }
            
    返回的Contours { Contour (v) 的Contour: $0 }
    

    epsilon代码在返回之前,以当前的价值为目标。

    在试用此新功能之前,需要将 epsilon 设置连接到ContourDetector。您只需从设置您的屏幕写入UserDefaults的中位即可。

    打开ContentViewModel.swiftasyncUpdateContours再次找到。然后,在定义特征的行列下detector,添加以下行:

    检测器.set(epsilon:UserDefaults .standard.epsilon)
    

    这将确定检测器在epsilon需要更新时显示的最新值。

    一次,继续制造并运行

    12.png

    此示例将值 0.01 用于终止 Epsilon设置。

    结论

    您可以使用教程中的所有代码部分下载最终项目。

    这里也推荐一些面试相关的内容,祝各位网友都能拿到满意offer!
    GCD面试要点
    block面试要点
    Runtime面试要点
    RunLoop面试要点
    内存管理面试要点
    MVC、MVVM面试要点
    网络性能优化面试要点
    网络编程面试要点
    KVC&KVO面试要点
    数据存储面试要点
    混编技术面试要点
    设计模式面试要点
    UI面试要点

    相关文章

      网友评论

          本文标题:iOS视觉框架教程:轮廓检测

          本文链接:https://www.haomeiwen.com/subject/lkeaurtx.html