一、本文主要涉及到opencv的視頻幀抓拍和驗證的相關問題,不包含如何集成opencvios
二、主要講解涉及到opencv中的關鍵類及一些經常使用的方法git
三、着重講解代理方法:github
- (void)processImage:(cv::Mat &)image
四、集成過程當中的注意事項async
五、附上抓拍的小demo的下載地址ide
六、擴展,驗證抓拍的圖片中是否包含人臉學習
=====================================分割線==========================================
如下爲正文this
1、集成opencv須要添加的framework和靜態庫atom
2、OpenCV使用過程當中的關鍵類及一些經常使用的方法spa
一、cap_ios.h、如下爲此類的原始代碼代理
/* For iOS video I/O * by Eduard Feicho on 29/07/12 * Copyright 2012. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #import <UIKit/UIKit.h> #import <Accelerate/Accelerate.h> #import <AVFoundation/AVFoundation.h> #import <ImageIO/ImageIO.h> #include "opencv2/core.hpp" //! @addtogroup videoio_ios //! @{ /////////////////////////////////////// CvAbstractCamera ///////////////////////////////////// @class CvAbstractCamera; CV_EXPORTS @interface CvAbstractCamera : NSObject { UIDeviceOrientation currentDeviceOrientation; BOOL cameraAvailable; } @property (nonatomic, strong) AVCaptureSession* captureSession; @property (nonatomic, strong) AVCaptureConnection* videoCaptureConnection; @property (nonatomic, readonly) BOOL running; @property (nonatomic, readonly) BOOL captureSessionLoaded; @property (nonatomic, assign) int defaultFPS; @property (nonatomic, readonly) AVCaptureVideoPreviewLayer *captureVideoPreviewLayer; @property (nonatomic, assign) AVCaptureDevicePosition defaultAVCaptureDevicePosition; @property (nonatomic, assign) AVCaptureVideoOrientation defaultAVCaptureVideoOrientation; @property (nonatomic, assign) BOOL useAVCaptureVideoPreviewLayer; @property (nonatomic, strong) NSString *const defaultAVCaptureSessionPreset; @property (nonatomic, assign) int imageWidth; @property (nonatomic, assign) int imageHeight; @property (nonatomic, strong) UIView* parentView; - (void)start; - (void)stop; - (void)switchCameras; - (id)initWithParentView:(UIView*)parent; - (void)createCaptureOutput; - (void)createVideoPreviewLayer; - (void)updateOrientation; - (void)lockFocus; - (void)unlockFocus; - (void)lockExposure; - (void)unlockExposure; - (void)lockBalance; - (void)unlockBalance; @end ///////////////////////////////// CvVideoCamera /////////////////////////////////////////// @class CvVideoCamera; CV_EXPORTS @protocol CvVideoCameraDelegate <NSObject> #ifdef __cplusplus // delegate method for processing image frames - (void)processImage:(cv::Mat&)image; #endif @end CV_EXPORTS @interface CvVideoCamera : CvAbstractCamera<AVCaptureVideoDataOutputSampleBufferDelegate> { AVCaptureVideoDataOutput *videoDataOutput; dispatch_queue_t videoDataOutputQueue; CALayer *customPreviewLayer; CMTime lastSampleTime; } @property (nonatomic, weak) id<CvVideoCameraDelegate> delegate; @property (nonatomic, assign) BOOL grayscaleMode; @property (nonatomic, assign) BOOL recordVideo; @property (nonatomic, assign) BOOL rotateVideo; @property (nonatomic, strong) AVAssetWriterInput* recordAssetWriterInput; @property (nonatomic, strong) AVAssetWriterInputPixelBufferAdaptor* recordPixelBufferAdaptor; @property (nonatomic, strong) AVAssetWriter* recordAssetWriter; - (void)adjustLayoutToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; - (void)layoutPreviewLayer; - (void)saveVideo; - (NSURL *)videoFileURL; - (NSString *)videoFileString; @end ///////////////////////////////// CvPhotoCamera /////////////////////////////////////////// @class CvPhotoCamera; CV_EXPORTS @protocol CvPhotoCameraDelegate <NSObject> - (void)photoCamera:(CvPhotoCamera*)photoCamera capturedImage:(UIImage *)image; - (void)photoCameraCancel:(CvPhotoCamera*)photoCamera; @end CV_EXPORTS @interface CvPhotoCamera : CvAbstractCamera { AVCaptureStillImageOutput *stillImageOutput; } @property (nonatomic, weak) id<CvPhotoCameraDelegate> delegate; - (void)takePicture; @end //! @} videoio_ios
以上方法從名知意,且命名簡潔明瞭,無需過多的註釋說明 ,此爲值得我等ITboy學習和觀摩的地方
二、關鍵方法說明
此處不對CvPhotoCamera作說明,主要針對 CvVideoCameraDelegate 的代理方法進行說明
- (void)processImage:(cv::Mat&)image;
此方法視頻幀的抓取代理,其中的image對象爲非正常的RGB對象,爲一個灰度對象,在使用過程當中,須要進行色值的轉換
- (void)processImage:(cv::Mat &)image { cv::Mat outCopyImg; image.copyTo(outCopyImg); cv::cvtColor(outCopyImg, outCopyImg, CV_BGR2RGB); //此處說明:cv::cvtColor爲顏色轉換方法,最後一個參數即爲咱們經常使用的RGB色值 if ([self whetherTheImageBlurry:image]) {
//此爲一個清晰度的驗證,也是來自於網上的摘錄,下方會貼出代碼 [self.videoCamera stop]; keepMatImg = outCopyImg; if (isNeedToCut == YES) { CGFloat mianW = UIScreen.mainScreen.bounds.size.width; CGFloat NH = mianW * 1920 / 1080; cv::Rect rect(0,(1920 - NH)/2,1080,NH); cv::Mat image_roi = outCopyImg(rect); self.keepImageAlive = MatToUIImage(image_roi);
//說明:網上有不少將cv::Mat類型的數據轉換爲UIimage的方法 ,可是OpenCV自己就提供了此方法 MatToUIImage(),因此此處再也不引用其餘方法 }else{ self.keepImageAlive = MatToUIImage(outCopyImg); } NSLog(@"keepImageAlive.size = %@",NSStringFromCGSize(self.keepImageAlive.size)); dispatch_async(dispatch_get_main_queue(), ^{ if (self.keepImageAlive) { self.fuzzyText.text = @"清晰"; self.resultImageView.image = self.keepImageAlive; self.resultImageView.hidden = NO; } }); }else{ dispatch_sync(dispatch_get_main_queue(), ^{ self.fuzzyText.text = @"模糊"; }); } }
三、清晰度的驗證的方法
- (BOOL)whetherTheImageBlurry:(cv::Mat)mat{ unsigned char *data; int height,width,step; int Iij; double Iave = 0, Idelta = 0; // cv::Mat mat = [OpenCVExtension cvMatFromUIImage:image]; if(!mat.empty()){ cv::Mat gray; cv::Mat outGray; // 將圖像轉換爲灰度顯示 cv::cvtColor(mat,gray,CV_RGB2GRAY); cv::Laplacian(gray, outGray, gray.depth()); // cv::convertScaleAbs( outGray, outGray ); IplImage ipl_image(outGray); data = (uchar*)ipl_image.imageData; height = ipl_image.height; width = ipl_image.width; step = ipl_image.widthStep; for(int i=0;i<height;i++) { for(int j=0;j<width;j++) { Iij = (int) data [i*width+j]; Idelta = Idelta + (Iij-Iave)*(Iij-Iave); } } Idelta = Idelta/(width*height); std::cout<<"矩陣方差爲:"<<Idelta<<std::endl; } return (Idelta > IdeltaCount) ? YES : NO; }
demo下載地址:https://tianlin106@github.com/tianlin106/OpencvAutoTakeImage.git
3、人臉識別的擴展- (void)processImage:(cv::Mat &)image
{ cv::Mat outCopyImg; image.copyTo(outCopyImg); cv::cvtColor(outCopyImg, outCopyImg, CV_BGR2RGB); if ([self isPhotoContainsFeature:MatToUIImage(outCopyImg)]) { if ([self isPhotoIsBrightness:image] == YES) { [self disposeCamare]; keepMatImg = outCopyImg; UIImage * resultImage = MatToUIImage(outCopyImg); //須要上傳 [self uploadImage:resultImage]; dispatch_async(dispatch_get_main_queue(), ^{ [self.imageView removeFromSuperview]; }); } } } - (BOOL)isPhotoContainsFeature:(UIImage *)image{ CIContext * context = [CIContext contextWithOptions:nil]; NSDictionary * param = [NSDictionary dictionaryWithObject:CIDetectorAccuracyHigh forKey:CIDetectorAccuracy]; CIDetector * faceDetector = [CIDetector detectorOfType:CIDetectorTypeFace context:context options:param]; //此類爲Core Image Framework 中的類 ,主要用於識別某些外貌特性,如下語言爲其API的描述
//An image processor that identifies notable features (such as faces and barcodes) in a still image or video.
CIImage * ciimage = [CIImage imageWithCGImage:image.CGImage]; NSArray * detectResult = [faceDetector featuresInImage:ciimage]; return detectResult.count; }
//此方法計算圖像的亮度是否符合要求 - (BOOL)isPhotoIsBrightness:(cv::Mat &)image { cv::Mat imageSobel; Sobel(image, imageSobel, CV_16U, 1, 1); //圖像的平均灰度 double meanValue = 0.0; meanValue = mean(imageSobel)[0]; if (meanValue > 1.3) { return YES; } return NO; }
四:集成主要事項:
一、導入OpenCV類目的文件的控制器必須爲.mm的C++混編的文件
二、在方法命名和定義形參時,儘可能避免使用關鍵字開頭或直接使用關鍵字,因爲OC對此項的檢查不是很嚴格,一旦包含C++的文件之後,對關鍵字的檢測會很強,此爲須要注意的事項