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

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

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

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

[cpp] view plaincopy

  1. typedef struct _singleRGBA
  2. {
  3. unsigned char red;
  4. unsigned char green;
  5. unsigned char blue;
  6. unsigned char alpha;
  7. } RGBA;
  8. @interface UIImage (ImageFilter)

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

[cpp] view plaincopy

  1. - (UIImage*)applyFilter:(FilterFunction)filter context:(void*)context
  2. {
  3. CGImageRef inImage = self.CGImage;
  4. CFDataRef m_DataRef = CGDataProviderCopyData(CGImageGetDataProvider(inImage));
  5. UInt8 *m_PixelBuf = (UInt8 *)CFDataGetBytePtr(m_DataRef);
  6. int length = CFDataGetLength(m_DataRef);
  7. for (int i=0; i<length; i+=4) {
  8. filter(m_PixelBuf, i, context);
  9. }
  10. CGContextRef ctx = CGBitmapContextCreate(m_PixelBuf,
  11. CGImageGetWidth(inImage),
  12. CGImageGetHeight(inImage),
  13. CGImageGetBitsPerComponent(inImage),
  14. CGImageGetBytesPerRow(inImage),
  15. CGImageGetColorSpace(inImage),
  16. CGImageGetBitmapInfo(inImage)
  17. );
  18. CGImageRef imageRef = CGBitmapContextCreateImage(ctx);
  19. CGContextRelease(ctx);
  20. UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
  21. CGImageRelease(imageRef);
  22. CFRelease(m_DataRef);
  23. return finalImage;
  24. }

其中,FilterFunction声明如下:

[cpp] view plaincopy

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

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

[cpp] view plaincopy

  1. void filterOpacity(UInt8 *pixelBuf, UInt32 offset, void *context)
  2. {
  3. double val = *((double*)context);
  4. int a = offset+3;
  5. int alpha = pixelBuf[a];
  6. pixelBuf[a] = SAFECOLOR(alpha * val);
  7. }
  8. void filterBrightness(UInt8 *pixelBuf, UInt32 offset, void *context)
  9. {
  10. double t = *((double*)context);
  11. int r = offset;
  12. int g = offset+1;
  13. int b = offset+2;
  14. int red = pixelBuf[r];
  15. int green = pixelBuf[g];
  16. int blue = pixelBuf[b];
  17. pixelBuf[r] = SAFECOLOR(red * t);
  18. pixelBuf[g] = SAFECOLOR(green * t);
  19. pixelBuf[b] = SAFECOLOR(blue * t);
  20. }
  21. void filterSaturation(UInt8 *pixelBuf, UInt32 offset, void *context)
  22. {
  23. double t = *((double*)context); // t (- [0, 2]
  24. int r = offset;
  25. int g = offset+1;
  26. int b = offset+2;
  27. int red = pixelBuf[r];
  28. int green = pixelBuf[g];
  29. int blue = pixelBuf[b];
  30. red = red * (0.3086 * (1-t) + t) + green * (0.6094 * (1-t)) + blue * (0.0820 * (1-t));
  31. green = red * (0.3086 * (1-t)) + green * ((0.6094 * (1-t)) + t) + blue * (0.0820 * (1-t));
  32. blue = red * (0.3086 * (1-t)) + green * (0.6094 * (1-t)) + blue * ((0.0820 * (1-t)) + t);
  33. pixelBuf[r] = SAFECOLOR(red);
  34. pixelBuf[g] = SAFECOLOR(green);
  35. pixelBuf[b] = SAFECOLOR(blue);
  36. }
  37. void filterContrast(UInt8 *pixelBuf, UInt32 offset, void *context)
  38. {
  39. double t = *((double*)context); // t (- [0, 10]
  40. int r = offset;
  41. int g = offset+1;
  42. int b = offset+2;
  43. int red = pixelBuf[r];
  44. int green = pixelBuf[g];
  45. int blue = pixelBuf[b];
  46. red = red * t + 128 * (1-t);
  47. green = green * t + 128 * (1-t);
  48. blue = blue * t + 128 * (1-t);
  49. pixelBuf[r] = SAFECOLOR(red);
  50. pixelBuf[g] = SAFECOLOR(green);
  51. pixelBuf[b] = SAFECOLOR(blue);
  52. }
  53. void filterPosterize(UInt8 *pixelBuf, UInt32 offset, void *context)
  54. {
  55. double levels = *((double*)context);
  56. if (levels == 0) levels = 1; // avoid divide by zero
  57. int step = 255 / levels;
  58. int r = offset;
  59. int g = offset+1;
  60. int b = offset+2;
  61. int red = pixelBuf[r];
  62. int green = pixelBuf[g];
  63. int blue = pixelBuf[b];
  64. pixelBuf[r] = SAFECOLOR((red / step) * step);
  65. pixelBuf[g] = SAFECOLOR((green / step) * step);
  66. pixelBuf[b] = SAFECOLOR((blue / step) * step);
  67. }
  68. void filterDesaturate(UInt8 *pixelBuf, UInt32 offset, void *context)
  69. {
  70. int r = offset;
  71. int g = offset+1;
  72. int b = offset+2;
  73. int red = pixelBuf[r];
  74. int green = pixelBuf[g];
  75. int blue = pixelBuf[b];
  76. red = red * 0.3086 + green * 0.6094 + blue * 0.0820;
  77. green = red * 0.3086 + green * 0.6094 + blue * 0.0820;
  78. blue = red * 0.3086 + green * 0.6094 + blue * 0.0820;
  79. pixelBuf[r] = SAFECOLOR(red);
  80. pixelBuf[g] = SAFECOLOR(green);
  81. pixelBuf[b] = SAFECOLOR(blue);
  82. }
  83. void filterInvert(UInt8 *pixelBuf, UInt32 offset, void *context)
  84. {
  85. int r = offset;
  86. int g = offset+1;
  87. int b = offset+2;
  88. int red = pixelBuf[r];
  89. int green = pixelBuf[g];
  90. int blue = pixelBuf[b];
  91. pixelBuf[r] = SAFECOLOR(255-red);
  92. pixelBuf[g] = SAFECOLOR(255-green);
  93. pixelBuf[b] = SAFECOLOR(255-blue);
  94. }
  95. void filterTint(UInt8 *pixelBuf, UInt32 offset, void *context)
  96. {
  97. RGBA *rgbaArray = (RGBA*)context;
  98. RGBA maxRGBA = rgbaArray[0];
  99. RGBA minRGBA = rgbaArray[1];
  100. int r = offset;
  101. int g = offset+1;
  102. int b = offset+2;
  103. int red = pixelBuf[r];
  104. int green = pixelBuf[g];
  105. int blue = pixelBuf[b];
  106. pixelBuf[r] = SAFECOLOR((red - minRGBA.red) * (255.0 / (maxRGBA.red - minRGBA.red)));
  107. pixelBuf[g] = SAFECOLOR((green - minRGBA.green) * (255.0 / (maxRGBA.green - minRGBA.green)));
  108. pixelBuf[b] = SAFECOLOR((blue - minRGBA.blue) * (255.0 / (maxRGBA.blue - minRGBA.blue)));
  109. }

其中SAFECOLOR宏如下:

[cpp] view plaincopy

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

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

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

[cpp] view plaincopy

  1. return [originImage changeOpacityByFactor:0.5];

[cpp] view plaincopy

  1. return [originImage changeBrightnessByFactor:1.2];

[cpp] view plaincopy

  1. return [originImage changeSaturationByFactor:2.0];

[cpp] view plaincopy

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

 

 

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-26 02:06:26

iOS中的图像处理(一)——基础滤镜的相关文章

iOS中的图像处理(二)——卷积运算

关于图像处理中的卷积运算,这里有两份简明扼要的介绍:文一,文二. 其中,可能的一种卷积运算代码如下: [cpp] view plaincopy - (UIImage*)applyConvolution:(NSArray*)kernel { CGImageRef inImage = self.CGImage; CFDataRef m_DataRef = CGDataProviderCopyData(CGImageGetDataProvider(inImage)); CFDataRef m_OutD

iOS中的图像处理(三)——混合运算

有时候,单独对一张图像进行处理是很难或者根本达不到我们想要的效果的.一个好的滤镜效果的诞生,往往要经过很多复杂步骤.细致微调.图片应用效果观察以及很多图层叠加. 我在JSWidget上发现了一些常用混合算法,对应着一些常用混合模式,通过这些blend modes,我们可以指定两张图像如何混合. 不过在此之前,我们需要纯颜色图像和渐变图像来做辅助: [cpp] view plaincopy + (UIImage *)imageWithColor:(UIColor *)color size:(CGS

图像处理之基础---卷积傅立叶变换中的复数

整个看FFT过程中复数一直很折磨我. 原本的实数的东西通过复数表达很像旋转矩阵用quaternion来表达,尽管旋转vector还是要用matrix来做,但是通过用quaternion表达的旋转意义可以做插值等很多快速的操作,而且内存消耗也小,在做完这些操作之后再转成matrix用就好了. 复数表达也是类似. a+bi = M*(cos(theta)+sin(theta)*i)----极坐标 cos(x) + sin(x)*i = exp(x*i)----欧拉公式 这个用欧拉公式转出来的exp(

iOS中的转场研究(转)

http://mikixiyou.iteye.com/blog/1745995 http://www.cocoachina.com/ios/20141113/10212.html 在iOS开发中,segue用来实现storyboard中源视图控制器和目标视图控制器连接,当segue被触发时,系统将完成下列操作: 1.实例化目标视图控制器2.实例化一个新segue对象,该对象持有所有的信息3.调用源视图控制器的prepareForSegue:sender:方法,4.调用segue的 perform

iOS中一些 常用的第三方库

转自ibireme的博客 做iOS开发总会接触到一些第三方库,这里整理一下,做一些吐槽. 目前比较活跃的社区仍旧是Github,除此以外也有一些不错的库散落在Google Code.SourceForge等地方.由于Github社区太过主流,这里主要介绍一下Github里面流行的iOS库. 首先整理了一份Github上排名靠前的iOS库(大概600个repos) 除了逛一下每日/每月流行之外,也可以到这里来看一下整个iOS Repos的排名. 下面是一些比较流行的第三方库: HTTP 相比较之下

IOS动画(2)基础动画

参考博客:http://www.cnblogs.com/kenshincui/p/3972100.html IOS中核心动画主要分4类:基础动画,关键帧动画,动画组,转场动画 CAAnimation:核心动画的基础类,不能直接使用,负责动画运行时间.速度的控制,本身实现了CAMediaTiming协议. CAPropertyAnimation:属性动画的基类(通过属性进行动画设置,注意是可动画属性),不能直接使用. CAAnimationGroup:动画组,动画组是一种组合模式设计,可以通过动画

iOS游戏框架Sprite Kit基础教程第1章编写第一个Sprite Kit程序

iOS游戏框架Sprite Kit基础教程第1章编写第一个Sprite Kit程序 程序是为了实现特定目标或解决特定问题而用计算机语言编写的命令序列的集合.本章将以编写第一个Sprite Kit程序为主线,为开发者讲解什么是Sprite Kit.苹果账号的注册.Xcode的下载和安装.编写程序.调试等内容.选自iOS游戏框架Sprite Kit基础教程Swift版上册大学霸 1.1  Sprite Kit介绍 从iOS 7开始添加了Sprite Kit.本节将为开发者讲解什么是Sprite Ki

OS X 和iOS 中的多线程技术(上)

OS X 和iOS 中的多线程技术(上) 本文梳理了OS X 和iOS 系统中提供的多线程技术.并且对这些技术的使用给出了一些实用的建议. 多线程的目的:通过并发执行提高 CPU 的使用效率,进而提供程序运行效率. 1.线程和进程 进程 什么是进程 进程是指在计算机系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行中其专用且受保护的内存空间内 比如同时打开 Xcode .Safari ,系统就会分别启动两个进程 通过活动监视器可以查看Mac系统中所开启的进程 线程 什么是线程 一

iOS中Animation 动画 UI_22

1.iOS中我们能看到的控件都是UIView的子类,比如UIButton UILabel UITextField UIImageView等等 2.UIView能够在屏幕的显示是因为在创建它的时候内部自动添加一个CALayer图层,通过这个图层在屏幕上显示的时候会调用一个drawRect: 的方法,完成绘图,才能在屏幕上显示 3.CALayer 本身就具有显示功能,但是它不能响应用户的交互事件,如果只是单纯的显示一个图形,此时你可以使用CALayer创建或者是使用UIView创建,但是如果这个图形