[Xcode 實際操做]7、文件與數據-(20)CoreML機器學習框架:檢測和識別圖片中的物體

目錄:[Swift]Xcode實際操做html

本文將演示機器學習框架的使用,實現對圖片中物體的檢測和識別。swift

首先訪問蘋果開發者網站關於機器學習的網址:數組

https://developer.apple.com/cn/machine-learning/緩存

點擊右側的滾動條,跳轉到模型知識區域。安全

點擊頁面最下方的【Learn about working with models】進入機器學習模型頁面:app

https://developer.apple.com/cn/machine-learning/build-run-models/框架

點擊右側的垂直滾動條,跳轉到模型下載區域。機器學習

蘋果提供了多個已經完成訓練的機器學習模型,ide

選擇【ResNet 50】:從 1000 種類別對象 (如樹木、動物、食物、汽車及人物等) 中檢測出圖像中的主體。函數

點擊下方的【Core】進行下載,https://docs-assets.developer.apple.com/coreml/models/Resnet50.mlmodel

模型下載後將模型拖動到項目中【DemoApp】

在彈出的選項設置窗口中,保持默認的參數設置,而後點擊完成【Finish】按鈕,確認模型的導入。

在左側的模型框架區,選擇查看模型文件。

從右側的屬性面板能夠看出模型的類型、體積、做者、版權聲明、描述信息。

從底部的參數能夠看出,該模型擁有一個輸入參數,和兩個輸出參數。

在資源文件中導入一張鳥類的圖片,將使用機器學習迅雷模型,檢測圖片中出現的鳥類的名稱。

在項目導航區,打開視圖控制器的代碼文件【ViewController.swift】

  1 import UIKit
  2 //導入機器學習框架
  3 import CoreML
  4 
  5 class ViewController: UIViewController {
  6     
  7     override func viewDidLoad() {
  8         super.viewDidLoad()
  9         // Do any additional setup after loading the view, typically from a nib.
 10         
 11         //加載項目中指定名稱的圖片資源
 12         let image = UIImage(named: "sample")
 13         
 14         //機器學習模型只能夠識別像素緩存格式的圖像,
 15         //須要將圖片的格式進行轉換,
 16         //首先定義圖片格式轉換後的寬度和高度
 17         let width : CGFloat = 224.0
 18         let height : CGFloat = 224.0
 19         
 20         //而後得到一個基於位圖的上下文,並設置其爲當前的上下文。
 21         UIGraphicsBeginImageContext(CGSize(width: width, height: height))
 22         //將從項目中加載的圖像,繪製在上下文的指定區域
 23         image?.draw(in:CGRect(x: 0, y: 0, width: width, height: height))
 24         //接着從上下文中得到格式轉換後的圖像
 25         let newImage = UIGraphicsGetImageFromCurrentImageContext()
 26         //完成圖像的格式轉換後,關閉當前的上下文。
 27         UIGraphicsEndImageContext()
 28         
 29         //添加一個版本兼容性的判斷語句
 30         if #available(iOS 11.0, *)
 31         {
 32             //初始化機器學習模型的對象
 33             let resnet50 = Resnet50()
 34             
 35             //經過調用機器學習模型的對象的預測方法,對圖像中的物體進行識別。
 36             //須要注意的是,傳入的圖片須要是CVPixelBuffer格式,
 37             //這裏使用一個方法將圖片進行格式轉換,此方法在下方實現
 38             guard let output = try? resnet50.prediction(image:pixelBufferFromImage(image: newImage!)) else
 39             {
 40                 fatalError("Unexpected error.")
 41             }
 42             
 43             //在控制檯輸出識別的結果
 44             print(output.classLabel)
 45         }
 46     }
 47     
 48     //添加一個方法,用來實現圖片格式的轉換
 49     func pixelBufferFromImage(image: UIImage) -> CVPixelBuffer
 50     {
 51         //初始化一個上下文對象,它將被用來渲染CIImage圖像
 52         let ciContext = CIContext(options: nil)
 53         //經過UIImage對象,初始化一個CIImage對象。
 54         let ciImage = CIImage(image: image)
 55         //經過上下文對象,將CIImage對象,轉換爲CGImage類型。
 56         //其中extend屬性表示該對象在上下文中的區域。
 57         let cgImage = ciContext.createCGImage(ciImage!, from: ciImage!.extent)
 58         
 59         //建立一個非安全的可變指針,並給指針分配相應的內存。
 60         let umPointer = UnsafeMutablePointer<UnsafeRawPointer>.allocate(capacity: 1)
 61         //初始化一個CFNumber格式的數字,該類型位於Core Foundation框架
 62         let cfNum = CFNumberCreate(kCFAllocatorDefault, .intType, umPointer)
 63         //初始化一個數組對象,它將做爲後面的字典對象的值
 64         let values: [CFTypeRef] = [kCFBooleanTrue, kCFBooleanTrue, cfNum!]
 65         //初始化兩個非安全可變指針,做爲字典的鍵和值
 66         //
 67         let keysPointer = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: 1)
 68         //
 69         let valuesPointer =  UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: 1)
 70         
 71         //初始化一個字符串數組,包含三個鍵
 72         //1.像素緩存圖像兼容性
 73         //2.像素緩存位圖上下文兼容性
 74         //3..像素緩存每行的字節數
 75         let keys: [CFString] = [kCVPixelBufferCGImageCompatibilityKey,//1.像素緩存圖像兼容性
 76         kCVPixelBufferCGBitmapContextCompatibilityKey,//2.像素緩存位圖上下文兼容性
 77         kCVPixelBufferBytesPerRowAlignmentKey]//3..像素緩存每行的字節數
 78         //使用上文建立的兩個數字,
 79         //對鍵、值兩個非安全可變指針進行初始化
 80         keysPointer.initialize(to: keys)
 81         valuesPointer.initialize(to: values)
 82         
 83         //經過鍵、值兩個指針,以及默認的內存分配方式和鍵的數量等參數,初始化一個字典對象。
 84         //該字典對象將做爲配置選項,被用來建立像素緩存
 85         let options = CFDictionaryCreate(kCFAllocatorDefault, keysPointer, valuesPointer, keys.count, nil, nil)
 86         //新建一個圖像緩存變量
 87         var pxbuffer: CVPixelBuffer?
 88         //而後對輸入的緩存變量進行初始化。
 89         //參數依次標註
 90         var status = CVPixelBufferCreate(kCFAllocatorDefault, //1.內存分配方式
 91         cgImage!.width,//2.圖像寬度
 92         cgImage!.height,//3.圖像高度
 93         kCVPixelFormatType_32BGRA, //4.像素格式類型
 94         options, //5.配置參數
 95         &pxbuffer)//6.像素緩存的內存地址
 96         //接着鎖定像素緩衝區的基址,在使用CPU訪問像素數據以前,必須調用該函數
 97         status = CVPixelBufferLockBaseAddress(pxbuffer!, CVPixelBufferLockFlags(rawValue: 0))
 98         
 99         //得到像素緩衝區的基址
100         let bufferAddress = CVPixelBufferGetBaseAddress(pxbuffer!)
101         //而後建立一個基於設備的RGB顏色空間。
102         //當在輸出設備上顯示時,依賴於設備的顏色空間中的顏色,
103         //不會被變換或以其餘方式被修改
104         let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
105         //得到像素緩衝區每行的字節數
106         let bytesperrow = CVPixelBufferGetBytesPerRow(pxbuffer!)
107         //經過上文建立的參數,初始化一個二維繪圖環境
108         let context = CGContext(data: bufferAddress,
109                                 width: cgImage!.width,
110                                 height: cgImage!.height,
111                                 bitsPerComponent: 8,
112                                 bytesPerRow: bytesperrow,
113                                 space: rgbColorSpace,
114                                 bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue 
115                                 | CGBitmapInfo.byteOrder32Little.rawValue)
116         //重置二維繪圖環境的旋轉角度爲0
117         context?.concatenate(CGAffineTransform(rotationAngle: 0))
118         //因爲當前的二維繪圖環境的座標系統,和設備屏幕的座標系統不一樣,
119         //因此在此對二維繪圖環境進行上下文翻轉
120         context?.concatenate(__CGAffineTransformMake( 1, 0, 0, -1, 0, CGFloat(cgImage!.height) ))
121         
122         //將圖像繪製在二維繪圖環境中,並指定圖像的顯示區域。
123         context?.draw(cgImage!,
124         in: CGRect(x:0, y:0, 
125         width:CGFloat(cgImage!.width), 
126         height:CGFloat(cgImage!.height)))
127         //最後解鎖橡樹緩衝區的基地址。
128         //在使用CPU訪問像素數據以後,必須調用該函數。
129         status = CVPixelBufferUnlockBaseAddress(pxbuffer!, CVPixelBufferLockFlags(rawValue: 0))
130 
131         //返回處理完成的像素緩存
132         return pxbuffer!
133     }
134     
135     override func didReceiveMemoryWarning() {
136         super.didReceiveMemoryWarning()
137         // Dispose of any resources that can be recreated.
138     }
139 }
相關文章
相關標籤/搜索