虹软c 虹软 人脸识别别SDK脸库是什么?

人脸识别SDK免费使用,让人欢喜让人忧
稿源:站长之家用户
最近对于应用人脸识别的企业来说,最让人震惊的消息莫过于免费人脸识别SDK - ArcFace的横空出世,人脸识别圈子里的人都在忙碌着尝试集成使用。ArcFace受到大家的关注与应用,不仅仅是因为它是免费的,而且是首次由全球领先的计算摄影技术开拓者和解决方案供应商——虹软公司开放,其性能上、稳定上都有很大的商业价值。整个SDK包括人脸检测、人脸跟踪和人脸识别三大功能。其目前提供了Windows、Android与iOS三个平台引擎,查看其API文档,Windows与iOS是基于C++实现的,Android则由java实现。虹软人脸识别技术免费推出,相当于给在人脸识别算法上的创业公司扔下一颗“深水炸弹”,同时也为中小企业将人脸识别技术集成到产品中去提供了最佳的桥梁。站在巨人的肩膀上创业(尽情发挥创意)人工智能领域的技术壁垒高,开发周期很长,参与者往往都要面临巨额投入却迟迟没有产出的窘境,而投资人也难以承受过高的试错成本,难免折戟沉沙。事实上,在很多行业,人工智能也只是工具、桥梁,让具有创意的产品与应用更完美。在这个产业链中酝酿着许许多多具有创新意识的企业家,创业者。对于他们来说开发人工智能技术是不太现实的,而购买技术又没有条件。此次虹软将人脸识别技术免费提供给开发者,注定激活了大量对人脸识别技术有需求的中小企业家、创业者,促使他们在人工智能领域上的起跑线往前拉了一大步,给他们带来了更多的创新机遇,让他们可以做更多、更快、更直接的探索。算法公司还想靠人脸识别SDK赚钱吗?虹软人脸识别的免费,也给同行出了一个大的难题;很多原先想在人脸识别算法程序上捞钱的公司应该会有看法。目前提供人脸识别算法的公司一般通过三种形式赚钱,一种是开放API接口,通过云平台提供人脸服务,一般通过调用次数与带宽、空间收费;这类方式数据隐私是最大的问题,而且也无法实现人脸跟踪的功能。另一种是像虹软一样提供SDK引擎包,但是这个价格往往很高,让创业者望而兴叹。第三种是软硬结合,打包销售人脸识别技术,但是这种方式也会加大使用者的成本,而且二次集成也不友好。虹软免费的做法,应该会让此类算法公司不太好过。
有好的文章希望站长之家帮助分享推广,猛戳这里
本网页浏览已超过3分钟,点击关闭或灰色背景,即可回到网页人脸识别技术:“免费”背后的野望|人工智能|虹软|中小企业_新浪财经_新浪网
如今,刷脸已经不是时髦的玩意儿,而逐渐成为一种标配。刷脸门禁比比皆是,人脸识别已然成为门禁的基础刚需技术。几个月前刷脸取厕纸还饱受关注甚至争议,如今若干省市纷纷仿效。人脸识别技术,究竟可以多大程度的改变生活,能想象的空间实在十分巨大。而就在近期,虹软公司在其官网发布免费 人脸识别技术,并宣称永久免费,区别于其他人脸识别技术云平台服务,虹软在技术上开放的更彻底,直接提供的SDK引擎更具有灵活性,此举一石更是激起千层浪。令人百思不得其解的是,究竟虹软是出于什么原因,要让人脸识别技术进入免费时代。
现状:中小企业AI创新应用的痛点
近两年各行业对于人工智能技术的需求越来越多,增长非常快;正如虹软官网宣称,从行业用户、商业用户、到个人用户,在门禁、考勤、通道、卡口、智能家居、、医疗、制造、金融、安防监控……以及更多领域有着迫切的应用需求。然而,从基础技术到真正的产品,中间需要历经较长的周期,从算法实现到产品化的成本非常高,构筑了中小企业进入AI领域的技术门槛 。
人工智能要落地,中小企业要发展,必须打破现有的思维模式,只有让中小企业使用无成本,无门槛,让算法真正能够服务于各个行业、各个领域中去,才能让人工智能技术惠及民生。
免费策略,其背后的战略高度和品牌价值
免费——不仅仅在中国是最成功的商业模式之一,全球成功的案例比比皆是。免费模式看中的不是短期的利益,而长期的盈利一定与应用数量的积累、深入领域的程度分不开。
免费的商业模式主要有这样几种形态:
交叉补贴:一部分的免费,来自于一部分的付费。A产品免费,带动B产品(付费)的销售,用付费产品B补贴免费产品A。
第三方付费:最常见的就是互联网的广告模式。
免费+收费模式:大部分用户免费,部分用户付费。类似于基础版不收费,旗舰版需要收费的模式。
虹软在人工智能领域采用免费共享的模式,除了理想、情怀和魄力以及胸襟之外,更重要的战略高度和品牌价值才是其背后的目标。
在火热的人脸识别市场,虹软先发制人,确是一步妙招。
首先,虹软在计算机视觉领域的技术积累和积淀,让其有足够的底气和自信去搭建开放技术平台。虹软的发展可以说贯穿整个智能设备行业的变迁。人脸识别引擎,只是其长期研发的众多的视觉人工智能技术中的颇具代表性的一个,有非常成熟的商用价值。恰逢人工智能应用的需求集中在近两年爆发,虹软顺势而为,大大降低计算机视觉技术的应用门槛,激发中小企业的智造力,或许将带来一轮人工智能领域应用和创新创业的热潮爆发。对于全行业和产业链条都是正收益 。
其次,开放人工智能技术的当红炸子鸡——“人脸识别”技术,引起的业内关注和热度,势必会带动虹软的品牌效应 。这对于虹软的现有业务有良好的带动,其技术产品众多,开放不仅对人脸识别技术有直接带动作用,对其他的技术也起到直接引流效果。即便是没有对于技术的直接营收产生立竿见影的效果,仅仅品牌效应和企业影响力的急剧增长,对于企业来说也极具价值的。
更重要的是,免费提供人脸识别SDK引擎,虹软通过技术附能聚集各行业的中小企业开发者,在垂直领域形成牢固的生态矩阵 。随着虹软人脸识别技术附能的企业越来越多,效果越来越好,区域越来越广,其达成的成就将是为全产业附能。生态组织的建立,非一朝一夕,不能计一时之得失,而最终以中小企业为细胞的生态矩阵形态的生产力、渗透力,为虹软在技术积累、市场扩张、大数据计算等领域建立强大的优势。
人工智能+行业,AI是人工智能,其实更确切的说它是增强智能。即在大数据背景下的人工智能是需要与行业结合,来增强行业中数据处理的能力,从而解决问题、提升效率。但通过什么方式和行业结合,依靠的就是无数的行业中的中小企业。
此外,技术巨头遍地开花,行业竞争激烈。乱象频出,竞争对手之间相互倾轧,甚至为了融资包装过度,无非为了在资本市场中获得一席之地。虹软开放人脸识别技术,完全免费的手段,可以迅速获取客户,先发制人抢占市场,毕竟在科技各领域的竞争都是残酷的,只有前两名可以活得好一点。当年O2O的千团大战,最终留下的也无非就是那两家而已,而烧掉的是社会的资源和资本财富。
此举相信会让已近癫狂的资本市场趋于冷静思考,对于人脸识别技术领域的健康发展能起到净化作用。
人工智能的应用前景无疑是巨大的,技术一旦落实并深入到各行业中去,真正为行业解决问题,满足客户的需求,必然会创造巨大的价值 。无论数量还是程度,互联网+的规模和范畴与其相比,都远不止几个数量级的差距。
帮助客户盈利,不管是通过提升效率、节约成本,还是通过创造蓝海市场,能想象的盈利空间巨大。有一点可以明确,中小企业抓住永久免费的契机拓展业务才是王道。 开放人脸识别技术,或许只是个开始,虹软官网显示现有开放的视觉人工智能技术还有基于深度学习的图片技术,也许后面还有更多出乎意料的彩蛋。页面已拦截
无锡网警提示您:
该网站已被大量用户举报,且存在未经证实的信息,可能会通过各种手段来盗取您的账号或骗取您的财产。没有更多推荐了,
不良信息举报
举报内容:
Android人脸识别--基于虹软免费SDK
举报原因:
原文地址:
原因补充:
最多只允许输入30个字
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!C# 实现人脸识别一 (运用虹软人脸识别引擎)知识背景:下载虹软人脸识别引擎下载地址: 目前虹软人脸识别引擎有3个平台,其中Windows与iOS是基于C++开发的,本文都是基于Windows版本下用C#实现人脸识别的,请大家注意下载的平台如何用C#调用C++的库那么,如何使用C#调用C++的库呢,C#提供了两种技术调用C++的DLL静态调用(DCOM+)动态调用(P/Invoke)我们可以将C或者C++的函数封装成COM组件,在C#中调用时比较方便,但是COM组件需要注册,而且多次注册可能也会导致一些问题,同时在处理C或者C++的类型与COM组件的类型转换的时候也可能有些麻烦采用动态的方式就是直接用C#调用C或者C++已经写好的动态链接库,这几种方式相对而言,P/Invoke要方便一些** 因此我们选择P/Invoke的方式**** P/Invoke是什么*P/Invoke的全称是Platform Invoke (平台调用) 它实际上是一种函数调用机制,通过P/Invoke我们就可以调用非托管DLL中的函数 ,实际上很多NET基类库中定义的类 型内部部调用了从Kernel32.dll,User32.dll,gdi32.dll等非托管DLL中导出的函数。来看一个简单的例子[DllImportAttribute("user32.dll", EntryPoint = "SetCursorPos")] [return: MarshalAsAttribute(UnmanagedType.Bool)] //可写可不写,定义如何封送返回参数 public static extern bool SetCursorPos(int X, int Y);这段代码的目的就是调用系统中获取鼠标参数的方法。P/INVOKE的过程关于P/Invoke的过程,我找到了MSDN上的一张图,如下所示。在使用P/Invoke调用C/C++方法时,会依次执行以下操作1 查找包含该函数的非托管DLL2 将该非托管DLL加载到内存中3 查找函数在内存中的地址并将其参数按照函数的调用约定压栈  4 将控制权转移给非托管函数注意:只在第一次调用函数时,才会查找和加载非托管DLL并查找函数在内存中的地址。当非托管函数产生异常时,P/Invoke会将异常传递给托管调用方看起来很复杂,但使用起来却很简单,只需要在C#中重新声明函数的定义就可以了,然后可以像其它函数一样调用。注意:只在第一次调用函数时,才会查找和加载非托管DLL并查找函数在内存中的地址。当非托管函数产生异常时,P/Invoke会将异常传递给托管调用方看起来很复杂,但使用起来却很简单,只需要在C#中重新声明函数的定义就可以了,然后可以像其它函数一样调用。第一步: 实现人脸检测我们希望先实现我们的简单的Hello World功能,从一张照片中检测人脸是否存在,我们称之为静态人脸检测。我们希望程序能够打开一张照片,告诉我们这张照片中是否有人脸,如果有,就需要识别并显示出来,如果没有,就提示照片中没有人脸。创建Demo项目项目技术我们使用C# 4.0版本,IDE使用Visual Studio 2013,项目就用标准的Winform项目。建立项目我们打开Visual Studio,选择C#语言,建立Winfrom项目,项目名称为FaceDetectDemo,路径随便选。立项后,项目结构如图所示:上图中的AFD和dll文件夹我们后面就会用到,刚建项目时是没有这两个文件夹的。建立视图通过设计器和工具箱,我们可以建立我们的视图界面,包括一个按钮两个PictureBox.大的那个我们用来显示完整的图片,小的用来显示识别到的人脸信息。我们把大PicturesBox的那个命名为pictureBox1,小的命名为pictureBox2,然后设置两个的SizeMode均为Zoom, 以方便我们自动显示照片。下载需要的SDK这里我们需要虹软提供的SDK中的DLL,如果你还没有下载它,那么现在就是下载的时候了。访问地址 在明显的地方找到WIndows版本,填写基本的资料后就可以下载了。下载的时候有一个版本选择,1:1,1:N之类的,我们选择默认的就可以了,1:N和1:1在人脸识别上是有差别的,但在人脸检测功能上基本上没有差异。在下载完成的页面上,会显示你申请的APPID和SDK KEY的信息,如下所示请确保牢记这些Key,因为接下来的程序中你将需要这些Key,如果忘记了,就登录刚才的那个地址,在用户中心里面可以看到这些Key,当然,你也可以在邮件中查找。我们打开下载的文件,是一个zip格式的压缩包,我们把它解压。发现里面还有三个包,我们解压其中名为Face_Detection的包。可以看到下面的目录结构命名很清晰,我这里只需要简单说一下。lib中的dll是要拷贝到你的运行目录中的,doc中的PDF相当重要,是SDK的入门指南。samplecode和inc是供C++调用时候用到的参考源码和头文件。这些都是比较重要的。现在,让我们把dll拖入到我们的应用程序的bin目录.在编辑选项时选择始终复制这个文件到输出目录.另外我们的SDK是32位系统的,所以我们还需要设置编译选项为x86.至此,项目创建工作顺利完成。一步一步,根据人脸识别的SDK代码示例来完善项目现在我们回到上一章节的四个文件夹,我们打开doc文件夹。这里面的pdf文件是我们接下来课程的基础。通读一遍,发现4个函数,3个结构体,然后2个枚举,两个变量类型,还有一段示例代码。我们来一步步定义它们.自定义数据类型C/C++ 可以定义自己的类型,打开SDK文档可以发现,这里面几乎没有我们熟悉的int,long,char*这些类型,取而代之是的Mint以及一些其它AFD开头的类型,SDK文档开篇引入了两个基础类型。typedef MInt32 AFD_FSDK_OrientP
typedef MInt32 AFD_FSDK_OrientC
所有基本类型在平台库中有定义。定义规则是在ANSIC 中的基本类型前加上字母“M”同时将类型的第一个字母改成大写。例如“long” 被定义成“MLong”
具体到上面的代码,它的意思是在项目中遇到AFD_FSDK_OrientPriority就认为是Mint32,对应C#就是int,全部的定义在inc文件夹afdcommdef.h头文件中定义结构体由于C并不是面向对象的语言,结构体作为可以自定义的类型,在一定程度的代替了我们C#中的类和对象,我们来一步步定义这些结构体。AFD_FSDK_FACERES这个结构体是用来存储脸部信息的,我们可以从文档中得到它的定义如下:typedef struct{
MRECT * rcF
AFD_FSDK_OrientCode * lfaceO
} AFD_FSDK_FACERES, * LPAFD_FSDK_FACERES;
根据我们上一节中的内容,可以知道这个MLong类似于long,rcFace和lfaceOrient则是两个指针。那么在C#中如何使用指针呢,直接用unsafe code肯定是可以的,不过这里我们使用IntPtr.IntPtr的简介
IntPtr用于表示指针或句柄的平台特定类型。这个其实说出了这样两个事实,IntPtr 可以用来表示指针或句柄、它是一个平台特定类型,它主要用在两个地方:
(1)C#调用WIN32 API时
(2)C#调用C/C++写的DLL时(其实和1相同,只是这个一般是我们在和他人合作开发时经常用到)
我们可以这样子理解,IntPtr就可以互换C++中的指针
我们根据刚才所说的定义规则,换算成C#语言的定义如下:public struct AFD_FSDK_FACERES
public int nF
public IntPtr rcF
public IntPtr lfaceO
注意:nface虽然C++中是long,但对应到C#中可不long,而是int.在32位程序中int和long占用的内存大小都是4Byte=32bit,其表示的大小都是:-~。MRECT我们在SDK文档中注意到rcFace的类型是MRect* 这里的* 说明这是一个指针类型,因此我们在定义这个类的时候使用了IntPtr,但是MRect是一个结构体,我们可在inc文件夹下面的amcomdef.h下面找到了它的定义.typedef struct __tag_rect
} MRECT, *PMRECT;
这个类型比较简单,C#版定义如下:public struct MRECT
AFD_FSDK_VERSION这个结构体定义的是我们API的版本信息,同样的我们来查看一下它的SDK的定义typedef struct
MPChar BuildD
MPChar CopyR
} AFD_FSDK_V
根据SDK开始约定,我们可以知道Mint32相当于int,MPChar相当于char*,这些自定义的变量类型可以在inc/comdef.h中查找,因此我们的对应的C#版本如下:
//定义FD的版本号
public struct AFD_FSDK_Version
public int lC
public int lM
public int lM
public int lB
public IntPtr V
public IntPtr BuildD
public IntPtr CopyR
AFD_FSDK_ORIENTCODE接下来我们来定义枚举,这里面用到的枚举有以下两个:AFD_FSDK_OrientPriority和AFD_FSDK_OrientCode,枚举比较简单。我们只需要把十六进制转换为10进制就可以了。根据SDK文档,我们需要定义的类型如下://定义人脸检查结果中人脸的角度
public enum AFD_FSDK_OrientCode
AFD_FSDK_FOC_0 = 1,
AFD_FSDK_FOC_90 = 2,
AFD_FSDK_FOC_270 = 3,
AFD_FSDK_FOC_180 = 4,
AFD_FSDK_FOC_30 = 5,
AFD_FSDK_FOC_60 = 6,
AFD_FSDK_FOC_120 = 7,
AFD_FSDK_FOC_150 = 8,
AFD_FSDK_FOC_210 = 9,
AFD_FSDK_FOC_240 = 10,
AFD_FSDK_FOC_300 = 11,
AFD_FSDK_FOC_330 = 12
AFD_FSDK_ORIENTPRIORITY定义脸部角度的检测范围
public enum AFD_FSDK_OrientPriority
AFD_FSDK_OPF_0_ONLY=1,
AFD_FSDK_OPF_90_ONLY=2,
AFD_FSDK_OPF_270_ONLY=3,
AFD_FSDK_OPF_180_ONLY=4,
AFD_FSDK_OPF_0_HIGHER_EXT=5
ASVLOFFSCREEN这个结构体是用来进行人脸识别的关键结构,我当初就是在定义函数时才发现这个没有。又跑回来重新定义的。这个在SDK文档中没有,但是我们在示例代码中能够看到。我看来看看一下LPASVLOFFSCREEN的定义。在我们SDK的inc文件夹中,我们找到了一个名为asvloffscreen.h的文件。我们把文件打开,可以发现里面的主要定义typedef struct __tag_ASVL_OFFSCREEN
MUInt32 u32PixelArrayF
MUInt8* ppu8Plane[4];
pi32Pitch[4];
}ASVLOFFSCREEN, *LPASVLOFFSCREEN;
u32PixelArrayFormat:像素数组的格式ppu8Plane[4]为一个指针数组pi32Pitch[4]为一整形数组如何定义数组数组的定义没有我们想象中的那么简单。在C++中定义数组的时候,是指定了数组的长度的,而C#中定义数组时,是不指定长度的。这只是一个问题,另一个问题是因为C#的数据和C++的数据布局方式有很大的不同,在P/Invoke和COM Interop当中必须要在C#和C++之间传递数据,有的时候,CLR或者说.NET能够自动在两种编程语言之间转换数据,有的时候又不行,这时候就需要程序员来帮忙告诉.NET怎样转换数据了。这个转换的方式是指定MarshalAs属性。Marshal属性相当难用,如何转换是一个复杂的事情,这个时个我们需要请出微软的神器。P/Invoke Interop Assistant,你可以去下面的链接下载这个神器 通过P/Invoke Interop Assistant的帮忙,我们可以知道应该这样子定义这个结构体。使用这个工具时,需要注意的是要把我们结构体中的类型转化为标准的C类型,我们可以在inc的amcomdef.h头文件中找到它们的转换定义。我们来看一下最终的这个结构体的定义public struct ASVLOFFSCREEN
public int u32PixelArrayF
public int i32W
public int i32H
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = System.Runtime.InteropServices.UnmanagedType.SysUInt)]
public System.IntPtr[] ppu8P
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = System.Runtime.InteropServices.UnmanagedType.I4)]
public int[] pi32P
现在你可以用这个工具来定义我们接来所需要用到的所有数据结构,也可以用来定义API函数。定义API函数查看SDK文档,可以看到FD共提供了3个方法。我们定义一个类来包含这些方法新建AFD文件夹,定义AFDFunction类,里面包含SDK中提供的所有方法。AFD_FSDK_INITIALFACEENGINE我们先来看一下第一个方法,初始化SDK引擎,在SDK文档中可以看到它的原型定义如下:原型MRESULT AFD_FSDK_InitialFaceEngine(
MPChar AppId,
MPChar SDKKey,
MByte *pMem,
MInt32 lMemSize,
MHandle *pEngine,
AFD_FSDK_OrientPriority iOrientPriority,
MInt32 nScale,
MInt32 nMaxFaceNum
我们来看一下它的参数列表AppId
用户申请SDK时获取的App IdSDKKey
用户申请SDK时获取的SDK KeypMem
分配给引擎使用的内存地址lMemSize
分配给引擎使用的内存大小pEngine
引擎handleiOrientPriority
期望的脸部检测角度范围nScale
用于数值表示的最小人脸尺寸 有效值范围[2,50] 推荐值 16。该尺寸是人脸相对于所在图片的长边的占比。例如,如果用户想检测到的最小人脸尺寸是图片长度的1/8,那么这个nScale就应该设置为8nMaxFaceNum
用户期望引擎最多能检测出的人脸数 有效值范围[1,50]如果成功返回MOK,失败返回MRCode,MOK是一个int型的值为0,MRCOde是一个定义。可以在inc文件 夹中的merror.h中找到。通过刚才提供的神器,我们可以定义这个函数如下:[DllImport("libarcsoft_fsdk_face_detection.dll", EntryPoint = "AFD_FSDK_InitialFaceEngine", CallingConvention = CallingConvention.Cdecl)]
public static extern int AFD_FSDK_InitialFaceEngine(string appId, string sdkKey, IntPtr pMem, int lMemSize, ref IntPtr pEngine, int iOrientPriority, int nScale, int nMaxFaceNum);
CallingConvertion这个属性用于定义C++函数调用的方式。Cdecl
调用方清理堆栈。这使您能够调用具有 varargs 的函数(如 Printf),使之可用于接受可变数目的参数的方法。FastCall
不支持此调用约定。StdCall 被调用方清理堆栈。这是使用平台 invoke 调用非托管函数的默认约定。ThisCall
第一个参数是 this 指针,它存储在寄存器 ECX 中。其他参数被推送到堆栈上。此调用约定用于对从非托管 DLL 导出的类调用方法。Winapi
此成员实际上不是调用约定,而是使用了默认平台调用约定。例如,在 Windows 上默认为 StdCall,在 Windows
上默认为 Cdecl。默认情况下,C和C++使用的Cdecl调用,因此我们在调用DLL时指定这个值就可以。AFD_FSDK_STILLIMAGEFACEDETECTION这个方法是我们的核心方法,它的功能如我们所料,就是通过读取输入的图像,检测是否存在人脸内容并输出人脸的结果信息。我们来看一下基础定义。MRESULT AFD_FSDK_StillImageFaceDetection(
MHandle hEngine,
LPASVLOFFSCREEN pImgData,
LPAFD_FSDK_FACERES pFaceRes
引擎handlepImgData
待检测的图像信息pFaceRes
人脸检测结果和初始化类似,第一个参数是hEngine引用,第二个参数pImgData是要检测的图形信息,第三个参数pFaceRes是一个输出参数,获取人脸的检测结果。需要注意的是里面的参数类型,第一个MHandle对应的是引擎的引用,这个没有问题,第二个是LPASVLOFFSCREEN 它是指向ASVLOFFSCREEN的一个结构体指针,同样LPAFD_FSDK_FACERES也是一个指针,我们知道指针对应的都是IntPtr,定义如下:[DllImport("libarcsoft_fsdk_face_detection.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int AFD_FSDK_StillImageFaceDetection(IntPtr pEngine, IntPtr pImgData, ref IntPtr pFaceRes);
AFD_FSDK_GETVERSION初始化之后的方法是GetVersion,功能就是获取SDK的版本信息。原型const AFD_FSDK_Version * AFD_FSDK_GetVersion(
MHandle hEngine
这个方法比较简单,参数就是Engine的引用,其返回值为Version结构体,我们在最初的时候已经定义完成。[DllImport("libarcsoft_fsdk_face_detection.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int AFD_FSDK_StillImageFaceDetection(IntPtr pEngine, IntPtr pImgData, ref IntPtr pFaceRes);
[DllImport("libarcsoft_fsdk_face_detection.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int AFD_FSDK_UninitialFaceEngine(IntPtr pEngine);
至此,我们的基础数据结构已创建完毕.实现图片读取和人脸识别功能我们来实现我们的图片读取和人脸识别功能,这个章节中,会包含大量的细节及互操作的内容。基础知识介绍其实关于P/Invoke的操作我们前面的代码已经讲解了很多。也基本把我们用到的结构体和函数定义出来,我们知道指针映射为IntPtr,引用类变量映射为IntPtr,char *可以映摄为字符串结构体,和数组如果从IntPtr中取数据呢,我们需要使用的一个类叫Marshal我们来看一下MSDN上的介绍Marshal类提供了一个方法集合,这些方法用于分配非托管内存、复制非托管内存块、将托管类型转换为非托管类型,此外还提供了在与非托管代码交互时使用的其他杂项方法,我们将会在下面开发进程中频繁使用这个类的多个方法。例如:在定义一个指针类型变量时IntPtr,我们需要使用Marshal.AllocHGlobal为其分配内存,得到IntPtr变量,在分配内存时,我们需要使用Marshal.SizeOf计算需要分配的内存的大小。然后调用Marshal.StructureToPtr为变量赋值让我们带着这些概念开始我们下面的内容。初始化引擎根据我们的SDK说明文档,在使用引擎之前需要先初始化。出于简单我就把初始化代码的部分放在Form1的构造函数内。而把引擎作为类的实例变量定义。我们在构造函数中添加初始化的代码。定义人脸识别引擎IntPtr detectEngine = IntPtr.Z
定义人脸识别引擎参数我们可以根据sampleCode定义我们人脸识别所需要的参数首先,定义Engine运行需要的内存,宽容度,人脸的数目以及有效的人脸角度。int detectSize = 40 * 1024 * 1024;
int nScale = 50;
int nMaxFaceNum = 10;
string appId = "你申请到的APPID";
string sdkFDKey = "你申请到的FDKEY";
初始始化引擎内存缓冲区在示例代码中,我们可以得到引擎在初始化时,需要指定缓冲区。在C#中,可以使用pMem = Marshal.AllocHGlobal(detectSize);
初始始化引擎针对人脸角度的检测范围,直接传递为AFD_FSDK_OrientPriority.AFD_FSDK_OPF_0_HIGHER_EXT,变量定义完成后,我们就可以调用我们的初始化方法了。返回值为int类型,通过返回的类型,可以得知是否能够调用成功。int retCode = AFDFunction.AFD_FSDK_InitialFaceEngine(appId, sdkFDKey, pMem, detectSize, out detectEngine, (int)AFD_FSDK_OrientPriority.AFD_FSDK_OPF_0_HIGHER_EXT, nScale, nMaxFaceNum);
if (retCode != 0)
MessageBox.Show("引擎初始化失败:错误码为:" + retCode);
this.Close();
实现业务逻辑接下来,我们找到我们的btnLoadImage方法,在这里填写我们的业务处理逻辑。1.读取一个jpg的文件,并加载的pictureBox1中显示出来,2.然后调用我们的引擎的AFD_FSDK_StillImageFaceDetection方法,检查出人脸的位置。3最后我们利用GDI+,把检测到的人脸部分提取出位置显示到PictureBox2中,4.把pictureBox1中的图片,添加上识别的红框,完成人脸检测的效果。打开图片加载图片比较简单,我们调用OpenFileDialog方法,打开一个图片文件,并显示到pictureBox1中OpenFileDialog openFile = new OpenFileDialog();
openFile.Filter = "图片文件|*.*.*.*.png|所有文件|*.*;";
openFile.Multiselect =
openFile.FileName = "";
if (openFile.ShowDialog() == DialogResult.OK)
Image image = Image.FromFile(openFile.FileName);
this.pictureBox1.Image = new Bitmap(image);
//TODO:完成下面的方法
checkAndMarkFace(this.pictureBox1.Image);
检测并标记人脸终于到正题了,很兴奋,对吧。不过还是没有思路,因为我们不知道如何来调用那个引擎。这个时候我们必须参考samplecode,通过sampleCode我们可以得知,首先我们需要读取图片的内容到BMP格式,而且这个BMP格式必须为ASVL_PAF_RGB24_B8G8R8,标准的Image中的Bitmap就是这个格式,读取bitmap中的所有图像信息存入ASVLOFFSCREEN的offInput中,这时候SampleCode中的代码是从文件中读取的,我们要直接从Bitmap中读取,这里面还是有一些不一样的。我们首先来看一下这个读取的代码private byte[] readBmp(Bitmap image, ref int width, ref int height, ref int pitch)
{//将Bitmap锁定到系统内存中,获得BitmapData
BitmapData data = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
//位图中第一个像素数据的地址。它也可以看成是位图中的第一个扫描行
IntPtr ptr = data.Scan0;
//定义数组长度
int soureBitArrayLength = data.Height * Math.Abs(data.Stride);
byte[] sourceBitArray = new byte[soureBitArrayLength];
//将bitmap中的内容拷贝到ptr_bgr数组中
Marshal.Copy(ptr, sourceBitArray, 0, soureBitArrayLength);
width = data.W
height = data.H
pitch = Math.Abs(data.Stride);
int line = width * 3;
int bgr_len = line *
byte[] destBitArray = new byte[bgr_len];
for (int i = 0; i & ++i)
Array.Copy(sourceBitArray, i * pitch, destBitArray, i * line, line);
image.UnlockBits(data);
return destBitA
有关这部分的内容,可以参考微软关于BitmapData的注解。识别人脸回到我们的这个方法,我们继续人脸识别的过程首先,我们把获取到的图像信息存起来byte[] imageData = readBmp(bitmap, ref width, ref height, ref pitch);
通过前面的过程,我们知道,我们的代码中的传入图像的参数类型是ASVLOFFSCREEN指针。通过查看ASVLOFFSCREEN类型。我们可以发现,u32PixelArrayFormat为需要图像的格式。这个是因为我们准备使用BMP位图,因此我们直接使用ASVL_PAF_RGB24_B8G8R8格式通过查询可知定义的值为513.i32Width和i32Height则为识别图像的大小。ppu8Plane为一个批向byte数组的指针数组,这里面会保存我们刚刚转换后的图片数据。而pi32Pitch则是为每一个图像指定了pitch大小,在结构中,一次人脸识别工作,可以传递四幅图片。我们先来把byte[]数组转化为C++识别的数组类型。IntPtr imageDataPtr = Marshal.AllocHGlobal(imageData.Length);
Marshal.Copy(imageData, 0, imageDataPtr, imageData.Length);
接下来是根据刚才的分析,我们设置的ASVLOFFSCREEN的结构体类型ASVLOFFSCREEN offInput = new ASVLOFFSCREEN();
offInput.u32PixelArrayFormat = 513;
offInput.ppu8Plane = new IntPtr[4];
offInput.ppu8Plane[0] = imageDataP
offInput.i32Width =
offInput.i32Height =
offInput.pi32Pitch = new int[4];
offInput.pi32Pitch[0] =
由于方法中需要是的一个结构体的指针,因此,我们还需要调用Marshal. AllocHGlobal方法创建指针,并使用Marshal.StructureToPtr进行初始化。IntPtr offInputPtr = Marshal.AllocHGlobal(Marshal.SizeOf(offInput));
Marshal.StructureToPtr(offInput, offInputPtr, false);
由于接口还需要一个结构体保存返回的人脸数据,我们来定义它AFD_FSDK_FACERES faceRes = new AFD_FSDK_FACERES();
同人脸数据一样,我们需要把这个结构体转换为指针类型。IntPtr faceResPtr = Marshal.AllocHGlobal(Marshal.SizeOf(faceRes));
这个是返回值,因此我们不需要对内容进行初始化。我们直接调用引擎int detectResult = FaceDllImport.AFD_FSDK_StillImageFaceDetection(detectEngine, offInputPtr, ref faceResPtr);
如果成功返回detectResult会返回0,也就是0这个时候,返回为0并不意味着找到了人脸,具体的人脸信息还需要在我们的AFD_FSDK_FACERES结构休中查找。使用Marshal.PtrToStructure批获得的指针类型转化为结构体类型。faceRes = (AFD_FSDK_FACERES) Marshal.PtrToStructure(faceResPtr, typeof(AFD_FSDK_FACERES));
根据前端的结构体定义部分的数据,我们可以发现其中AFD_FSDK_FACERES.nFace属性为识别到的人脸的数目。faceRes.rcFace则为识别到的人脸的数据。nFace可以直接转化为int。标出识别到的人脸信息AFD_FSDK_FACERES中的rcFace是一个结构体指针,因此我们使用Marshal.PtrToStructure将其转化为结构体。 MRECT rect = (MRECT)Marshal.PtrToStructure(faceRes.rcFace , typeof(MRECT));
通过获得这个rect信息,就可以得到我们需要的人脸的位置数据了,包括人脸矩形的在上角和右下角的坐标。然后我们就可以利用这些数据来重新创建一个位图Image image = CutFace(bitmap, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
将位图显示到图片控件上this.pictureBox2.Image =
然后我们想像Demo中的一样,标出人脸的位置。我们就可以使用这样的方法。this.pictureBox1.Image=
DrawRectangleInPicture(pictureBox1.Image, new Point(rect.left, rect.top), new Point(rect.right, rect.bottom), Color.Red, 2, DashStyle.Dash);
来看一下这里面用到的两上C#方法比较简单,纯属C#代码,比较简单public static Bitmap CutFace(Bitmap srcImage, int StartX, int StartY, int iWidth, int iHeight)
if (srcImage == null)
int w = srcImage.W
int h = srcImage.H
if (StartX &= w || StartY &= h)
if (StartX + iWidth & w)
iWidth = w - StartX;
if (StartY + iHeight & h)
iHeight = h - StartY;
Bitmap bmpOut = new Bitmap(iWidth, iHeight, PixelFormat.Format24bppRgb);
Graphics g = Graphics.FromImage(bmpOut);
g.DrawImage(srcImage, new Rectangle(0, 0, iWidth, iHeight), new Rectangle(StartX, StartY, iWidth, iHeight), GraphicsUnit.Pixel);
g.Dispose();
return bmpO
Image DrawRectangleInPicture(Image bmp, Point p0, Point p1, Color RectColor, int LineWidth, DashStyle ds)
if (bmp == null)
Graphics g = Graphics.FromImage(bmp);
Brush brush = new SolidBrush(RectColor);
Pen pen = new Pen(brush, LineWidth);
pen.DashStyle =
g.DrawRectangle(pen, new Rectangle(p0.X, p0.Y, Math.Abs(p0.X - p1.X), Math.Abs(p0.Y - p1.Y)));
g.Dispose();
点击运行现在你可以点击运行你的项目了,如果没有任何问题,你的将会看到下面的画面。如果出现问题,你需要根据返回的错误码进行查找。引擎初始化失败一般是APPID和APPKEY不对,你需要确保你到下载的地方申请了正确的APPID和KEY,并且注意平台是Windows平台的。初始化失败可以通过返回值进行查看,他们官网上也会有一个错误代码表。对照查表一般会解决问题。找不到DLL首先请保证你把DLL拷贝到对应的目录下面,其次要确定设置输出选项为拷贝到输出目录。内存不能读或者写这个是C++的尿性,也是C#程序员不多见的报错,主要检查相关参数是否传入正确。还要注意,如果人脸检测返回的值不为0,获取到的人脸数目会是一个比较大的随机数。这个时候如果用循环读取,就会出现地址越界的情况。最后来一张华仔的图镇楼今天我们只是讲解了一下人脸识别的最简单的Demo,我们下一节从获取两张人脸的相似度来入手讲解如何识别不同的人的,欢迎继续关注。如果你已经了解了本博客的内容,你可以打开FR的文档,自己来进行模拟实现。7314 条评论分享收藏}

我要回帖

更多关于 虹软 人脸识别 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信