Core Image提供了很多滤镜,这里介绍自己开发Core Image滤镜的方法,相信会对一些朋友有用。

 

本文通过一个例子从头至尾介绍了如何开发一个将彩色图片转换为灰度图片的滤镜,并介绍了滤镜的使用方法。

 

原文作者是Andy Finnell,他参与了Adobe Fireworks的开发。

原文地址是 http://www.losingfight.com/blog/2007/01/13/grayscale-for-the-greater-good/

 

建立项目

 

我希望建立一个图片滤镜插件,幸运地是,XCode已经自带了一个开发滤镜插件的模板。在XCode菜单中选择File-> New Project… 选择Image Unit Plug-in for Objective-C 模板。

 

接下来取名为 Grayscale,因为这是这个插件要做的事情:灰度化图片。

 

修改描述文件

 

现在我们有了一个项目,需要做的第一件事是修改描述属性列表。Description.plst会告诉Core Image滤镜的参数、类别和在哪里能够找到插件的核心。但是需要手工修改。

 

为了让Core Image能够找到并使用滤镜,我们需要给这个滤镜一个有意义的分类。苹果已经提供了一些预先定义的分类,我们可以从中选择。当然,我们也可以修改默认的CICategoryStylize,比如选为CICategoryColorEffect。

 

修改之后的Description.plist看起来是这样的:

 

<key>CIAttributeFilterCategories</key>

<array>

<string>CICategoryColorEffect</string>

<string>CICategoryVideo</string>

<string>CICategoryStillImage</string>

</array>

 

在Description.plist中最重要的事情是修改滤镜的参数。但是看来我们在这个灰度化滤镜中除了源图片之外,并不需要任何输入参数。默认的Description.plist带有三个参数,因此我们需要删掉最后的两个参数。

 

这样就差不多了,不过我还是需要修改显示的名称,让这个名称在界面中显示。所以我们还需要修改一下Description.strings文件。

 

"MyKernelFilter" = "Demo CIKernel Only Filter";

"inputScale" = "Scale";

"inputGreenWeight" = "Green Weight";

 

由于我们不需要任何用户输入的数据,我们可以不用管后两个字符串:inputScale和inputGreenWeight。MyKernelFilter是我们滤镜的名称,所以我们要把它改为Grayscale。

 

"MyKernelFilter" = "Grayscale";

 

这样,滤镜所需的定制修改就做好了。

编写滤镜核心

我们已经设置好所有滤镜所需的资源,我们就该写一些实际的代码了。核心代码是使用Core Image Kernel Language写成的,是一个OpenGL Shading Language的子集。

 

我们打开MyKernelFilter.cikernel文件,删掉它默认的内容。加入以下的代码:

 

kernel vec4 grayscaleKernel(sampler image)

{

    // Get source pixel

    vec4   p = sample(image, samplerCoord(image));

 

// Calculate the intensity

float intensity = clamp(0.3* p.r + 0.59* p.g + 0.11* p.b, 0.0, 1.0);

 

// Set the destination pixel based on intensity

    return vec4(intensity, intensity, intensity, p.a);

}

 

函数名叫什么其实没有关系,只要它包含kernel关键字。而kernel在这里表示源图片中像素的颜色值到目标像素的颜色值的关系图。你会注意到它返回四个颜色的矢量(红、绿、蓝和Alpha),并将源图做为唯一参数使用。如果还有其他的参数,他们会跟在image这个参数后面出现,就像在Description.plist文件中写的一样。

 

上面代码第一行仅仅取出源图的点:

 vec4   p = sample(image, samplerCoord(image));

 

就像之前所述,image是做为参数传入的源文件,samplerCoord()函数返回源图片中像素的坐标。sample()函数会返回图片和坐标的像素值。