C#开发学习人工智能的第一步
前言
作为一个软件开发者,我们除了要学会复制,黏贴,还要学会调用api和优秀的开源类库。
也许,有人说c#做不了人工智能,如果你相信了,那只能说明你的思想还是狭隘的。
做不了人工智能的不是c#这种语言,而是你,我这种普通的程序员。
做人工智能需要一定的学历背景,一定的数学基础和公司专项的资源供给;而这种机缘小之又小,你我既然是普通的程序员,就必然与此无缘。
但在人工智能如日中天的当下,接触深度学习是必然会发生的事情,所以我们要做的就是,学会调用相关的类库。
现在,让我们迈出c#学习人工智能的第一步,通过调用affdex来锁定图片中人物的面部,然后将其截取出来。
准备工作
首先,我们需要先访问官网下载affdex的sdk。
在官网找中找到下载affdex的sdk的地方也是个挺困难的事。。。所以下载链接如下:
进入网页后,向下拉动滚动条,找到到下图所示位置,点击download进行下载。
下载完成后得到sdk,如下图:
下面,我们双击进行安装,不过安装sdk有一些限制,需要预先安装net framework4.0和c++ 2015。如果电脑里已经安装了,就不必担心了;如果安装的是c++2015-2017这类型的,则需要卸载了,重新安装c++2015的版本,否则affdex的sdk将安装失败。
安装完成后,我们去安装目录找到affdex.dll,affdex-native.dll,tensorflow.dll三个文件,如下图:
我们先将它们复制出来,等待使用。
简单的介绍一下,这三个类库中,affdex.dll是可以被c#项目直接引用的,而另外两个文件是affdex.dll的依赖文件;也就是说,affdex-native.dll,tensorflow.dll需要在生成时,输出到运行目录下。
有经验的朋友想必已经发现了,这里有个类库名叫tensorflow.dll,tensorflow是什么啊?稍微百度一下大家就会了解了,它是专门来做深度学习的。
也就是说affdex是支持深度学习的。
----------------------------------------------------------------------------------------------------
现在我们来学习affdex的使用。
首先我们新建一个wpf项目,然后引用affdex.dll。
然后将项目的运行平台设置为64位,因为,这样处理图片的速度能快一点,如下图:
在affdex中我们可以发现四个探头—videodetector,photodetector,framedetector,cameradetector。
在这里我们要处理的是图片,所以我们选择photodetector,下面我们创建一个photowindow.xaml页面来使用photodetector处理图片。
代码实现
首先,我们定义一个photodetector的属性,用于处理图片。
然后我们在构造函数中对他进行实例化,代码如下:
private affdex.photodetector detector { get; set; }
public photowindow()
{
initializecomponent();
uint maxnumfaces = 1;//最多识别图片中几张脸
detector = new affdex.photodetector(maxnumfaces, affdex.facedetectormode.small_faces);
detector.setimagelistener(this);
detector.setprocessstatuslistener(this);
detector.start();
}
在上述代码中可以看到,除了初始化photodetector,我们还做了一个图片监听设置setimagelistener,那么图片监听是干什么的呢?
很简单,图片被photodetector处理完,我们需要知道图片处理结果呀,而这个图片监听正是是用来返回图片处理结果的。
可以看到图片监听设置的入参是this,也就是说,需要把图片的处理结果返回给当前页面。
如果就这样写是会编译报错的,会提示setimagelistener的入参错误。
我们查看setimagelistener的入参,发现它的入参是一个imagelistener接口,即,setimagelistener的入参是一个要实现了imagelistener接口的类。
到这里,我们就都明白了,现在我们让当前photowindow.xaml窗体继承接口imagelistener,并实现接口imagelistener内的方法。
public partial class photowindow : window, affdex.imagelistener
===========================================================================
public void onimagecapture(affdex.frame frame)
{
}
public void onimageresults(dictionary<int, face> faces, affdex.frame frame)
{
}
如上述代码所示,在我们实现的接口onimageresults里有两个参数:faces、frame。
其中faces是最重要的,这里包含affdex分析图片的结果。
----------------------------------------------------------------------------------------------------
现在,affdex的配置代码已经写完了,我们可以把图片读取出来调用affdex处理了。
public photowindow()
{
initializecomponent();
uint maxnumfaces = 1;//最多识别图片中几张脸
detector = new affdex.photodetector(maxnumfaces, affdex.facedetectormode.small_faces);
detector.setimagelistener(this);
detector.start();
byte[] bytes = filehelper.filetobytes(system.io.path.combine(system.appdomain.currentdomain.basedirectory, "timg.jpg"));
bitmapsource bitmapsource = imagehelper.bytestobitmapimage(bytes);
var w = bitmapsource.width;
var h = bitmapsource.height;
var stride = bitmapsource.format.bitsperpixel * (int)w / 8; //计算stride
byte[] bytelist = new byte[(int)h * stride];
bitmapsource.copypixels(bytelist, stride, 0);
affdex.frame frame = new affdex.frame((int)w, (int)h, bytelist, affdex.frame.color_format.bgra);
detector.process(frame);
}
如上述代码所示,我们在启动了detector后,读取了一个人物图片,然后把人物图片的像素数组解析出来,生成一个frame;这个frame是affdex的类,用于保存图像数据信息。
最后,我们把生成的frame对象,扔给detecotor的process方法处理。
detecotor处理完成后,会触发onimageresults方法。
在onimageresults方法里,入参faces包含了处理结果。
现在我们使用faces里的内容,来定位图片中人物面部的位置。
public void onimageresults(dictionary<int, face> faces, affdex.frame frame)
{
face face = null;
if (faces != null && faces.values != null && faces.values.count() > 0)
{
face = faces.values.first();//因为我们的detector只识别了一个脸,所以这里最多只有一个数据
}
int top = (int)face.featurepoints.min(r => r.x);
int left = (int)face.featurepoints.min(r => r.y);
int bottom = (int)face.featurepoints.max(r => r.x);
int right = (int)face.featurepoints.max(r => r.y);
imagehelper.cutpicture(system.io.path.combine(system.appdomain.currentdomain.basedirectory, "timg.jpg"),
left, top, right , bottom - top);
}
如上述代码所示,我们在onimageresults里做了【最简单】人物面部坐标定位,并进行了剪切。
处理结果如下图所示:
结语
事实上,上面介绍的只是affdex最基础调用,而且,这里并没有使用到深度学习的内容,只是简单的扫描和分析。
想要使用深度学习的内容还需要进一步学习该开源控件,不过,万事开头难,我们现在已经迈出了第一步。
----------------------------------------------------------------------------------------------------
到此c#开发学习人工智能的第一步就完成了。
代码已经传到github上了,欢迎大家下载。
github地址:https://github.com/kiba518/wpfaffdex
----------------------------------------------------------------------------------------------------
注:此文章为原创,任何形式的转载都请联系作者获得授权并注明出处!
若您觉得这篇文章还不错,请点击下方的【推荐】,非常感谢!