# go接口式调用ArcSoft4.0 **Repository Path**: BlacksMoon/ArcSoft4.0-Go ## Basic Information - **Project Name**: go接口式调用ArcSoft4.0 - **Description**: 使用go-iris框架,实现go调用虹软SDK 4.0 增值版 - **Primary Language**: Go - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 3 - **Forks**: 2 - **Created**: 2021-01-07 - **Last Updated**: 2024-09-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ArcSoft4.0_Go ### 一、项目说明 [虹软官网传送门](https://www.arcsoft.com.cn/) ,有不同平台和不同版本的sdk,有需要的根据业务下载。 此次项目支持windows和linux系统。 1. 项目由go-iris框架创建(最快的go-api框架,没有之一)。 2. 采用虹软最新增值4.0SDK。 3. 调用虹软sdk的方法参考于 WindOSX 大佬写的低版本调用方法,在这里感谢 [WindOSX](https://www.jianshu.com/p/0cb08216753c) 的技术支持。 4. toml管理配置文件 5. 采用cgo调用C++库(gcc版本大于4.8.2),win10计算机需要装mingw64 windows版本,具体自行百度和科学上网下载。 其它的请自行百度,此处就不细细阐述了。 6. 支持jwt bear token 认证方式,当然你想用auth2.0,也有对应的库进行解析。 7. 此次主要针对window版本的dll,linux调用方法一样,将路径换位自己的路径即可,文件名为.so 8. 使用go mod 管理项目包【我使用的是jetbrain golang】,初始化 go mod init,下载包 go mod tidy + ![包管理设置](https://images.gitee.com/uploads/images/2021/0123/040214_22804a9d_1983982.png "3.png") 9. go的版本,windows 最好是 >= 1.14 10. 自动化文档支持 yaag (无需注释,只要修改yaag源码的html模板) 和 swager 需要在接口上写注释及参数说明,即可) ### 二、虹软增值版4.0新增接口及改动 ``` bash 新增接口: 1、激活接口 2、离线激活接口 3、获取设备信息接口 4、图片质量检测 5、更新检测人脸信息接口 6、人脸遮挡检测 7、人脸额头检测 改动的接口:(主要是新增参数) 1、人脸检测 2、提取特征值 3、特征值比较 ``` ### 三、开始使用 1. 修改配置文件 + ![配置文件图解1](https://images.gitee.com/uploads/images/2021/0123/035436_7329e3e0_1983982.png "1.png") + ![配置文件图解2](https://images.gitee.com/uploads/images/2021/0123/035502_bddc5596_1983982.png "2.png") 2. 拷贝dll 1. 第一种,gcc低版本,需要将dll文件拷贝至system32下; 2. 第二种,gcc高版本,需要将dll文件拷贝至mingw64的lib下,具体看你mingw64配置及报错路径; 3. 第三种,gcc高版本,需要将dll文件拷贝当前项目的根目录; 4. 第四种,gcc高版本,指定dll相对路径,使用cgo 引用动态库: ``` bash /* #cgo CFLAGS: -I./include #cgo LDFLAGS: -L${SRCDIR}/lib -larcsoft_face_engine #include #include "./include/merror.h" #include "./include/asvloffscreen.h" #include "./include/arcsoft_face_sdk.h" */ import "C" ``` ``` bash 此处常见问题: (1) import "C" 之前不能有换行 (2) ${SRCDIR} 在cgo里面表示当前目录的绝对路径 (3) 出现undefined reference to XXXX,此时有两种解决问题的思路: 第一种是头文件中的方法没有被 #ifdef __cplusplus extern "C" { #endif 你的方法() #ifdef __cplusplus } #endif #endif 包裹。 第二种解决办法:升级gcc版本,因为版本过低导致编译错误。 ``` 3. 运行 常见问题 ``` bash (1) 虹软很多数据类型没有暴露出来,使用过的时候,当枚举类的数据结构作为参数传入函数时,需要加上枚举的标识 enum。 (2) 使用C头文件中的枚举,可以直接用 C.XXXXX [XXX标识枚举结构体内的枚举数据] /************************************************************************ * 初始化引擎 ************************************************************************/ MRESULT ASFInitEngine( enum ASF_DetectMode detectMode, // [in] AF_DETECT_MODE_VIDEO 视频模式:适用于摄像头预览,视频文件识别 // AF_DETECT_MODE_IMAGE 图片模式:适用于静态图片的识别 enum ASF_OrientPriority detectFaceOrientPriority, // [in] 检测脸部的角度优先值,参考 ArcFaceCompare_OrientPriority MInt32 detectFaceMaxNum, // [in] 最大需要检测的人脸个数 MInt32 combinedMask, // [in] 用户选择需要检测的功能组合,可单个或多个 MHandle *hEngine // [out] 初始化返回的引擎handle ); 其它修改类似。 (3) cgo中数据类型转化,如: 指针 -> (*C.MPChar)(unsafe.Pointer(&deviceInfo) 、(*C.MUInt8)(unsafe.Pointer(&imgData[0])) 变量,强制转化 -> C.MInt32(abc),当然也可以使用断言,abc.(C.MInt32) 数组,主要采用切片的方式进行转化 -> (*[10]int32)(unsafe.Pointer(asfFaceInfo.faceID))[:faceNum:faceNum] .... 其它类似 (4) 如果代码出现一串内存地址,请及时升级gcc版本。 (5) 人脸特征值需要释放内存。 (6)【特别说明】 ![修改imgo包的源码1](https://images.gitee.com/uploads/images/2021/0123/081346_707d53e7_1983982.png "4.png") ![修改imgo包的源码2](https://images.gitee.com/uploads/images/2021/0123/081359_f882f221_1983982.png "5.png") ``` ### 四、代码结构 ``` bash ├─.gitee ├─.idea ├─apidoc ├─attachment │ ├─downloads │ └─pics │ ├─bind │ ├─check │ ├─info │ └─slice ├─auth ├─common ├─database ├─docs ├─face // 人脸sdk主要位置 │ └─__4_0 │ ├─include │ └─lib ├─logutils ├─middleware ├─routes ├─srv └─utils ``` ### 五、代码调用实例及说明 ``` bash // 获取人脸信息 func GetFaceInfos(engine *FaceEngine, transId string, width, height int, imageData []uint8, info MultiFaceInfo, img []byte, isReg, isMask int32) ( ib bool, multi []*SingleFacePropertyFourth) { if err := engine.ProcessPro(width-width%4, height, ColorFormatBGR24, imageData, info, EnableAge|EnableGender|EnableFace3DAngle|EnableLiveness|EnableMaskDetect|EnableFaceLandMark, ); err != nil { logutils.Logger.Error("图片活体检测失败.", zap.String("transId", transId), zap.String("error", err.Error())) return } logutils.Logger.Info("图片活体检测成功.", zap.String("transId", transId)) var faceProperty []*SingleFacePropertyFourth // 获取年龄 ageInfo, err := engine.GetAgePro() if err != nil { logutils.Logger.Error("获取年龄失败.", zap.String("transId", transId), zap.String("error", err.Error())) return false, nil } logutils.Logger.Info("获取年龄成功.", zap.String("transId", transId)) // 获取性别 genderInfo, err := engine.GetGenderPro() if err != nil { logutils.Logger.Error("获取性别失败.", zap.String("transId", transId), zap.String("error", err.Error())) return false, nil } logutils.Logger.Info("获取性别成功.", zap.String("transId", transId)) // 获取3DAngle angleInfo, err := engine.GetFace3DAnglePro() if err != nil { logutils.Logger.Error("获取3DAngle失败.", zap.String("transId", transId), zap.String("error", err.Error())) return false, nil } logutils.Logger.Info("获取3DAngle成功.", zap.String("transId", transId)) // 获取口罩遮挡 maskInfo, err := engine.GetMaskPro() if err != nil { logutils.Logger.Error("获取人脸遮挡失败.", zap.String("transId", transId), zap.String("error", err.Error())) return false, nil } logutils.Logger.Info("获取人脸遮挡成功.", zap.String("transId", transId)) // 额头点位 landMark, err := engine.GetFaceLandMarkInfo() if err != nil { logutils.Logger.Error("获取人脸额头失败.", zap.String("transId", transId), zap.String("error", err.Error())) return false, nil } logutils.Logger.Info("获取人脸额头成功.", zap.String("transId", transId)) //获取活体值 liveInfo, err := engine.GetLivenessScorePro() if err != nil { logutils.Logger.Error("获取活体值失败.", zap.String("transId", transId), zap.String("error", err.Error())) return false, nil } logutils.Logger.Info("获取活体值成功.", zap.String("transId", transId)) maxInt := GetMaxFace(info.FaceRect) for k, v := range info.FaceRect { property := new(SingleFacePropertyFourth) property.FaceRect = v property.FaceOrient = info.FaceOrient[k] property.Age = ageInfo.AgeArray[k] property.Gender = genderInfo.GenderArray[k] property.GenderType = ExplainAge(genderInfo.GenderArray[k]) property.Face3DAngle = angleInfo property.MaskInfo = maskInfo property.LandMarkInfo = landMark property.Live = liveInfo.IsLive[k] // 是否带眼镜 property.WearGlasses = info.WearGlasses[k] property.LeftEyeClosed = info.LeftEyeClosed[k] property.RightEyeClosed = info.RightEyeClosed[k] // 提取人脸图片并以base64返回 resImage := CutImage(img, v) // 转存提取的人脸 SaveImage("./attachment/pics/slice/"+transId+"/", "face_"+transId+"_"+strconv.Itoa(k)+".jpg", resImage, transId) property.FaceImage = base64.StdEncoding.EncodeToString(resImage) // 提取活体值 //pw,ph,imageD := ImageConvert(resImage,transId) //liveInfo := GetLive(transId,pw,ph,imageD) //if liveInfo != nil{ // property.Live = liveInfo.IsLive // property.LiveType = ExplainLive(liveInfo.IsLive) //} // 提取人脸特征 sing := SingleFaceInfo{v, info.FaceOrient[k], info.FaceDataInfoList[k]} _, feature := FeatureExtractUtil(engine, transId, width, height, imageData, sing, uint32(isReg), uint32(isMask)) property.Feature = feature feature.Release() if maxInt == k { property.Max = 1 } faceProperty = append(faceProperty, property) } return true, faceProperty } ``` ### 六、关于一些配置说明 ``` bash 1、本项目采用go-iris框架搭建完成。 2、新增接口主要新在routes/route.go中添加接口定义及方法,支持分级路由,多级路由,支持中间件验证,然后实现对应的方法即可。 3、iris 取出参数非常方便,支持 query、params、json、xml等格式,非常方便取出参数。 4、中间件使用jwt bearer token的方式验证,支持api调用次数等配置。 5、配置文件中有几个参数说明下: # 是否是测试模式 test = true # 同一个请求是否可以请求多次,项目中有配置api的使用总次数及统计使用次数(当然用的方法比较原始) repeat = true # 授权 如果 authorization = 1 则token请求的queryparams里, authorization= 0 则放Header里 authorization = 1 ``` ### 七、打包 ``` bash 在当前目录下运行 linux.bat即可 ``` ### 八、运行效果 ![绑定人脸](https://images.gitee.com/uploads/images/2021/0124/223529_126feaf5_1983982.png "7.png") ![获取人脸信息](https://images.gitee.com/uploads/images/2021/0124/223614_0813dfe3_1983982.png "8.png") ### 九、开源说明 + 开源不易,请使用代码时,注明引用,谢谢~ + 如果你觉得我的代码帮到了你,请捐赠以表示支持,谢谢~