中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

大邑縣建設(shè)局網(wǎng)站深圳開發(fā)公司網(wǎng)站建設(shè)

大邑縣建設(shè)局網(wǎng)站,深圳開發(fā)公司網(wǎng)站建設(shè),電影網(wǎng)站開發(fā)java,電子書城網(wǎng)站開發(fā)項(xiàng)目概況目錄概述一、如何用Swift調(diào)用OpenCV庫1.項(xiàng)目引入OpenCV庫2.橋接OpenCV及Swift二、運(yùn)用AVFoundation獲取實(shí)時圖像數(shù)據(jù)1.建立視頻流數(shù)據(jù)捕獲框架2.建立 Capture Session3.取得并配置 Capture Devices4.設(shè)定 Device Inputs5.配置Video Data Output輸出6.工程隱私權(quán)限配置7.處理相機(jī)…

目錄

  • 概述
  • 一、如何用Swift調(diào)用OpenCV庫
    • 1.項(xiàng)目引入OpenCV庫
    • 2.橋接OpenCV及Swift
  • 二、運(yùn)用AVFoundation獲取實(shí)時圖像數(shù)據(jù)
    • 1.建立視頻流數(shù)據(jù)捕獲框架
    • 2.建立 Capture Session
    • 3.取得并配置 Capture Devices
    • 4.設(shè)定 Device Inputs
    • 5.配置Video Data Output輸出
    • 6.工程隱私權(quán)限配置
    • 7.處理相機(jī)視頻回調(diào)
  • 三、視頻流原始數(shù)據(jù)CMSampleBuffer處理
    • 1.CMSampleBuffer數(shù)據(jù)轉(zhuǎn)換為Mat數(shù)據(jù)
    • 2.回調(diào)中的數(shù)據(jù)處理
    • 3.Mat數(shù)據(jù)轉(zhuǎn)換為UIImage數(shù)據(jù)用于顯示
  • 四、Swift界面搭建
    • 1.在UI層捕獲相機(jī)數(shù)據(jù)
    • 2.直接顯示CMSampleBuffer方法
  • 五、基于Object-C++的OpenCV圖像處理部分
    • 1.引入頭文件
    • 2.OpenCV人臉識別輸出識別框
  • 總結(jié)


概述

在2020年6月9日之后,OpenCV可以直接在Objective-C和Swift中使用它,而無需自己編寫Objective-C++,可以直接在OpenCV官網(wǎng)下載iOS Package包,使用起來也是比較簡單。但由于之前對OpenCV庫的使用是使用C++編寫,所以O(shè)bjective-C++在圖像處理部分使用起來更順手,因此本文主要的技術(shù)框架是使用Objective-C++編寫圖像處理流程,Swift編寫iOS界面及AVFoundation相機(jī)等的調(diào)用以獲取實(shí)時的圖像數(shù)據(jù)。本文主要以實(shí)時框出人臉為示例,iOS移動端界面的顯示結(jié)果大致如下圖。

示例圖像
OpenCV官網(wǎng):https://opencv.org/releases/


一、如何用Swift調(diào)用OpenCV庫

1.項(xiàng)目引入OpenCV庫

  1. 使用cocoapods就非常簡單:
pod 'OpenCV'
  1. 自行手動添加:在官網(wǎng)下載相應(yīng)版本的iOS Pack,解壓后得到一個 opencv2.framework 庫,創(chuàng)建項(xiàng)目并右鍵添加文件到項(xiàng)目。

2.橋接OpenCV及Swift

  1. 前面說到OpenCV框架是用C++進(jìn)行編程的,因此要用Objective-C++代碼于Swift代碼進(jìn)行橋接。首先添加一個 Objective-C 文件到項(xiàng)目中,會彈出一個是否添加 Bridging-Header 文件,選擇添加(若此處沒彈出,則可以手動添加Bridging-Header 文件,即添加一個頭文件(Header file),重命名為“項(xiàng)目名-Bridging-Header.h”),這就實(shí)現(xiàn)了Swift和Object-C的混編。
  2. 將這個Object-C的文件擴(kuò)展名“.m”改為“.mm”這就將該文件變成了Objective-C++文件,文件大致如下

工程文件圖


二、運(yùn)用AVFoundation獲取實(shí)時圖像數(shù)據(jù)

Apple預(yù)設(shè)的APIs 如UIImagePickerController能夠直接獲取攝像頭獲取的圖像并顯示在界面上,操作簡單,但無法對原數(shù)據(jù)進(jìn)行操作,因此本文中應(yīng)用AVFoundation的 Capture Sessions來采集圖像和視頻流。根據(jù)官方文檔,Capture Session 是用以【管理采集活動、并協(xié)調(diào)來自 Input Devices 到采集 Outputs 的數(shù)據(jù)流】。在 AVFoundation 內(nèi),Capture Sessions 是由AVCaptureSession來管理的。

1.建立視頻流數(shù)據(jù)捕獲框架

首先創(chuàng)建一個NSObject類型的Controller名為CameraController,處理攝像頭的事務(wù),設(shè)置prepare函數(shù)以供主程序調(diào)用,其主要負(fù)責(zé)設(shè)立一個新的 Capture Session。設(shè)定 Capture Session 分為五個步驟:

  1. 建立一個 Capture Session
  2. 取得并配置 Capture Devices
  3. 在 Capture Device 上建立 Inputs
  4. 設(shè)置一個 Video Data Output 物件
  5. 配置Video Data Output Queue參數(shù)
func prepare(completionHandler: @escaping (Error?) -> Void) {//建立一個 Capture Sessionfunc createCaptureSession() { }//取得并配置 Capture Devicesfunc configureCaptureDevices() throws { }//在 Capture Device 上建立 Inputsfunc configureDeviceInputs() throws { }//設(shè)置一個 Video Data Output 物件func configureVideoDataOutput() throws { }//配置Video Data Output Queue參數(shù)func configureVideoDataOutputQueue() throws{ }DispatchQueue(label: "prepare").async {do {createCaptureSession()try configureCaptureDevices()try configureDeviceInputs()try configureVideoDataOutput()try configureVideoDataOutputQueue()}catch {DispatchQueue.main.async {completionHandler(error)}         return}DispatchQueue.main.async {completionHandler(nil)}}
}

2.建立 Capture Session

建立新的AVCaptureSession,并將它存儲在captureSession的屬性里,并設(shè)定一些用于拋出的錯誤類型

var captureSession: AVCaptureSession?func createCaptureSession() { self.captureSession = AVCaptureSession()
}//設(shè)定prepare過程中遇到的錯誤類型enum CameraControllerError: Swift.Error {case captureSessionAlreadyRunningcase captureSessionIsMissingcase inputsAreInvalidcase invalidOperationcase noCamerasAvailablecase unknown}//設(shè)定相機(jī)位置為前后相機(jī)public enum CameraPosition {case frontcase rear}

3.取得并配置 Capture Devices

建立了一個AVCaptureSession后,需要建立AVCaptureDevice物件來代表實(shí)際的相機(jī)

        //前置鏡頭var frontCamera: AVCaptureDevice?//后置鏡頭var rearCamera: AVCaptureDevice?func configureCaptureDevices() throws {//使用了AVCaptureDeviceDiscoverySession找出設(shè)備上所有可用的內(nèi)置相機(jī) (`.builtInDualCamera`)。//若沒找到相機(jī)則拋出異常。let session = AVCaptureDevice.DiscoverySession.init(deviceTypes: [AVCaptureDevice.DeviceType.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .unspecified)           let cameras = session.devices.compactMap { $0 }guard !cameras.isEmpty else { throw CameraControllerError.noCamerasAvailable }//遍歷前面找到的可用相機(jī),分辨出前后相機(jī)。//然后,將該相機(jī)設(shè)定為自動對焦,遇到任何問題也會拋出異常。for camera in cameras {if camera.position == .front {self.frontCamera = camera}if camera.position == .back {self.rearCamera = cameratry camera.lockForConfiguration()camera.focusMode = .continuousAutoFocuscamera.unlockForConfiguration()}}}

4.設(shè)定 Device Inputs

var currentCameraPosition: CameraPosition?
var frontCameraInput: AVCaptureDeviceInput?
var rearCameraInput: AVCaptureDeviceInput?func configureDeviceInputs() throws {//確認(rèn)`captureSession`是否存在,若不存在拋出異常guard let captureSession = self.captureSession else { throw CameraControllerError.captureSessionIsMissing }//建立所需的 Capture Device Input 來進(jìn)行數(shù)據(jù)采集。//`AVFoundation`每一次 Capture Session 僅能允許一臺相機(jī)輸入。//由于裝置的初始設(shè)定為后相相機(jī)。先嘗試用后相機(jī) Input,再加到 Capture Session;if let rearCamera = self.rearCamera {self.rearCameraInput = try AVCaptureDeviceInput(device: rearCamera)if captureSession.canAddInput(self.rearCameraInput!) { captureSession.addInput(self.rearCameraInput!) }self.currentCameraPosition = .rear}//嘗試建立前相機(jī)Input   else if let frontCamera = self.frontCamera {self.frontCameraInput = try AVCaptureDeviceInput(device: frontCamera)if captureSession.canAddInput(self.frontCameraInput!) { captureSession.addInput(self.frontCameraInput!) }else { throw CameraControllerError.inputsAreInvalid }self.currentCameraPosition = .front}else { throw CameraControllerError.noCamerasAvailable }
}

5.配置Video Data Output輸出

        var videoOutput: AVCaptureVideoDataOutput?//配置相機(jī)的視頻輸出,并開始func configureVideoDataOutput() throws {guard let captureSession = self.captureSession else { throw CameraControllerError.captureSessionIsMissing }self.videoOutput = AVCaptureVideoDataOutput()if captureSession.canAddOutput(self.videoOutput!) { captureSession.addOutput(self.videoOutput!) }captureSession.startRunning()}//配置視頻的輸出代理及輸出格式func configureVideoDataOutputQueue() throws{let videoDataOutputQueue = DispatchQueue(label: "videoDataOutputQueue")self.videoOutput!.setSampleBufferDelegate(self, queue: videoDataOutputQueue)self.videoOutput!.alwaysDiscardsLateVideoFrames = falselet BGRA32PixelFormat = NSNumber(value: Int32(kCVPixelFormatType_32BGRA))let rgbOutputSetting = [kCVPixelBufferPixelFormatTypeKey.string : BGRA32PixelFormat]self.videoOutput!.videoSettings = rgbOutputSetting}

6.工程隱私權(quán)限配置

根據(jù)Apple 規(guī)定的安全性要求,必須提供一個app使用相機(jī)權(quán)限的原因。在工程的Info.plist,加入下圖的設(shè)置:

相機(jī)權(quán)限設(shè)置

7.處理相機(jī)視頻回調(diào)

能夠從下方的回調(diào)中得到相機(jī)返回的實(shí)時數(shù)據(jù),格式為CMSampleBuffer,該視頻流格式不止包含圖像信息還包含時間戳信息等,若想通過opencv進(jìn)行處理還需進(jìn)行數(shù)據(jù)轉(zhuǎn)換。

extension CameraController: AVCaptureVideoDataOutputSampleBufferDelegate{func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {}
}

參考地址:https://www.appcoda.com.tw/avfoundation-camera-app/


三、視頻流原始數(shù)據(jù)CMSampleBuffer處理

1.CMSampleBuffer數(shù)據(jù)轉(zhuǎn)換為Mat數(shù)據(jù)

OpenCV提供了UIImageToMat的函數(shù),根據(jù)這個思路,我們應(yīng)當(dāng)將CMSampleBuffer轉(zhuǎn)換為UIImage數(shù)據(jù),CMSsampleBuffer不止包含ImageBuffer,通過API自帶的CMSampleBufferGetImageBuffer(),可以得到與我們希望得到的圖像數(shù)據(jù)更為接近的cvPixelBuffer。

總的來說,下方是CMSampleBuffer轉(zhuǎn)換為UIImage的兩種方式,第一種通過CIImage第二種通過CGImage,通過CIImage轉(zhuǎn)換成的UIImage雖然能顯示在UIImageVIew上,但是在轉(zhuǎn)換成Mat格式的時候會報錯,因此選用第二種通過CGImage的轉(zhuǎn)換。最后調(diào)用opencv庫的UIImageToMat函數(shù)便能得到Mat數(shù)據(jù)了。

    func image(orientation: UIImage.Orientation = .up, scale: CGFloat = 1.0) -> UIImage? {if let buffer = CMSampleBufferGetImageBuffer(self) {let ciImage = CIImage(cvPixelBuffer: buffer)return UIImage(ciImage: ciImage, scale: scale, orientation: orientation)}return nil}func imageWithCGImage(orientation: UIImage.Orientation = .up, scale: CGFloat = 1.0) -> UIImage? {if let buffer = CMSampleBufferGetImageBuffer(self) {let ciImage = CIImage(cvPixelBuffer: buffer)let context = CIContext(options: nil)guard let cg = context.createCGImage(ciImage, from: ciImage.extent) else {return nil}           return UIImage(cgImage: cg, scale: scale, orientation: orientation)}return nil}

2.回調(diào)中的數(shù)據(jù)處理

這邊選用的方案是UIImageView來顯示原始圖像,并且在UIImageView上添加一個蒙層圖像來顯示識別框。此處選用蒙層的原因是,圖像處理每幀需要70ms的處理時間,若直接顯示處理后的圖片會有延遲丟幀的情況視覺效果較差,因此實(shí)時圖像采用原始圖像數(shù)據(jù),而識別框丟幀并不影響視覺效果。

   //回調(diào)原始圖像var videoCpatureCompletionBlock: ((UIImage) -> Void)?//回調(diào)CMSsmapleBuffer圖像var videoCaptureCompletionBlockCMS: ((CMSampleBuffer)-> Void)?//回調(diào)蒙層圖像var videoCaptureCompletionBlockMask: ((UIImage) -> Void)?//用于記錄幀數(shù)var frameFlag : Int = 0//用于給異步線程加鎖var lockFlagBool : Bool = falsefunc captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {if let image = sampleBuffer.imageWithCGImage(orientation: .up, scale: 1.0){self.frameFlag = self.frameFlag + 1var output = imageif(self.frameFlag != -1){self.videoCaptureCompletionBlockCMS?(sampleBuffer)self.videoCpatureCompletionBlock?(output)if(self.lockFlagBool == false){//此處必須開線程處理,否則會報錯DispatchQueue.global().async {lockFlagBool = truevar output = image//addimageProcess為opencv圖像處理過程,寫在Objecj-C++文件中,本文后面記錄output = opencv_test.addimageProcess(output)self.videoCaptureCompletionBlockMask?(output)lockFlagBool = false}}}else{print("丟幀")self.frameFlag = 0}}}

3.Mat數(shù)據(jù)轉(zhuǎn)換為UIImage數(shù)據(jù)用于顯示

為了最后能用于顯示,還要轉(zhuǎn)換為UImage,該部分很簡單,直接調(diào)用OpenCV的庫函數(shù),當(dāng)然如果想轉(zhuǎn)換為CMSampleBuffer的話還需要重新添加丟失的數(shù)據(jù),比如時間戳。

MatToUIImage()

參考地址:https://stackoverflow.com/questions/15726761/make-an-uiimage-from-a-cmsamplebuffer


四、Swift界面搭建

1.在UI層捕獲相機(jī)數(shù)據(jù)

UI界面的操作比較簡單,實(shí)例化之前的CameraController類,并設(shè)定configureCameraController函數(shù)來調(diào)用類中的prepare函數(shù),以及接受回調(diào)的圖像數(shù)據(jù),這些回調(diào)對UIImageView的圖像刷新必須要在主線程中,否則會報錯。其中,selfImageView和maskImageView是兩個自己創(chuàng)建的UImageView來顯示UIImage圖像的,這兩個UIImageView要保持在同樣位置同樣大小。

    let cameraController = CameraController()override func viewDidLoad() {configureCameraController() }func configureCameraController() {cameraController.prepare {(error) inif let error = error {print(error)}self.cameraController.videoCpatureCompletionBlock = { image inDispatchQueue.main.async {self.selfImageView.image = image}}self.cameraController.videoCaptureCompletionBlockMask = { image inDispatchQueue.main.async {self.maskImageView.image = image}}//直接顯示CMSampleBuffer的方法// self.cameraController.videoCaptureCompletionBlockCMS = { CMSampleBuffer in//self.displayLayer.enqueue(CMSampleBuffer)//}}}

2.直接顯示CMSampleBuffer方法

其實(shí)蘋果的API也提供了直接顯示CMSampleBuffer的簡單方法,通過AVSampleBufferDisplayLayer以及其.enqueue方法,其展示方式如下:

var displayLayer:AVSampleBufferDisplayLayer!override func viewDidLoad() {displayLayer = AVSampleBufferDisplayLayer()displayLayer.videoGravity = .resizeAspect     self.imageView.layer.addSublayer(displayLayer)self.displayLayer.frame.origin.y = self.imageView.frame.origin.yself.displayLayer.frame.origin.x = self.imageView.frame.origin.x}func configureCameraController() {cameraController.prepare {(error) inif let error = error {print(error)}//直接顯示CMSampleBuffer的方法self.cameraController.videoCaptureCompletionBlockCMS = { CMSampleBuffer inself.displayLayer.enqueue(CMSampleBuffer)}}}

五、基于Object-C++的OpenCV圖像處理部分

1.引入頭文件

這部分用C++編寫過OpenCV的都相當(dāng)熟悉了,在.mm文件中引入以下頭文件,并引入命名空間,若該部分找不到文件應(yīng)當(dāng)確認(rèn)是否已正確安裝OpenCV庫。

#import <opencv2/opencv.hpp>
#import "opencv-test.h"
#import <opencv2/imgcodecs/ios.h>//對iOS支持
#import <opencv2/imgcodecs/ios.h>
//導(dǎo)入矩陣幫助類
#import <opencv2/highgui.hpp>
#import <opencv2/core/types.hpp>
#import <iostream>using namespace std;
using namespace cv;@implementation opencv_test//各類處理函數(shù)
@end

2.OpenCV人臉識別輸出識別框

本文使用了OpenCV自帶的人臉識別框架CascadeClassifier,將得到的人臉坐標(biāo)放入vector中,最后繪制在蒙層上,最后輸出蒙層圖片。其它對于圖像的處理也可以用相同的方式處理,在參考資料中有馬賽克操作。

+(UIImage*)addimageProcess:(UIImage*)image {//用于記錄時間CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();Mat src;//將iOS圖片->OpenCV圖片(Mat矩陣)UIImageToMat(image, src);Mat src_gray;//圖像灰度化cvtColor(src, src_gray, COLOR_RGBA2GRAY, 1);std::vector<cv::Rect> faces;//初始化OpenCV的人臉識別檢測器CascadeClassifier faceDetector;//獲取權(quán)重文件,文件需要提前導(dǎo)入至工程目錄中NSString* cascadePath = [[NSBundle mainBundle]pathForResource:@"haarcascade_frontalface_alt"ofType:@"xml"];//配置檢測器faceDetector.load([cascadePath UTF8String]);faceDetector.detectMultiScale(src_gray, faces, 1.1,2, 0|CASCADE_SCALE_IMAGE, cv::Size(30, 30));//確定圖像寬高int width = src.cols;int height = src.rows;//Mat Mask = Mat::zeros(width, height, CV_8UC4);//創(chuàng)建透明蒙層圖像 Scalar(0,0,0,0) 分別是RGBA A為透明度Mat Mask = Mat(height, width, CV_8UC4, Scalar(0,0,0,0));// Draw all detected facesfor(unsigned int i = 0; i < faces.size(); i++){const cv::Rect& face = faces[i];// Get top-left and bottom-right corner pointscv::Point tl(face.x, face.y);cv::Point br = tl + cv::Point(face.width, face.height);// Draw rectangle around the faceScalar magenta = Scalar(0, 255, 0, 255);cv::rectangle(Mask, tl, br, magenta, 4, 8, 0);}//打印處理時間CFAbsoluteTime endTime = (CFAbsoluteTimeGetCurrent() - startTime);NSLog(@"normalProcess方法耗時: %f ms", endTime * 1000.0);return MatToUIImage(Mask);
}

參考資料:https://www.twblogs.net/a/5b830b452b717766a1eadb20/?lang=zh-cn


總結(jié)

遇到的困難:一是在于方案中用UIImageView來進(jìn)行顯示,必須在主線程中進(jìn)行渲染,對于線程的處理相對繁瑣,若是處理不得當(dāng)便會有延時丟幀不刷新等的問題。
存在的問題:OpenCV自帶的人臉識別算法比較老舊,處理速度也比較慢效果也一般,要引入其他神經(jīng)網(wǎng)絡(luò)框架在客戶端上的可行性有待討論,處理速度也未知。

另外,若有需要總的工程文件的可以私聊我。

http://www.risenshineclean.com/news/22585.html

相關(guān)文章:

  • 政府職能網(wǎng)站建設(shè)seo門戶網(wǎng)價格是多少錢
  • 設(shè)計(jì)本官方網(wǎng)站下載如何設(shè)計(jì)網(wǎng)站
  • 開網(wǎng)站賺50萬做百度指數(shù)官方下載
  • 網(wǎng)站項(xiàng)目建設(shè)方案河南網(wǎng)絡(luò)推廣那家好
  • 大連三合一網(wǎng)站制作百度快照收錄入口
  • WordPress命令執(zhí)行漏洞搜索引擎優(yōu)化簡稱seo
  • 網(wǎng)站推廣優(yōu)化技巧大全優(yōu)化推廣方案
  • 免費(fèi)建網(wǎng)站 步驟寧波企業(yè)網(wǎng)站seo
  • 上海市建設(shè)人才網(wǎng)站鄭州網(wǎng)站優(yōu)化推廣
  • 網(wǎng)站響應(yīng)式技術(shù)蘇州關(guān)鍵詞優(yōu)化排名推廣
  • 國外網(wǎng)站空間需要備案嗎鄭州seo優(yōu)化外包熱狗網(wǎng)
  • 樂清建設(shè)路小學(xué)校園網(wǎng)站在廣州做seo找哪家公司
  • survive制作公司重慶電子商務(wù)seo
  • 做交友網(wǎng)站賺錢嗎免費(fèi)進(jìn)入b站2022年更新
  • 怎么做代購上那個網(wǎng)站抖音自動推廣引流app
  • 梧州推廣網(wǎng)站服務(wù)商優(yōu)化大師的功能有哪些
  • 做的網(wǎng)站為什么看不到圖片魔方優(yōu)化大師官網(wǎng)下載
  • wordpress簡潔seo是什么工作內(nèi)容
  • 網(wǎng)上購物最便宜的網(wǎng)站愛站網(wǎng)長尾關(guān)鍵詞搜索
  • 給企業(yè)建設(shè)網(wǎng)站的流程圖網(wǎng)絡(luò)服務(wù)器的作用
  • 軟件設(shè)計(jì)專業(yè)優(yōu)化品牌seo關(guān)鍵詞
  • 沈北新區(qū)建設(shè)局網(wǎng)站搜索引擎優(yōu)化的英語簡稱
  • 網(wǎng)站開發(fā)使用軟件有哪些如何創(chuàng)造一個自己的網(wǎng)站
  • 如何做網(wǎng)站代理如何制作網(wǎng)站賺錢
  • 聚誠商務(wù)做網(wǎng)站多少錢中國聯(lián)通騰訊
  • 京東上怎樣做網(wǎng)站網(wǎng)推公司
  • 企業(yè)名稱的英文做網(wǎng)站名中小企業(yè)管理培訓(xùn)課程
  • 如何做html網(wǎng)站網(wǎng)絡(luò)營銷服務(wù)外包
  • 域名備案網(wǎng)站要不要關(guān)湖北seo
  • 政府網(wǎng)站app建設(shè)seo網(wǎng)站設(shè)計(jì)工具