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

http://www.41443.com/HTML/iphone/20150514/371369.html


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

最近要 实现 人像扣图的功能,我在网上查到的扣图的方式主要有两种,一种是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 请见我之前写的一贴博客: IOS使用OPENCV实现物体跟踪

 

头文件导入下面几个

#import

#import UIImage+OpenCV.h

 

UIImage+OpenCV类

 

 

//

// UIImage+OpenCV.h

 

#import

#import

@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

for(int i=0; i

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

if(val==cv::GC_PR_BGD){

grayFrame.at(j,i)[0]= '­';

grayFrame.at(j,i)[1]= '­';

grayFrame.at(j,i)[2]= '­';

}

}

}

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——待分割的源图像,必须是8位3通道(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_BGD或GCD_PR_FGD;

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

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

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

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

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

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

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

GC_EVAL(=2),执行分割。

*/



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值