之前好奇, 想实现这样的功能 -----> 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]; }