IOS 用openCv实现简单的扣人像的


最近要实现人像扣图的功能,我在网上查到的扣图的方式主要有两种,一种是coreImage 色域,一种是openCv边缘检测
第一种适合纯色背景,扣图精准,第二种,适合复杂背景,但是默认的扣图不精确,如下图
 
1.处理前的照片

技术分享

2.处理后的照片
技术分享


coreImage 网上已经有很多实现了,也有很多文章,我就不多说了,我只把我实现的代码贴出来,代码粘过去就能用,另忘了,导入CubeMap.c

     //coreImage 扣图 createCubeMap(值1,值2)值范围0~360 扣掉值1到值2范围内的颜色

    CubeMap myCube = createCubeMap(self.slider1.value, self.slider2.value);

    NSData *myData = [[NSData alloc]initWithBytesNoCopy:myCube.data length:myCube.length freeWhenDone:true];

    CIFilter *colorCubeFilter = [CIFilter filterWithName:@"CIColorCube"];

    [colorCubeFilter setValue:[NSNumber numberWithFloat:myCube.dimension] forKey:@"inputCubeDimension"];

    [colorCubeFilter setValue:myData forKey:@"inputCubeData"];

    [colorCubeFilter setValue:[CIImage imageWithCGImage:_preview.image.CGImage] forKey:kCIInputImageKey];

    

    CIImage *outputImage = colorCubeFilter.outputImage;

    CIFilter *sourceOverCompositingFilter = [CIFilter filterWithName:@"CISourceOverCompositing"];

    [sourceOverCompositingFilter setValue:outputImage forKey:kCIInputImageKey];

    [sourceOverCompositingFilter setValue:[CIImage imageWithCGImage:backgroundImage.CGImage] forKey:kCIInputBackgroundImageKey];

    

    outputImage = sourceOverCompositingFilter.outputImage;

    CGImage *cgImage = [[CIContext contextWithOptions: nil]createCGImage:outputImage fromRect:outputImage.extent];


下面我讲一下,ios结合openCv实现扣图的方法

下载opencv2
具体怎么IOS下弄opencv 请见我之前写的一贴博客:
http://blog.csdn.net/wuzehai02/article/details/8439778


头文件导入下面几个

#import <opencv2/opencv.hpp>

#import "UIImage+OpenCV.h"


UIImage+OpenCV类


//

//  UIImage+OpenCV.h


#import <UIKit/UIKit.h>

#import <opencv2/opencv.hpp>

@interface UIImage (UIImage_OpenCV)


+(UIImage *)imageWithCVMat:(constcv::Mat&)cvMat;

-(id)initWithCVMat:(constcv::Mat&)cvMat;


@property(nonatomic,readonly) cv::Mat CVMat;

@property(nonatomic,readonly) cv::Mat CVGrayscaleMat;


@end


//

//  UIImage+OpenCV.mm


#import "UIImage+OpenCV.h"


staticvoid ProviderReleaseDataNOP(void *info,const void *data,size_t size)

{

    // Do not release memory

    return;

}




@implementation UIImage (UIImage_OpenCV)


-(cv::Mat)CVMat

{

    

    CGColorSpaceRef colorSpace =CGImageGetColorSpace(self.CGImage);

    CGFloat cols =self.size.width;

    CGFloat rows =self.size.height;

    

    cv::Mat cvMat(rows, cols,CV_8UC4); // 8 bits per component, 4 channels

    

   CGContextRef contextRef = CGBitmapContextCreate(cvMat.data,                // Pointer to backing data

                                                    cols,                     // Width of bitmap

                                                    rows,                    // Height of bitmap

                                                    8,                         // Bits per component

                                                    cvMat.step[0],             // Bytes per row

                                                    colorSpace,                // Colorspace

                                                   kCGImageAlphaNoneSkipLast |

                                                   kCGBitmapByteOrderDefault); // Bitmap info flags

    

   CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), self.CGImage);

   CGContextRelease(contextRef);

    

   return cvMat;

}


-(cv::Mat)CVGrayscaleMat

{

    CGColorSpaceRef colorSpace =CGColorSpaceCreateDeviceGray();

    CGFloat cols =self.size.width;

    CGFloat rows =self.size.height;

    

    cv::Mat cvMat =cv::Mat(rows, cols,CV_8UC1); // 8 bits per component, 1 channel

 

   CGContextRef contextRef = CGBitmapContextCreate(cvMat.data,                // Pointer to backing data

                                                    cols,                     // Width of bitmap

                                                    rows,                    // Height of bitmap

                                                    8,                         // Bits per component

                                                    cvMat.step[0],             // Bytes per row

                                                    colorSpace,                // Colorspace

                                                   kCGImageAlphaNone |

                                                   kCGBitmapByteOrderDefault); // Bitmap info flags

    

   CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), self.CGImage);

   CGContextRelease(contextRef);

    CGColorSpaceRelease(colorSpace);

    

   return cvMat;

}


+ (UIImage *)imageWithCVMat:(constcv::Mat&)cvMat

{

    return [[[UIImagealloc] initWithCVMat:cvMat]autorelease];

}


- (id)initWithCVMat:(constcv::Mat&)cvMat

{

    NSData *data = [NSDatadataWithBytes:cvMat.datalength:cvMat.elemSize() * cvMat.total()];

    

   CGColorSpaceRef colorSpace;

    

   if (cvMat.elemSize() == 1)

    {

        colorSpace = CGColorSpaceCreateDeviceGray();

    }

   else

    {

        colorSpace = CGColorSpaceCreateDeviceRGB();

    }

    

    CGDataProviderRef provider =CGDataProviderCreateWithCFData((CFDataRef)data);

    

   CGImageRef imageRef = CGImageCreate(cvMat.cols,                                    // Width

                                        cvMat.rows,                                    // Height

                                        8,                                             // Bits per component

                                        8 * cvMat.elemSize(),                          // Bits per pixel

                                        cvMat.step[0],                                 // Bytes per row

                                        colorSpace,                                    // Colorspace

                                       kCGImageAlphaNone | kCGBitmapByteOrderDefault // Bitmap info flags

                                        provider,                                      // CGDataProviderRef

                                       NULL,                                          // Decode

                                       false,                                         // Should interpolate

                                       kCGRenderingIntentDefault);                    // Intent   

    

   self = [selfinitWithCGImage:imageRef];

   CGImageRelease(imageRef);

    CGDataProviderRelease(provider);

    CGColorSpaceRelease(colorSpace);

    

    return self;

}


@end



好了,上面的都是准备工作,具体的代码其实很简单


    cv::Mat grayFrame,_lastFrame, mask,bgModel,fgModel;

    _lastFrame = [self.preview.imageCVMat];

    cv::cvtColor(_lastFrame, grayFrame,cv::COLOR_RGBA2BGR);//转换成三通道bgr


    cv::Rect rectangle(1,1,grayFrame.cols-2,grayFrame.rows -2);//检测的范围

    //分割图像

    cv::grabCut(grayFrame, mask, rectangle, bgModel, fgModel, 3,cv::GC_INIT_WITH_RECT);//openCv强大的扣图功能


    int nrow = grayFrame.rows;

    int ncol = grayFrame.cols * grayFrame.channels();

    for(int j=0; j<nrow; j++){//扣图,不知道这样写对不对,我也是新手,请大家多多指教

        for(int i=0; i<ncol; i++){

            uchar val = mask.at<uchar>(j,i);

            if(val==cv::GC_PR_BGD){

                grayFrame.at<cv::Vec3b>(j,i)[0]= ‘\255‘;

                grayFrame.at<cv::Vec3b>(j,i)[1]= ‘\255‘;

                grayFrame.at<cv::Vec3b>(j,i)[2]= ‘\255‘;

            }

        }

    }

    cv::cvtColor(grayFrame, grayFrame,cv::COLOR_BGR2RGB); //转换成彩色图片

    _preview.image = [[UIImagealloc] initWithCVMat:grayFrame];//显示结果



上面的代码测试可用,其实这里最关键的代码是使用了opencv的grabCut 图像分割函数

grabCut函数的API说明如下:

void cv::grabCut( InputArray _img, InputOutputArray _mask, Rect rect,

                  InputOutputArray _bgdModel, InputOutputArray _fgdModel,

                  int iterCount, int mode )

/*

****参数说明:

         img——待分割的源图像,必须是83通道(CV_8UC3)图像,在处理的过程中不会被修改;

         mask——掩码图像,如果使用掩码进行初始化,那么mask保存初始化掩码信息;在执行分割的时候,也可以将用户交互所设定的前景与背景保存到mask中,然后再传入grabCut函数;在处理结束之后,mask中会保存结果。mask只能取以下四种值:

                   GCD_BGD=0),背景;

                   GCD_FGD=1),前景;

                   GCD_PR_BGD=2),可能的背景;

                   GCD_PR_FGD=3),可能的前景。

                   如果没有手工标记GCD_BGD或者GCD_FGD,那么结果只会有GCD_PR_BGDGCD_PR_FGD

         rect——用于限定需要进行分割的图像范围,只有该矩形窗口内的图像部分才被处理;

         bgdModel——背景模型,如果为null,函数内部会自动创建一个bgdModelbgdModel必须是单通道浮点型(CV_32FC1)图像,且行数只能为1,列数只能为13x5

         fgdModel——前景模型,如果为null,函数内部会自动创建一个fgdModelfgdModel必须是单通道浮点型(CV_32FC1)图像,且行数只能为1,列数只能为13x5

         iterCount——迭代次数,必须大于0

         mode——用于指示grabCut函数进行什么操作,可选的值有:

                   GC_INIT_WITH_RECT=0),用矩形窗初始化GrabCut

                   GC_INIT_WITH_MASK=1),用掩码图像初始化GrabCut

                   GC_EVAL=2),执行分割。

*/

参考文章:http://blog.csdn.net/zouxy09/article/details/8534954



郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。