iOS --- 通過CPU實現的簡單濾鏡效果
iOS中使用CPU實現濾鏡效果的原理很簡單, 即將圖片轉換成像素資料, 然後對每一個像素進行相應的濾鏡效果計算, 然後重新得到過濾後的圖片.
CPU濾鏡效果代碼如下:
標頭檔
// CPUImageFilterUtil.h#import #import #import #import //LOMOstatic const float colormatrix_lomo[] = { 1.7f, 0.1f, 0.1f, 0, -73.1f, 0, 1.7f, 0.1f, 0, -73.1f, 0, 0.1f, 1.6f, 0, -73.1f, 0, 0, 0, 1.0f, 0 };//黑白static const float colormatrix_heibai[] = { 0.8f, 1.6f, 0.2f, 0, -163.9f, 0.8f, 1.6f, 0.2f, 0, -163.9f, 0.8f, 1.6f, 0.2f, 0, -163.9f, 0, 0, 0, 1.0f, 0 };//複古static const float colormatrix_huajiu[] = { 0.2f,0.5f, 0.1f, 0, 40.8f, 0.2f, 0.5f, 0.1f, 0, 40.8f, 0.2f,0.5f, 0.1f, 0, 40.8f, 0, 0, 0, 1, 0 };//哥特static const float colormatrix_gete[] = { 1.9f,-0.3f, -0.2f, 0,-87.0f, -0.2f, 1.7f, -0.1f, 0, -87.0f, -0.1f,-0.6f, 2.0f, 0, -87.0f, 0, 0, 0, 1.0f, 0 };//銳利化static const float colormatrix_ruise[] = { 4.8f,-1.0f, -0.1f, 0,-388.4f, -0.5f,4.4f, -0.1f, 0,-388.4f, -0.5f,-1.0f, 5.2f, 0,-388.4f, 0, 0, 0, 1.0f, 0 };//淡雅static const float colormatrix_danya[] = { 0.6f,0.3f, 0.1f, 0,73.3f, 0.2f,0.7f, 0.1f, 0,73.3f, 0.2f,0.3f, 0.4f, 0,73.3f, 0, 0, 0, 1.0f, 0 };//酒紅static const float colormatrix_jiuhong[] = { 1.2f,0.0f, 0.0f, 0.0f,0.0f, 0.0f,0.9f, 0.0f, 0.0f,0.0f, 0.0f,0.0f, 0.8f, 0.0f,0.0f, 0, 0, 0, 1.0f, 0 };//清寧static const float colormatrix_qingning[] = { 0.9f, 0, 0, 0, 0, 0, 1.1f,0, 0, 0, 0, 0, 0.9f, 0, 0, 0, 0, 0, 1.0f, 0 };//浪漫static const float colormatrix_langman[] = { 0.9f, 0, 0, 0, 63.0f, 0, 0.9f,0, 0, 63.0f, 0, 0, 0.9f, 0, 63.0f, 0, 0, 0, 1.0f, 0 };//光暈static const float colormatrix_guangyun[] = { 0.9f, 0, 0, 0, 64.9f, 0, 0.9f,0, 0, 64.9f, 0, 0, 0.9f, 0, 64.9f, 0, 0, 0, 1.0f, 0 };//藍調static const float colormatrix_landiao[] = { 2.1f, -1.4f, 0.6f, 0.0f, -31.0f, -0.3f, 2.0f, -0.3f, 0.0f, -31.0f, -1.1f, -0.2f, 2.6f, 0.0f, -31.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f};//夢幻static const float colormatrix_menghuan[] = { 0.8f, 0.3f, 0.1f, 0.0f, 46.5f, 0.1f, 0.9f, 0.0f, 0.0f, 46.5f, 0.1f, 0.3f, 0.7f, 0.0f, 46.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f};//夜色static const float colormatrix_yese[] = { 1.0f, 0.0f, 0.0f, 0.0f, -66.6f, 0.0f, 1.1f, 0.0f, 0.0f, -66.6f, 0.0f, 0.0f, 1.0f, 0.0f, -66.6f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f};static const float colormatrixs[][20]={ { 0.8f, 1.6f, 0.2f, 0, -163.9f, 0.8f, 1.6f, 0.2f, 0, -163.9f, 0.8f, 1.6f, 0.2f, 0, -163.9f, 0, 0, 0, 1.0f, 0 }, { 0.2f,0.5f, 0.1f, 0, 40.8f, 0.2f, 0.5f, 0.1f, 0, 40.8f, 0.2f,0.5f, 0.1f, 0, 40.8f, 0, 0, 0, 1, 0 }, { 1.9f,-0.3f, -0.2f, 0,-87.0f, -0.2f, 1.7f, -0.1f, 0, -87.0f, -0.1f,-0.6f, 2.0f, 0, -87.0f, 0, 0, 0, 1.0f, 0 }, { 4.8f,-1.0f, -0.1f, 0,-388.4f, -0.5f,4.4f, -0.1f, 0,-388.4f, -0.5f,-1.0f, 5.2f, 0,-388.4f, 0, 0, 0, 1.0f, 0 }, { 0.6f,0.3f, 0.1f, 0,73.3f, 0.2f,0.7f, 0.1f, 0,73.3f, 0.2f,0.3f, 0.4f, 0,73.3f, 0, 0, 0, 1.0f, 0 }, { 1.2f,0.0f, 0.0f, 0.0f,0.0f, 0.0f,0.9f, 0.0f, 0.0f,0.0f, 0.0f,0.0f, 0.8f, 0.0f,0.0f, 0, 0, 0, 1.0f, 0 }, { 0.9f, 0, 0, 0, 0, 0, 1.1f,0, 0, 0, 0, 0, 0.9f, 0, 0, 0, 0, 0, 1.0f, 0 }, { 0.9f, 0, 0, 0, 63.0f, 0, 0.9f,0, 0, 63.0f, 0, 0, 0.9f, 0, 63.0f, 0, 0, 0, 1.0f, 0 }, { 0.9f, 0, 0, 0, 64.9f, 0, 0.9f,0, 0, 64.9f, 0, 0, 0.9f, 0, 64.9f, 0, 0, 0, 1.0f, 0 }, { 2.1f, -1.4f, 0.6f, 0.0f, -31.0f, -0.3f, 2.0f, -0.3f, 0.0f, -31.0f, -1.1f, -0.2f, 2.6f, 0.0f, -31.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f }, { 0.8f, 0.3f, 0.1f, 0.0f, 46.5f, 0.1f, 0.9f, 0.0f, 0.0f, 46.5f, 0.1f, 0.3f, 0.7f, 0.0f, 46.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f }, { 1.0f, 0.0f, 0.0f, 0.0f, -66.6f, 0.0f, 1.1f, 0.0f, 0.0f, -66.6f, 0.0f, 0.0f, 1.0f, 0.0f, -66.6f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f }};@interface CPUImageFilterUtil : NSObject+ (UIImage *)imageWithImage:(UIImage *)inImage withColorMatrix:(const float*)f;@end
實現檔案
// CPUImageFilterUtil.m#import CPUImageFilterUtil.h@implementation CPUImageFilterUtil// 返回一個使用RGBA通道的位元影像上下文static CGContextRef CreateRGBABitmapContext (CGImageRef inImage){ CGContextRef context = NULL; CGColorSpaceRef colorSpace; //記憶體空間的指標,該記憶體空間的大小等於映像使用RGB通道所佔用的位元組數。 void *bitmapData; int bitmapByteCount; int bitmapBytesPerRow; //擷取橫向的像素點的個數 size_t pixelsWide = CGImageGetWidth(inImage); size_t pixelsHigh = CGImageGetHeight(inImage); //縱向 //每一行的像素點佔用的位元組數,每個像素點的ARGB四個通道各佔8個bit(0-255)的空間 bitmapBytesPerRow = (int)(pixelsWide * 4); //計算整張圖佔用的位元組數 bitmapByteCount = (int)(bitmapBytesPerRow * pixelsHigh); //建立依賴於裝置的RGB通道 colorSpace = CGColorSpaceCreateDeviceRGB(); //分配足夠容納圖片位元組數的記憶體空間 bitmapData = malloc(bitmapByteCount); //建立CoreGraphic的圖形上下文,該上下文描述了bitmaData指向的記憶體空間需要繪製的映像的一些繪製參數 context = CGBitmapContextCreate (bitmapData, pixelsWide, pixelsHigh, 8, bitmapBytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast); //Core Foundation中通過含有Create、Alloc的方法名字建立的指標,需要使用CFRelease()函數釋放 CGColorSpaceRelease( colorSpace ); return context;}// 返回一個指標,該指標指向一個數組,數組中的每四個元素都是映像上的一個像素點的RGBA的數值(0-255),用無符號的char是因為它正好的取值範圍就是0-255static unsigned char *RequestImagePixelData(UIImage *inImage){ CGImageRef img = [inImage CGImage]; CGSize size = [inImage size]; //使用上面的函數建立上下文 CGContextRef cgctx = CreateRGBABitmapContext(img); CGRect rect = {{0,0},{size.width, size.height}}; //將靶心圖表像繪製到指定的上下文,實際為上下文內的bitmapData。 CGContextDrawImage(cgctx, rect, img); unsigned char *data = CGBitmapContextGetData (cgctx); //釋放上面的函數建立的上下文 CGContextRelease(cgctx); return data;}static void changeRGBA(int *red,int *green,int *blue,int *alpha, const float* f)//修改RGB的值{ int redV = *red; int greenV = *green; int blueV = *blue; int alphaV = *alpha; *red = f[0] * redV + f[1] * greenV + f[2] * blueV + f[3] * alphaV + f[4]; *green = f[0+5] * redV + f[1+5] * greenV + f[2+5] * blueV + f[3+5] * alphaV + f[4+5]; *blue = f[0+5*2] * redV + f[1+5*2] * greenV + f[2+5*2] * blueV + f[3+5*2] * alphaV + f[4+5*2]; *alpha = f[0+5*3] * redV + f[1+5*3] * greenV + f[2+5*3] * blueV + f[3+5*3] * alphaV + f[4+5*3]; if (*red > 255) { *red = 255; } if(*red < 0) { *red = 0; } if (*green > 255) { *green = 255; } if (*green < 0) { *green = 0; } if (*blue > 255) { *blue = 255; } if (*blue < 0) { *blue = 0; } if (*alpha > 255) { *alpha = 255; } if (*alpha < 0) { *alpha = 0; }}+ (UIImage*)imageWithImage:(UIImage*)inImage withColorMatrix:(const float*) f{ unsigned char *imgPixel = RequestImagePixelData(inImage); CGImageRef inImageRef = [inImage CGImage]; GLuint w = (GLuint)CGImageGetWidth(inImageRef); GLuint h = (GLuint)CGImageGetHeight(inImageRef); int wOff = 0; int pixOff = 0; //雙層迴圈按照長寬的像素個數迭代每個像素點 for(GLuint y = 0;y< h;y++) { pixOff = wOff; for (GLuint x = 0; x
使用方法
UIImage *originImage = [UIImage imageNamed:@testImage];const float *colorMatrix = colormatrix_lomo;UIImage *filteredImage = [CPUImageFilterUtil imageWithImage:originImage withColorMatrix:colorMatrix];
效果如下: