AForge.NET 开源框架






4.97/5 (147投票s)
本文介绍了一个用于计算机视觉和人工智能领域研究人员的开源 C# 框架 - 图像处理、神经网络、遗传算法等。
引言
过去两年里,我一直在从事一些计算机视觉和人工智能领域的研究项目。因此,产生了大量的代码,并在 Code Project 上发表了几篇文章,描述了其中的一些领域。在发表这些文章时,我发现这些领域不仅对我个人感兴趣,也引起了广大开发者的兴趣。自我在 Code Project 发表第一篇文章以来,我收到了来自世界各地许多人的电子邮件,他们将我的代码应用于各种各样的应用程序。其中一些人不仅对使用我的代码感兴趣,还希望扩展我的项目并为其做出贡献。从第一次收到这样的提议开始,一个开源项目的想法便久久萦绕在我心头。
本文的目的是正式发布一个新的开源项目 AForge.NET - 一个面向计算机视觉和人工智能领域研究人员的 C# 框架。该框架总结了我之前在这些领域的大部分工作,并将不断扩展新想法。目前,该框架包含三个重要部分,这些部分在我之前的几篇文章中已详细讨论过:
- 图像处理
- 神经网络
- 进化算法
启动这个项目,我们不仅仅是想将所有先前不同领域的源代码汇集起来,并原封不动地提供给社区。除了提供多个库及其源代码外,该框架还提供了许多示例应用程序来演示框架的使用,以及 HTML Help 格式的文档,可用作参考。该项目的目标不仅是扩展其功能,还要提供支持,改进和扩展其文档和示例应用程序集。
图像处理库
图像处理库包含一套图像处理过滤器和工具,用于处理计算机视觉 [^] 和图像分析/处理 [^] 的众多不同任务。目前,该库包含以下过滤器,并且随着新过滤器的开发,其数量不断增加:
- 颜色过滤器(灰度、怀旧、反色、通道旋转、通道提取、通道替换、通道滤波、颜色滤波、欧几里得颜色滤波、RGB 通道线性校正)
- HSL 过滤器(线性校正、亮度、对比度、饱和度、色调修改器、HSL 滤波)
- YCbCr 过滤器(线性校正、YCbCr 滤波、通道提取/替换)
- 二值化过滤器(阈值、带进位的阈值、有序抖动、拜耳抖动、Floyd-Steinberg、Burkes、Jarvis-Judice-Ninke、Sierra、Stevenson-Arce、Stucki 抖动方法)
- 自适应二值化(简单图像统计);
- 数学形态学过滤器(腐蚀、膨胀、开运算、闭运算、击中/未击中、细化、粗化)
- 卷积滤波器(均值、模糊、锐化、边缘、高斯模糊、基于高斯核的锐化)
- 2 个源过滤器(合并、交集、相加、相减、差值、向内移动、变形)
- 边缘检测器(同质性、差值、Sobel、Canny)
- 伽马校正,中值滤波器
- 保守平滑,抖动,油画,像素化,简单骨架化
- 斑点计数器和连通组件标记过滤器
- 纹理生成器(云、大理石、木纹、迷宫、纺织品),纹理化器,纹理滤波器,纹理合并滤波器
- 缩放和旋转(最近邻,双线性,三次样条)
- FFT 频率滤波
- 图像统计
在使用库例程之前,需要确保源图像是库支持的两种格式之一(每像素 24 位彩色图像或每像素 8 位索引图像表示的灰度图像)。
// load an image
System.Drawing.Bitmap image = (Bitmap) Bitmap.FromFile( fileName );
// format image
AForge.Imaging.Image.FormatImage( ref image );
该库描述了两个主要接口:IFilter
和 IInPlaceFilter
,所有图像处理过滤器都应实现这两个接口。第一个接口是所有过滤器必须实现的,描述了它们的功能。这允许在不修改源图像的情况下将过滤器应用到源图像。相反,图像处理例程会返回一个新图像,而源图像保持不变。第二个接口仅由那些可以直接应用于源图像并更新它的过滤器实现。
下面的示例代码演示了如何使用一个可以直接应用于源图像的过滤器。
// create filter
HSLFiltering filter = new HSLFiltering(
new IntRange( 330, 30 ), // hue range
new DoubleRange( 0.5, 1 ), // saturation range
new DoubleRange( 0, 1 ) ); // luminance range
filter.UpdateLuminance = false;
filter.UpdateHue = false;
// apply the filter
filter.ApplyInPlace( sourceImage );
上面的示例演示了 HSL 过滤器的使用,该过滤器保留指定 HSL 范围内的像素,并清除范围外的像素。通过附加的配置属性,可以清除像素的特定 HSL 通道,而不是整个像素。上面的示例保留了饱和度大于 0.5 的红色,其他颜色则转换为灰度。
![]() |
下一个示例演示了使用一个生成新图像作为其工作结果的过滤器的用法。
// create filter
IFilter filter = new FloydSteinbergDithering( );
// apply the filter
Bitmap newImage = filter.Apply( sourceImage );
此示例演示了称为 Floyd-Steinberg 二值化的二值化算法的使用。
![]() |
神经网络库
神经网络库实现了几种常见的流行神经网络概念。它可以应用于使用监督学习算法的多层前馈网络或使用无监督学习算法的自组织网络所能解决的各种问题 [^]。在设计该库时,主要思想是保持其灵活性和可重用性。这样可以轻松地将新神经网络架构和学习算法扩展到库中,并且可以将其应用于解决范围广泛的其他问题。
例如,我们来看一下如何用该库解决一些常见问题。下面的代码示例演示了如何将该库应用于分类问题。
// prepare learning data
double[][] input = new double[samples][];
double[][] output = new double[samples][];
// ... preparing the data ...
// create perceptron
ActivationNetwork network = new ActivationNetwork( new ThresholdFunction( ),
2, classesCount );
// create teacher
PerceptronLearning teacher = new PerceptronLearning( network );
// set learning rate
teacher.LearningRate = learningRate;
// loop
while ( ... )
{
// run epoch of learning procedure
double error = teacher.RunEpoch( input, output );
...
}
上面的代码示例可以分为三个主要部分:1)准备学习数据,2)创建和初始化神经网络和学习算法,3)训练网络。我们再来看另一个代码示例,它解决了截然不同的问题——逼近。
// prepare learning data
double[][] input = new double[samples][];
double[][] output = new double[samples][];
// ... preparing the data ...
// create multi-layer neural network
ActivationNetwork network = new ActivationNetwork(
new BipolarSigmoidFunction( sigmoidAlphaValue ),
1, neuronsInFirstLayer, 1 );
// create teacher
BackPropagationLearning teacher = new BackPropagationLearning( network );
// set learning rate and momentum
teacher.LearningRate = learningRate;
teacher.Momentum = momentum;
// loop
while ( ... )
{
// run epoch of learning procedure
double error = teacher.RunEpoch( input, output ) / samples;
...
}
![]() |
代码看起来与上面的代码非常相似,并且也可以分为相同的三个部分。这两个代码示例之间的唯一区别是学习数据准备例程以及一些网络/学习算法参数。当然,不同的问题有不同的输入和输出数据,因此它们在神经网络学习的数据准备方式上可能有所不同。但除此之外,这两个代码示例在概念上非常相似。
上面的两个示例演示了如何使用监督学习算法和前馈网络。现在,我们来看另一个示例,它利用了完全不同的神经网络架构——Kohonen 自组织映射,并将其应用于颜色聚类任务。
// set neurons weights randomization range
Neuron.RandRange = new DoubleRange( 0, 255 );
// create network
DistanceNetwork network = new DistanceNetwork( 3, 100 * 100 );
// create learning algorithm
SOMLearning trainer = new SOMLearning( network );
// input
double[] input = new double[3];
// loop
while ( ... )
{
// update learning rate and radius
// ...
// prepare network input
input[0] = rand.Next( 256 );
input[1] = rand.Next( 256 );
input[2] = rand.Next( 256 );
// run learning iteration
trainer.Run( input );
...
}
![]() |
这个示例的概念在某些方面与上面两个示例相似。是的,它跳过了数据准备的第一步。但示例是在运行每个学习迭代之前准备数据的。与对整个数据集(学习轮次)运行学习算法不同,学习算法只针对刚刚准备好的数据样本运行。
进化算法库
进化计算库实现了几种流行的算法,如遗传算法(GA)、遗传编程(GP)和基因表达编程(GEP)。这使其适用于许多不同类型的问题 [^]。该库的设计理念与整个库保持一致——使其灵活、可重用且易于使用。
与神经网络库一样,进化库的使用对于各种问题来说都非常简单且类似。为了说明这一点,我们将看两个例子:1)函数优化和 2)函数逼近。
函数优化
// define optimization function
public class UserFunction : OptimizationFunction1D
{
public UserFunction( ) :
base( new DoubleRange( 0, 255 ) ) { }
public override double OptimizationFunction( double x )
{
return Math.Cos( x / 23 ) * Math.Sin( x / 50 ) + 2;
}
}
...
// create genetic population
Population population = new Population( 40,
new BinaryChromosome( 32 ),
new UserFunction( ),
new EliteSelection( ) );
// run one epoch of the population
population.RunEpoch( );
![]() |
函数逼近
// function to be approximated
double[,] data = new double[5, 2] {
{1, 1}, {2, 3}, {3, 6}, {4, 10}, {5, 15} };
// create population
Population population = new Population( 100,
new GPTreeChromosome( new SimpleGeneFunction( 6 ) ),
new SymbolicRegressionFitness( data, new double[] { 1, 2, 3, 5, 7 } ),
new EliteSelection( ),
0.1 );
// run one epoch of the population
population.RunEpoch( );
上面的两个示例代码看起来非常相似。最大的区别在于定义进化算法适应度函数的章节。在第一个示例中,适应度函数是通过要优化的函数的定义来确定的。在第二个示例中,使用了库中的标准适应度函数,并且只为其准备了初始化数据。这两个示例的其余部分在细节上可能有所不同,但概念上仍然非常相似。
大多数示例如此相似的事实是通过实现大多数进化计算实体为单独的类来实现的。这使得它们可以像乐高积木一样被轻松重用和组合,以解决特定的任务。
更多示例
正如本文开头所述,该框架不仅提供了一套库及其源代码,还为框架的每个领域提供了一套示例应用程序。从这个角度来看,建议访问该项目的主页,以获取所有最新的更新和版本,以及获得支持并参与讨论组。
项目主页
正如开源项目通常那样,它有一个主页,提供项目的访问信息、源代码、稳定版本、讨论组和问题跟踪系统。目前,该项目在Google Code 上拥有自己的空间,可通过以下链接访问:http://code.google.com/p/aforge/。
![]() |
为什么选择 Google Code?正如所见,Google 是一个发展极其迅速的公司,每天都提供越来越多的服务。而且,正如可以注意到的,所有这些服务都质量很高,并且高度集成到复合系统中。因此,相信通过与 Google 合作,该项目将有一个良好的发展空间。
访问源代码和稳定版本
Google Code 项目使用Subversion 作为源代码管理系统,它非常方便易用。要访问项目存储库,您可以使用命令行工具,因为有各种客户端工具可供选择。至于我,我更喜欢使用Tortoise SVN 客户端,它与 Windows Explorer 集成,并通过一个不错的 GUI 提供对存储库的访问。
为了跟上最新进展,您可以不时地检查存储库日志。这将为您提供有关所有最新提交的信息——它们的时间和说明——其中描述了在特定提交中具体更改/添加的内容。
![]() |
如果您注意到工作存储库中的任何更改,并且您足够勇敢或愿意获取对您感兴趣的关键更新,那么您可以从项目的工作文件夹(trunk)获取最新的源代码快照。但如果您想确保您收到的内容,并且想要更稳定的版本,那么建议从已知最新标签下载项目。要浏览项目存储库并了解其结构和可用的分支或标签,您可以使用 Repo-browser 工具,该工具可从 Explorer 的上下文菜单中访问。
![]() |
提交问题和功能请求
正如通常发生的那样,项目并不完美,可能存在各种错误或问题,应报告并放入修复队列。此外,显然许多不同的人可能想要获得额外的功能或有其他扩展项目的请求。为了集中存储所有这些问题和请求,项目有一个问题跟踪系统,允许提交任何类型的问题,并标记其类型、优先级和区域。问题跟踪系统也可从项目主页访问,并由 Google Code 提供。
![]() |
请注意,如果您发现错误或有扩展请求,请尝试通过项目的问题跟踪系统提交,而不是通过 CodeProject。这将大大简化跟踪所有这些不同问题的难度,并且它们将被存储在一个集中的地方,因此可以搜索某个问题及其状态,避免反复提交。
参与项目
您对项目感兴趣吗?您想参与讨论吗?您想成为项目的一员吗?如果是,欢迎您加入项目的讨论组。
结论
在参与这个项目的过程中,我在许多不同的领域学到了很多东西。这个项目不仅成了我的爱好,它的部分内容还被用于我的学士学位论文、各种研究工作和项目中。将所有这些结合起来并作为开源项目分享,也给了我在项目管理、控制和组织方面的新经验。我希望这个项目能引起更多人的兴趣,并被许多人使用。我希望有些人甚至会加入进来,从而用新的想法来扩展它。
历史
- [2007.05.18] - 文章从 C# 算法子分类“神经网络”移动到“通用”子分类
- [2007.05.16] - 文章已编辑并发布到 CodeProject.com 主要文章库
- [2007.02.23] - 1.1.0 版本
- 项目已转换为 .NET 2.0
- 已完成与旧的独立成像和数学库的合并;
- 使用 Sandcastle 生成文档
- [2006.12.22] - 文章首次发布,框架 1.0.0 版本发布,开源项目正式启动