###反色处理
前段时间,需要实现一个很简单的图像处理功能,就是将图片反色。
由于只是个小功能,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;
}
最后真机实验了下,用裁剪后的小图片进行反色处理,基本感知不到延迟,而用 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++。