iOS中的图像处理(一)——基础滤镜

10539人阅读 评论(6) 收藏 举报
分类:

最近在稍微做一些整理,翻起这部分的代码,发现是两个多月前的了。

这里讨论的是基于RGBA模型下的图像处理,即将变换作用在每个像素上。

代码是以UIImage的category形式存在的:

typedef struct _singleRGBA
{
    unsigned char red;
    unsigned char green;
    unsigned char blue;
    unsigned char alpha;
} RGBA;

@interface UIImage (ImageFilter)


首先,我们需要获得目标图像的位图信息;然后对每个像素进行变换;最后再生成图像。

- (UIImage*)applyFilter:(FilterFunction)filter context:(void*)context
{
	CGImageRef inImage = self.CGImage;
	CFDataRef m_DataRef = CGDataProviderCopyData(CGImageGetDataProvider(inImage));
	UInt8 *m_PixelBuf = (UInt8 *)CFDataGetBytePtr(m_DataRef);
	
	int length = CFDataGetLength(m_DataRef);
	
	for (int i=0; i<length; i+=4) {
		filter(m_PixelBuf, i, context);
	}
	
	CGContextRef ctx = CGBitmapContextCreate(m_PixelBuf,
											 CGImageGetWidth(inImage),
											 CGImageGetHeight(inImage),
											 CGImageGetBitsPerComponent(inImage),
											 CGImageGetBytesPerRow(inImage),
											 CGImageGetColorSpace(inImage),
											 CGImageGetBitmapInfo(inImage)
											 );
	
	CGImageRef imageRef = CGBitmapContextCreateImage(ctx);
	CGContextRelease(ctx);
	UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
	CGImageRelease(imageRef);
	CFRelease(m_DataRef);
    
	return finalImage;
}


其中,FilterFunction声明如下:

typedef void (*FilterFunction)(UInt8 *pixelBuf, UInt32 offset, void *context);

在此基础上,我们可以把每个变换操作独立出来,比如调整亮度、对比度、色调、透明度等:

void filterOpacity(UInt8 *pixelBuf, UInt32 offset, void *context)
{
	double val = *((double*)context);
	
	int a = offset+3;
	
	int alpha = pixelBuf[a];
	
	pixelBuf[a] = SAFECOLOR(alpha * val);
}

void filterBrightness(UInt8 *pixelBuf, UInt32 offset, void *context)
{
	double t = *((double*)context);
	
	int r = offset;
	int g = offset+1;
	int b = offset+2;
	
	int red = pixelBuf[r];
	int green = pixelBuf[g];
	int blue = pixelBuf[b];
	
	pixelBuf[r] = SAFECOLOR(red * t);
	pixelBuf[g] = SAFECOLOR(green * t);
	pixelBuf[b] = SAFECOLOR(blue * t);
}

void filterSaturation(UInt8 *pixelBuf, UInt32 offset, void *context)
{
	double t = *((double*)context); // t (- [0, 2]
	
	int r = offset;
	int g = offset+1;
	int b = offset+2;
	
	int red = pixelBuf[r];
	int green = pixelBuf[g];
	int blue = pixelBuf[b];
    
    red = red * (0.3086 * (1-t) + t) + green * (0.6094 * (1-t)) + blue * (0.0820 * (1-t));
    green = red * (0.3086 * (1-t)) + green * ((0.6094 * (1-t)) + t) + blue * (0.0820 * (1-t));
    blue = red * (0.3086 * (1-t)) + green * (0.6094 * (1-t)) + blue * ((0.0820 * (1-t)) + t);
	
	pixelBuf[r] = SAFECOLOR(red);
	pixelBuf[g] = SAFECOLOR(green);
	pixelBuf[b] = SAFECOLOR(blue);
}

void filterContrast(UInt8 *pixelBuf, UInt32 offset, void *context)
{
    double t = *((double*)context); // t (- [0, 10]
	
	int r = offset;
	int g = offset+1;
	int b = offset+2;
	
	int red = pixelBuf[r];
	int green = pixelBuf[g];
	int blue = pixelBuf[b];
    
    red = red * t + 128 * (1-t);
    green = green * t + 128 * (1-t);
    blue = blue * t + 128 * (1-t);
	
	pixelBuf[r] = SAFECOLOR(red);
	pixelBuf[g] = SAFECOLOR(green);
	pixelBuf[b] = SAFECOLOR(blue);
}

void filterPosterize(UInt8 *pixelBuf, UInt32 offset, void *context)
{
    double levels = *((double*)context);
	if (levels == 0) levels = 1; // avoid divide by zero
	int step = 255 / levels;
	
	int r = offset;
	int g = offset+1;
	int b = offset+2;
	
	int red = pixelBuf[r];
	int green = pixelBuf[g];
	int blue = pixelBuf[b];
	
	pixelBuf[r] = SAFECOLOR((red / step) * step);
	pixelBuf[g] = SAFECOLOR((green / step) * step);
	pixelBuf[b] = SAFECOLOR((blue / step) * step);
}

void filterDesaturate(UInt8 *pixelBuf, UInt32 offset, void *context)
{
	int r = offset;
	int g = offset+1;
	int b = offset+2;
	
	int red = pixelBuf[r];
	int green = pixelBuf[g];
	int blue = pixelBuf[b];
    
    red = red * 0.3086 + green * 0.6094 + blue * 0.0820;
    green = red * 0.3086 + green * 0.6094 + blue * 0.0820;
    blue = red * 0.3086 + green * 0.6094 + blue * 0.0820;
	
	pixelBuf[r] = SAFECOLOR(red);
	pixelBuf[g] = SAFECOLOR(green);
	pixelBuf[b] = SAFECOLOR(blue);
}

void filterInvert(UInt8 *pixelBuf, UInt32 offset, void *context)
{
	int r = offset;
	int g = offset+1;
	int b = offset+2;
	
	int red = pixelBuf[r];
	int green = pixelBuf[g];
	int blue = pixelBuf[b];
	
	pixelBuf[r] = SAFECOLOR(255-red);
	pixelBuf[g] = SAFECOLOR(255-green);
	pixelBuf[b] = SAFECOLOR(255-blue);
}

void filterTint(UInt8 *pixelBuf, UInt32 offset, void *context)
{
    RGBA *rgbaArray = (RGBA*)context;
    RGBA maxRGBA = rgbaArray[0];
    RGBA minRGBA = rgbaArray[1];
    
	int r = offset;
	int g = offset+1;
	int b = offset+2;
	
	int red = pixelBuf[r];
	int green = pixelBuf[g];
	int blue = pixelBuf[b];
	
	pixelBuf[r] = SAFECOLOR((red - minRGBA.red) * (255.0 / (maxRGBA.red - minRGBA.red)));
	pixelBuf[g] = SAFECOLOR((green - minRGBA.green) * (255.0 / (maxRGBA.green - minRGBA.green)));
	pixelBuf[b] = SAFECOLOR((blue - minRGBA.blue) * (255.0 / (maxRGBA.blue - minRGBA.blue)));
}


其中SAFECOLOR宏如下:

#define SAFECOLOR(color) MIN(255,MAX(0,color))

最后,拿一张帅气的Andy照片来实践下,希望没有侵犯到肖像权。
原图如下:


通过以下四种变换,可以分别得到四张处理过的图片:

return [originImage changeOpacityByFactor:0.5];

return [originImage changeBrightnessByFactor:1.2];

return [originImage changeSaturationByFactor:2.0];

return [originImage tintWithMaxRGBA:(RGBA){190, 190, 230} minRGBA:(RGBA){50, 35, 10}];

  

 



4
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1585349次
    • 积分:14685
    • 等级:
    • 排名:第787名
    • 原创:195篇
    • 转载:9篇
    • 译文:2篇
    • 评论:869条
    博客专栏
    文章分类
    最新评论