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

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

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

  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)

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

  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声明如下:

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

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

  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宏如下:

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

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

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

  1. return [originImage changeOpacityByFactor:0.5];
  1. return [originImage changeBrightnessByFactor:1.2];
  1. return [originImage changeSaturationByFactor:2.0];
  1. return [originImage tintWithMaxRGBA:(RGBA){190, 190, 230} minRGBA:(RGBA){50, 35, 10}];

 

 

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

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

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

    关于图像处理中的卷积运算,这里有两份简明扼要的介绍:文一,文二. 其中,可能的一种卷积运算代码如下: - (UIImage*)applyConvolution:(NSArray*)kernel { C ...

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

    有时候,单独对一张图像进行处理是很难或者根本达不到我们想要的效果的.一个好的滤镜效果的诞生,往往要经过很多复杂步骤.细致微调.图片应用效果观察以及很多图层叠加. 我在JSWidget上发现了一些常用混 ...

  3. iOS中数据库应用基础

    iOS 数据库入门 一.数据库简介 1.什么是数据库? 数据库(Database) 是按照数据结构来组织,存储和管理数据的仓库 数据库可以分为2大种类 关系型数据库(主流) PC端 Oracle My ...

  4. iOS 中的 HotFix 方案总结详解

    相信HotFix大家应该都很熟悉了,今天主要对于最近调研的一些方案做一些总结.iOS中的HotFix方案大致可以分为四种: WaxPatch(Alibaba) Dynamic Framework(Ap ...

  5. iOS中assign、copy 、retain等关键字的含义

    iOS中assign.copy .retain等关键字的含义  转自:http://my.oschina.net/majiage/blog/267409 assign: 简单赋值,不更改索引计数cop ...

  6. iOS中几种常用的数据存储方式

    自己稍微总结了一下下,方便大家查看 1.write直接写入文件的方法 永久保存在磁盘中,可以存储的对象有NSString.NSArray.NSDictionary.NSData.NSNumber,数据 ...

  7. Cordoval在iOS中的运用整理

    一:关于Cordoval理论知识 1:PhoneGap是手机平台上流行的一款中间件.它构建在各种手机平台所提供的WebView(浏览器内核)组件的基础之上,使用javascript语言对应用开发者提供 ...

  8. iOS中集成ijkplayer视频直播框架

    ijkplayer 是一款做视频直播的框架, 基于ffmpeg, 支持 Android 和 iOS, 网上也有很多集成说明, 但是个人觉得还是不够详细, 在这里详细的讲一下在 iOS 中如何集成ijk ...

  9. iOS开发UI篇—Button基础

    iOS开发UI篇—Button基础 一.简单说明 一般情况下,点击某个控件后,会做出相应反应的都是按钮 按钮的功能比较多,既能显示文字,又能显示图片,还能随时调整内部图片和文字的位置 二.按钮的三种状 ...

随机推荐

  1. iOS 技能集结号

    1. 获取磁盘总空间大小 2. 获取磁盘可用空间大小 3. 获取指定路径下某个文件的大小 4. 获取文件夹下所有文件的大小 5. 获取字符串(或汉字)首字母 6. 将字符串数组按照元素首字母顺序进行排 ...

  2. USACO Section 5.3 Big Barn(dp)

    USACO前面好像有类似的题目..dp(i,j)=min(dp(i+1,j),dp(i+1,j+1),dp(i,j+1))+1  (坐标(i,j)处无tree;有tree自然dp(i,j)=0) .d ...

  3. Mysql开启远程

    改表法: x:\>mysql -u root -pvmware mysql> use mysql;mysql> update User set Host = ‘%’ where Us ...

  4. [LeetCode]题解(python):085-Maximal Rectangle

    题目来源: https://leetcode.com/problems/maximal-rectangle/ 题意分析: 给定一个二维的二进制矩阵,也就是只包括0 和 1的,找出只包括1的最大的矩阵的 ...

  5. shell学习-读取输入

    功能:读取输入,打印:如果长度小于MINLEN,那么输出空格. #!/bin/bash # paragraph-space.sh # Insert a blank line between parag ...

  6. ASP.NET MVC进阶之路:深入理解依赖注入(DI)和控制反转(IOC)

    0X1 什么是依赖注入 依赖注入(Dependency Injection),是这样一个过程:某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只定义一个注入点.在程序运行过程中,客户 ...

  7. viewpager的layout_width="wrap_content"无效问题

    在viewpager当中直接使用layout_width="wrap_content"是无效的,扩展了一下.解决这个问题. package com.soulagou.ui; imp ...

  8. 基于Visual C++2013拆解世界五百强面试题--题17-程序结果分析1

    分析程序结果,分析过程我们就写在程序注释里面. 写出下列代码的输出内容 #include <stdio.h> int inc(int a) { return (++a); } int mu ...

  9. 字符串模式匹配KMP算法

    一篇不错的博客:http://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html KMP字符串模式匹配通俗点说就是一种在一个字符串中 ...

  10. Flex 按钮添加图标

    第一种是在Flex应用中创建一个变量,利用[Bindable]和[Embed] ,在代码中以参数形式传入制定图标(icon)的路径,然后利用类似icon="{Icon}"的代码嵌入 ...