简易图像反色处理

###反色处理

前段时间,需要实现一个很简单的图像处理功能,就是将图片反色。

由于只是个小功能,app 也没有其他图片处理的需求,并不希望因此而导入一个庞大的第三方库。

先是看了下 core Image,有个 CIColorInvert 的滤镜,不过最终效果跟预想的有点出入。

其实功能并不是很难,干脆自己实现下。

因为图片事先已经被裁剪处理过,比较小,所以直接用 Core Graphics 进行处理。

所谓反色,大体理解就是用 255 分别减去 R,G,B。从二进制角度理解就是 0 变 1,1 变 0 。

那么我们就先得:

1.遍历图像的每个像素点颜色;

2.分别取出RGB,求得新的反色值,加上原来的透明度,得到新的像素颜色;

3.输出新的图片;

比较关键是第二个步骤,听起来可能有点繁琐,但实际实现起来却很简单。

UInt32 inputColor = *inputPixel;
inputColor = inputColor ^ 0xFFFFFF;

inputColor 获得了指针 inputPixel 指向图像的某一个像素点颜色,由于颜色是由 RBGA 组成的,每一种都是 8 位,所以是 UInt32。

然后用异或运算符,就实现了步骤2的效果。

具体代码:

- (UIImage *)processUsingImage:(UIImage*)inputImage {

UInt32 * inputPixels;

CGImageRef inputCGImage = [inputImage CGImage];
NSUInteger inputWidth = CGImageGetWidth(inputCGImage);
NSUInteger inputHeight = CGImageGetHeight(inputCGImage);

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

NSUInteger bytesPerPixel = 4;
NSUInteger bitsPerComponent = 8;

NSUInteger inputBytesPerRow = bytesPerPixel * inputWidth;

inputPixels = (UInt32 *)calloc(inputHeight * inputWidth, sizeof(UInt32));

CGContextRef context = CGBitmapContextCreate(inputPixels, inputWidth, inputHeight,
bitsPerComponent, inputBytesPerRow, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

CGContextDrawImage(context, CGRectMake(0, 0, inputWidth, inputHeight), inputCGImage);

for (NSUInteger j = 0; j < inputHeight; j++) {
for (NSUInteger i = 0; i < inputWidth; i++) {

UInt32 * inputPixel = inputPixels + j * inputWidth + i;
UInt32 inputColor = *inputPixel;
inputColor = inputColor ^ 0xFFFFFF;
*inputPixel = inputColor;
}
}

CGImageRef newCGImage = CGBitmapContextCreateImage(context);
UIImage * processedImage = [UIImage imageWithCGImage:newCGImage];

CGColorSpaceRelease(colorSpace);
CGContextRelease(context);
free(inputPixels);

return processedImage;
}

doge1

最后真机实验了下,用裁剪后的小图片进行反色处理,基本感知不到延迟,而用 iPhone5s 处理相机拍摄的原始图片,时间平均在 0.2-0.3 秒上下。需求也用不到原图,只需要处理小图片,基本没问题。而用 core image 的处理时间更长,可能由于效果实现不一样,算法也比较复杂。

题外话:Swift 的 SIMD

由于最近看到 Swift 2: SIMD,似乎也可以做一些简单的图形处理。

比如一个颜色,你要把每个 RGB 的值都降低为原来的一半,那么:

let vec = float3(255.0, 255.0, 255.0)
let matrix = float3x3(
[float3(0.5, 0.0, 0.0),
float3(0.0, 0.5, 0.0),
float3(0.0, 0.0, 0.5)]
)

let result = vec * matrix

由于是并行计算,执行效率会高很多。

具体实现可自行尝试,当然真正的图像处理应该还是用 C++。