iOS开发-简单图片背景替换(实现抠图效果)

之前好奇, 想实现这样的功能   -----> iOS图像处理-(jpg去除白色背景)

把一张图片(.jpg)的白色背景抠掉,转成.png 格式的有alpha通道的透明图。

原图黑白分明, 像这样

转换成这样

然后在论坛,得到了想要的答案。这里先谢过那位大牛, 也提供了参考资料:iOS8 Core Image In Swift:更复杂的滤镜

然后今天, 自己也总结一下。

写了个小小的demo, 实现背景图片的切换. 效果如下:

可以看到, 原先的黄色渐变背景被替换掉了。  接下去就是要实现这样一个功能。

当然. 如果感兴趣, 你可以从这里下载到源码:http://download.csdn.net/detail/hitwhylz/8186081

消除橙黄色

就像Photoshop的魔法棒一样,Core Image也有类似的滤镜,但是没有那么简单粗暴,使用起来很麻烦。

在Core Image里,我们为了消除某种颜色,需要使用CIColorCube滤镜,而CIColorCube滤镜需要一张cube映射表,这张表其实就是张颜色表(3D颜色查找表),把你想消除的颜色的alpha值设置为0,其他的颜色不变,Core Image将会把图像数据上的颜色映射为表中的颜色,以此来达到消除某种颜色的目的。

CIColorCube的这张表默认不会对inputImage作任何处理,但在我们这里要将所有的橙黄色干掉,所以需要自己来建立这张表。

我们要消除的“橙黄色”并不只是视觉上的一种颜色,而是颜色的范围,最直接的方法是将RGBA转成HSV(Hue,Saturation,Value),在HSV的格式下,颜色是围绕圆柱体中轴的角度来表现的,在这种表现方法下,你能把颜色的范围想象成连在一起的扇形,然后直接把该块区域干掉(alpha设为0),这就表示我们实际上需要指定颜色区域的范围------围绕圆柱体中轴线的最小角度以及最大角度,此范围内的颜色alpha设为0。最后,Cube Map表中的数据必须乘以alpha,所以创建Cube Map的最后一步是把RGB值乘以你刚刚计算出来的alpha值:如果是想要消除的颜色,乘出来就是0,反之则不变。这是一张代表颜色值区域的HSV(Hue值)图:

可以看到如果是纯黄色,其取值是60度,蓝色是240度,我们这种情况取值大概在35到55左右(偏黄一点),在这个网站上可以看到更详细的RGB颜色对应的HSV值。

那么接下来我们就准备创建Cube Map表,创建Cube Map表的方法在苹果官方示例中可以找到,是C语言实现的,为了方便起见,我们就直接创建一个C文件来包含这些代码。

在工程里选择新建一个.c文件,我取名为cubeMap.c,

.c文件搞完以后,即把苹果官方示例中的代码(以下代码)添加进去:

struct CubeMap {
    int length;
    float dimension;
    float *data;
};

struct CubeMap createCubeMap(float minHueAngle, float maxHueAngle) {
    const unsigned int size = 64;
    struct CubeMap map;
    map.length = size * size * size * sizeof (float) * 4;
    map.dimension = size;
    float *cubeData = (float *)malloc (map.length);
    float rgb[3], hsv[3], *c = cubeData;

    for (int z = 0; z < size; z++){
        rgb[2] = ((double)z)/(size-1); // Blue value
        for (int y = 0; y < size; y++){
            rgb[1] = ((double)y)/(size-1); // Green value
            for (int x = 0; x < size; x ++){
                rgb[0] = ((double)x)/(size-1); // Red value
                rgbToHSV(rgb,hsv);
                // Use the hue value to determine which to make transparent
                // The minimum and maximum hue angle depends on
                // the color you want to remove
                float alpha = (hsv[0] > minHueAngle && hsv[0] < maxHueAngle) ? 0.0f: 1.0f;
                // Calculate premultiplied alpha values for the cube
                c[0] = rgb[0] * alpha;
                c[1] = rgb[1] * alpha;
                c[2] = rgb[2] * alpha;
                c[3] = alpha;
                c += 4; // advance our pointer into memory for the next color value
            }
        }
    }
    map.data = cubeData;
    return map;
}

我将这个方法稍微改造了一下,选择一个结构体,因为外面要用到length和dimension。苹果没有提供rgbToHSV方法的实现,可以用我找到的这个:

void rgbToHSV(float *rgb, float *hsv) {
    float min, max, delta;
    float r = rgb[0], g = rgb[1], b = rgb[2];
    float *h = hsv, *s = hsv + 1, *v = hsv + 2;

    min = fmin(fmin(r, g), b );
    max = fmax(fmax(r, g), b );
    *v = max;
    delta = max - min;
    if( max != 0 )
        *s = delta / max;
    else {
        *s = 0;
        *h = -1;
        return;
    }
    if( r == max )
        *h = ( g - b ) / delta;
    else if( g == max )
        *h = 2 + ( b - r ) / delta;
    else
        *h = 4 + ( r - g ) / delta;
    *h *= 60;
    if( *h < 0 )
        *h += 360;
}

我在.c文件中导入的库:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

使用这个文件的时候, 需要把调用方, 比如我这里的ViewController.m 改为 ViewController.mm

这样就能支持c文件。 然后导入头文件 #include "cubeMap.c"

之后就是简单的调用了, 具体参加如下代码:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    //size  600?×?450

    //显示原图片
    UILabel *oldLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 65, 160, 15)];
    oldLabel.text = @"原图";
    oldLabel.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:oldLabel];

    UIImageView *oldImageView = [[UIImageView alloc]initWithFrame:CGRectMake(5, 80, 150, 112)];
    oldImageView.image = [UIImage imageNamed:@"beautyPic.jpg"];
    [self.view addSubview:oldImageView];

    //显示背景图片
    UILabel *backLabel = [[UILabel alloc]initWithFrame:CGRectMake(160, 65, 160, 15)];
    backLabel.text = @"背景图";
    backLabel.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:backLabel];

    UIImageView *backImageView = [[UIImageView alloc]initWithFrame:CGRectMake(165, 80, 150, 112)];
    backImageView.image = [UIImage imageNamed:@"background"];
    [self.view addSubview:backImageView];

    //更换背景图片
    CubeMap myCube = createCubeMap(35, 55);
    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:oldImageView.image.CGImage] forKey:kCIInputImageKey];

    CIImage *outputImage = colorCubeFilter.outputImage;

    CIFilter *sourceOverCompositingFilter = [CIFilter filterWithName:@"CISourceOverCompositing"];
    [sourceOverCompositingFilter setValue:outputImage forKey:kCIInputImageKey];
    [sourceOverCompositingFilter setValue:[CIImage imageWithCGImage:backImageView.image.CGImage] forKey:kCIInputBackgroundImageKey];

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

    UILabel *newLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 200, 320, 15)];
    newLabel.text = @"合成图";
    newLabel.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:newLabel];

    UIImageView *newImageView = [[UIImageView alloc]initWithFrame:CGRectMake(10, 220, 300, 225)];
    newImageView.image = [UIImage imageWithCGImage:cgImage];
    [self.view addSubview:newImageView];

}
时间: 2024-10-03 18:31:26

iOS开发-简单图片背景替换(实现抠图效果)的相关文章

iOS开发基础-图片切换(2)

延续:iOS开发基础-图片切换(1),对(1)里面的代码进行改善. 在 ViewController 类中添加新的数组属性:  @property (nonatomic, strong) NSArray *infoArray; //存放图片信息 通过 self.infoArray 的 getter 方法对其实现初始化(懒加载),其中代码中的 _infoArray 不能用 self.infoArray 替换: 1 //infoArray的get方法 2 - (NSArray *)infoArray

iOS开发基础-图片切换(3)

延续:iOS开发基础-图片切换(2),对(2)里面的代码用属性列表plist进行改善. 新建 Property List 命名为 Data 获得一个后缀为 .plist 的文件. 按如图修改刚创建的文件: 最后,修改 infoArray 的 getter 方法: 1 //infoArray的getter方法 2 - (NSArray *)infoArray { 3 NSLog(@"需要获取图片信息数组"); 4 //只实例化一次 5 if (_infoArray == nil) { 6

iOS开发-简单解析JSON数据

什么是JSON ? JSON是一种轻量级的数据格式,一般用于数据交互 服务器返回给客户端的数据,一般都是JSON格式或者XML格式(文件下载除外) ? JSON的格式很像OC中的字典和数组 ? {"name" : "Jack", "age" : 10} {"name" : ["jack", "rose", "jim"]} ? 标准JSON格式的注意点: key必须用双

IOS开发之触摸背景关闭键盘的代码实现

直接上代码: // 触摸背景,关闭键盘 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ UITouch *touch = [touches anyObject]; UIView *view = (UIView *)[touch view]; if (view == self.view) { [weightTextField resignFirstResponder]; } } 以上代码是在一个viewContro

iOS开发之剖析&quot;秘密&quot;App内容页面效果(二)

@前些天写了一篇"秘密"的Cell效果文章,但是与在工作中想要的效果还是有差距,而且扩展性很不好,于是重写封装,把整体视图都放到scrollView中,基本是和secret app 一模一样的效果了. @代码如下:(模糊效果的类就不写了,大家可以搜"UIImage+ImageEffects",还要导入Accelerate.framework) 1.MTSecretAppEffect.h #import <Foundation/Foundation.h>

iOS开发之剖析&quot;秘密&quot;App内容页面效果

最近在玩"秘密",发现点击主界面的Cell进去后的页面效果不错,就写了个Demo来演示下. 它主要效果:下拉头部视图放大,上拉视图模糊而且到一定位置固定不动,其他Cell可以继续上移. @封装的主要效果类:MTHeadEffect.m(.h文件省略,很简单的) #import "MTHeadEffect.h" #import <QuartzCore/QuartzCore.h> #import <Accelerate/Accelerate.h>

iOS开发练习之UIPickerView实现歌词翻滚效果

麻雀虽小,五脏俱全.在平时的项目中,任何一个模块或者功能里其实都隐藏着许多我们平时注意不到的知识点,其实很多东西大家每天都在用,但很多时候都是知其然,而不知其所以然.时间久了,也就懒得去想到底是什么原因了,怎么实现的之类.回想自己的学习路程,也基本都这样混过来,实在愧对光阴,近日抽空,查看过往笔记,顺手写了个小代码练习,感觉温故知新.现分享代码,以供新手入门参考,尤其其中错误的部分也很有广泛性.同时也欢迎各路成精的老鸟们喷吐,能够指正,这样也促进我再进步一点. ViewController.m文

iOS开发中图片方向的获取与更改

iOS开发中 再用到照片的时候  或多或少遇到过这样的问题  就是我想用的照片有横着拍的有竖着排的  所以导致我选取图片后的效果也横七竖八的   显示效果不好 比如: 图中红圈选中的图片选取的是横着拍的图片 所以显示的头像也是横着的 显示效果不佳 问题描述: 使用过iPhone或者iPad的朋友在拍照时不知是否遇到过这样的问题,将设备中的照片导出到Windows上时,经常发现导出的照片方向会有问题,要么横着,要么颠倒着,需要旋转才适合观看.而如果直接在这些设备上浏览时,照片会始终显示正确的方向,

IOS开发防止图片渲染的方法

IOS开发中,很多时候我们在给导航控制器或者其它的控制器中的部件添加图片的时候,图片会被渲染,下面就是处理图片渲染的方法. UIImage *image = [UIImage imageNamed:@"a.jpg"]; image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];