关于图像处理中的卷积运算,这里有两份简明扼要的介绍:文一文二

其中,可能的一种卷积运算代码如下:

  1. - (UIImage*)applyConvolution:(NSArray*)kernel
  2. {
  3. CGImageRef inImage = self.CGImage;
  4. CFDataRef m_DataRef = CGDataProviderCopyData(CGImageGetDataProvider(inImage));
  5. CFDataRef m_OutDataRef = CGDataProviderCopyData(CGImageGetDataProvider(inImage));
  6. UInt8 * m_PixelBuf = (UInt8 *) CFDataGetBytePtr(m_DataRef);
  7. UInt8 * m_OutPixelBuf = (UInt8 *) CFDataGetBytePtr(m_OutDataRef);
  8. int h = CGImageGetHeight(inImage);
  9. int w = CGImageGetWidth(inImage);
  10. int kh = [kernel count] / 2;
  11. int kw = [[kernel objectAtIndex:0] count] / 2;
  12. int i = 0, j = 0, n = 0, m = 0;
  13. for (i = 0; i < h; i++) {
  14. for (j = 0; j < w; j++) {
  15. int outIndex = (i*w*4) + (j*4);
  16. double r = 0, g = 0, b = 0;
  17. for (n = -kh; n <= kh; n++) {
  18. for (m = -kw; m <= kw; m++) {
  19. if (i + n >= 0 && i + n < h) {
  20. if (j + m >= 0 && j + m < w) {
  21. double f = [[[kernel objectAtIndex:(n + kh)] objectAtIndex:(m + kw)] doubleValue];
  22. if (f == 0) {continue;}
  23. int inIndex = ((i+n)*w*4) + ((j+m)*4);
  24. r += m_PixelBuf[inIndex] * f;
  25. g += m_PixelBuf[inIndex + 1] * f;
  26. b += m_PixelBuf[inIndex + 2] * f;
  27. }
  28. }
  29. }
  30. }
  31. m_OutPixelBuf[outIndex]     = SAFECOLOR((int)r);
  32. m_OutPixelBuf[outIndex + 1] = SAFECOLOR((int)g);
  33. m_OutPixelBuf[outIndex + 2] = SAFECOLOR((int)b);
  34. m_OutPixelBuf[outIndex + 3] = 255;
  35. }
  36. }
  37. CGContextRef ctx = CGBitmapContextCreate(m_OutPixelBuf,
  38. CGImageGetWidth(inImage),
  39. CGImageGetHeight(inImage),
  40. CGImageGetBitsPerComponent(inImage),
  41. CGImageGetBytesPerRow(inImage),
  42. CGImageGetColorSpace(inImage),
  43. CGImageGetBitmapInfo(inImage)
  44. );
  45. CGImageRef imageRef = CGBitmapContextCreateImage(ctx);
  46. CGContextRelease(ctx);
  47. UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
  48. CGImageRelease(imageRef);
  49. CFRelease(m_DataRef);
  50. CFRelease(m_OutDataRef);
  51. return finalImage;
  52. }

方法的参数kernel是卷积运算中的卷积核,下面是几种滤镜的卷积核:

  1. #pragma mark -
  2. #pragma mark - Basic Convolutions
  3. /* Reference :
  4. * http://docs.gimp.org/en/plug-in-convmatrix.html
  5. */
  6. - (UIImage *)sharpen
  7. {
  8. //  double dKernel[5][5] = {
  9. //      {0,  0.0, -1.0,  0.0, 0},
  10. //      {0, -1.0,  5.0, -1.0, 0},
  11. //      {0,  0.0, -1.0,  0.0, 0}
  12. //    };
  13. double dKernel[5][5] = {
  14. {0, 0.0, -0.2,  0.0, 0},
  15. {0, -0.2, 1.8, -0.2, 0},
  16. {0, 0.0, -0.2,  0.0, 0}
  17. };
  18. NSMutableArray *kernel = [[[NSMutableArray alloc] initWithCapacity:5] autorelease];
  19. for (int i = 0; i < 5; i++) {
  20. NSMutableArray *row = [[[NSMutableArray alloc] initWithCapacity:5] autorelease];
  21. for (int j = 0; j < 5; j++) {
  22. [row addObject:[NSNumber numberWithDouble:dKernel[i][j]]];
  23. }
  24. [kernel addObject:row];
  25. }
  26. return [self applyConvolution:kernel];
  27. }
  28. - (UIImage *)edgeEnhance
  29. {
  30. double dKernel[5][5] = {
  31. {0,  0.0,  0.0,  0.0, 0},
  32. {0, -1.0,  1.0,  0.0, 0},
  33. {0,  0.0,  0.0,  0.0, 0}
  34. };
  35. NSMutableArray *kernel = [[[NSMutableArray alloc] initWithCapacity:5] autorelease];
  36. for (int i = 0; i < 5; i++) {
  37. NSMutableArray *row = [[[NSMutableArray alloc] initWithCapacity:5] autorelease];
  38. for (int j = 0; j < 5; j++) {
  39. [row addObject:[NSNumber numberWithDouble:dKernel[i][j]]];
  40. }
  41. [kernel addObject:row];
  42. }
  43. return [self applyConvolution:kernel];
  44. }
  45. - (UIImage *)edgeDetect
  46. {
  47. double dKernel[5][5] = {
  48. {0,  0.0,  1.0,  0.0, 0},
  49. {0,  1.0, -4.0,  1.0, 0},
  50. {0,  0.0,  1.0,  0.0, 0}
  51. };
  52. NSMutableArray *kernel = [[[NSMutableArray alloc] initWithCapacity:5] autorelease];
  53. for (int i = 0; i < 5; i++) {
  54. NSMutableArray *row = [[[NSMutableArray alloc] initWithCapacity:5] autorelease];
  55. for (int j = 0; j < 5; j++) {
  56. [row addObject:[NSNumber numberWithDouble:dKernel[i][j]]];
  57. }
  58. [kernel addObject:row];
  59. }
  60. return [self applyConvolution:kernel];
  61. }
  62. - (UIImage *)emboss
  63. {
  64. double dKernel[5][5] = {
  65. {0, -2.0, -1.0,  0.0, 0},
  66. {0, -1.0,  1.0,  1.0, 0},
  67. {0,  0.0,  1.0,  2.0, 0}
  68. };
  69. NSMutableArray *kernel = [[[NSMutableArray alloc] initWithCapacity:5] autorelease];
  70. for (int i = 0; i < 5; i++) {
  71. NSMutableArray *row = [[[NSMutableArray alloc] initWithCapacity:5] autorelease];
  72. for (int j = 0; j < 5; j++) {
  73. [row addObject:[NSNumber numberWithDouble:dKernel[i][j]]];
  74. }
  75. [kernel addObject:row];
  76. }
  77. return [self applyConvolution:kernel];
  78. }

在此基础上,我Google了下Photoshop中对照片进行黑白处理的简单步骤:

  1. 去色
  2. 调整对比度
  3. 高斯模糊
  4. 浮雕效果
  5. 边缘检测
  6. 调整对比度
  7. 调整亮度
  8. 反相

我按步骤实现了相应代码:

  1. return [[[[[[[[originImage desaturate]
  2. changeContrastByFactor:1.5]
  3. gaussianBlur:1.3] emboss]
  4. edgeDetect]
  5. changeContrastByFactor:1.5]
  6. changeBrightnessByFactor:1.5]
  7. invert];

可惜效果有点粗糙,照片仍旧以上一篇文章中的Andy为例:

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

iOS中的图像处理(二)——卷积运算的更多相关文章

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

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

  2. ios 中的构造方法(二)

    在之前有简单介绍了构造方法的结构,以及构造方法的作用,那么我们现在来讨论一下: 对象的创建分为两步:+ alloc 分配内存空间和 -init 进行初始化 那么在继承自 NSObject 的类当中,我 ...

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

    最近在稍微做一些整理,翻起这部分的代码,发现是两个多月前的了. 这里讨论的是基于RGBA模型下的图像处理,即将变换作用在每个像素上. 代码是以UIImage的category形式存在的: typede ...

  4. [OpenCV-Python] OpenCV 中的图像处理 部分 IV (二)

    部分 IVOpenCV 中的图像处理 OpenCV-Python 中文教程(搬运)目录 16 图像平滑 目标 • 学习使用不同的低通滤波器对图像进行模糊 • 使用自定义的滤波器对图像进行卷积(2D 卷 ...

  5. ios 中生成二维码和相册中识别二维码

    iOS 使用CIDetector扫描相册二维码.原生扫描 原生扫描 iOS7之后,AVFoundation让我们终于可以使用原生扫描进行扫码了(二维码与条码皆可)AVFoundation可以让我们从设 ...

  6. Quartz 2D在ios中的使用简述二:创建画布

    在iOS中使用Quartz画图时,第一步就是要获取画布(图形上下文),然后再画布上做各种操作.先看下CoreGraphics.h这个头文件,就可以知道能够创建多少种上下文类型. #include &l ...

  7. 卷积运算的本质,以tensorflow中VALID卷积方式为例。

    卷积运算在数学上是做矩阵点积,这样可以调整每个像素上的BGR值或HSV值来形成不同的特征.从代码上看,每次卷积核扫描完一个通道是做了一次四重循环.下面以VALID卷积方式为例进行解释. 下面是pyth ...

  8. iOS中的二维数组

    首先我们知道OC中是没有二维数组的,二维数组是通过一位数组的嵌套实现的,但是别忘了我们有字面量,实际上可以和C/C++类似的简洁地创建和使用二维数组.这里总结了创建二维数组的两种方法以及数组的访问方式 ...

  9. iOS中的crash防护(二)KVC造成的crash

      接上篇< iOS中的crash防护(一)unrecognized selector sent to instance> 我们攻克了找不到方法实现的crash,这一篇我这里主要分析一下在 ...

随机推荐

  1. c/c++ double的数字 转成字符串后 可以有效的避免精度要求不高的数

    char n[100]; sprintf(n,"%lf",db);

  2. USB 开发

    http://blog.csdn.net/myarrow/article/details/8484113

  3. HOOK API(三)—— HOOK 所有程序的 MessageBox

    HOOK API(三) —— HOOK 所有程序的 MessageBox 0x00 前言 本实例要实现HOOK MessageBox,包括MessageBoxA和MessageBoxW,其实现细节与H ...

  4. BZOJ 1834: [ZJOI2010]network 网络扩容(最大流+最小费用最大流)

    第一问直接跑最大流.然后将所有边再加一次,费用为扩容费用,容量为k,再从一个超级源点连一条容量为k,费用为0的边到原源点,从原汇点连一条同样的边到超级汇点,然  后跑最小费用最大流就OK了. ---- ...

  5. mysql中varchar最长多少

    4.0版本以下,varchar(20),指的是20字节,如果存放UTF8汉字时,只能存6个(每个汉字3字节) 5.0版本以上,varchar(20),指的是20字符,无论存放的是数字.字母还是UTF8 ...

  6. IOS 学习笔记(4) 控件 标签(UILabel)的使用方法

    虽说Label的中文翻译是标签标记,但它其实是一个静态文本内容的展现控件. 一般来说,UILabel只是一个只读的文本视图,开发者可以利用UiLabel来展示内容长度有固定上限的文字内容.并且,UIL ...

  7. android 子线程更新UI

    参考http://examples.javacodegeeks.com/android/core/os/handler/android-handler-example/package com.exam ...

  8. C#手机充值

    C#手机充值系统开发(基于聚合数据) 说是手机充值系统有点装了,其实就是调用了聚合数据的支付接口,其实挺简单的事 但是我发现博客园竟然没有类似文章,我就个出头鸟把我的代码贡献出来吧 首先说准备工作: ...

  9. 帝国cms7.0判断字段为空,显示为不同

    在一些情况下,我们的字段会留空,但是又不希望内容模板上只显示空.比如,在后台,如添加作者为小明,则显示小明,不填作者则显示"佚名",我们可以用以下代码. <? if($nav ...

  10. delphi 编译生成ipa文件

    找IPA文件 开发模式ipa文件和发布模式ipa文件,路径不同. http://www.itnose.net/detail/6101808.html 一.开发模式Development 不需要真机,可 ...