├── .gitattributes ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── engine.go ├── examples └── example1.go ├── go.mod ├── include ├── amcomdef.h ├── arcsoft_face_sdk.h ├── asvloffscreen.h └── merror.h ├── mask.jpg └── util └── image_util.go /.gitattributes: -------------------------------------------------------------------------------- 1 | *.h linguist-language=Go 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | .idea/ 23 | .vscode/ 24 | 25 | *.exe 26 | *.test 27 | *.prof 28 | 29 | *.dat 30 | *.dll 31 | 32 | face-engine 33 | go.sum -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.15.x 5 | 6 | before_install: 7 | - wget -O lib.zip https://github.com/windosx/face-engine/releases/download/v4.0.4/libarcsoft_linux_x64.zip 8 | - unzip lib.zip -d ./arcsoftlib/ 9 | - sudo cp ./arcsoftlib/libarcsoft_face.so /usr/lib 10 | - sudo cp ./arcsoftlib/libarcsoft_face_engine.so /usr/lib 11 | 12 | script: 13 | - go build -o test github.com/windosx/face-engine/v4/examples 14 | - chmod +x test 15 | - ./test 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2021 WindOSX 2 | 3 |   Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 |    5 |   The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 虹软人脸检测SDK Go语言版 2 | ![LICENSE](https://img.shields.io/github/license/windosx/face-engine) 3 | ![Supported platform](https://img.shields.io/badge/platform-win%20%7C%20linux-lightgrey) 4 | [![Build Status](https://travis-ci.org/windosx/face-engine.svg?branch=master)](https://travis-ci.org/windosx/face-engine) 5 | [![GoDoc](http://godoc.org/github.com/windosx/face-engine?status.svg)](http://godoc.org/github.com/windosx/face-engine) 6 | 7 | # 一、项目简介 8 | 9 | 由于公司是虹软的重度用户,出于工作需要和个人兴趣,寻思着用golang封装一下C++的SDK,利用golang的跨平台特性达到跨平台的效果(当然前提是SDK支持的平台) 10 | 11 | 目前支持的SDK版本有:[v2.x](https://github.com/windosx/face-engine/tree/v2.2.0) [v3.x](https://github.com/windosx/face-engine/tree/v3.0.8) [v4.0.0](https://github.com/windosx/face-engine) 12 | 13 | # 二、编译环境与运行环境的准备 14 | 15 | ## 1. 安装go版本SDK 16 | 推荐使用go module的方式进行安装(需要哪个版本修改版本号即可): 17 | 18 | ```bash 19 | go get -u -d github.com/windosx/face-engine/v4 20 | ``` 21 | ## 2. 安装gcc环境 22 | Linux下可以通过对应的包管理器进行安装,Windows下根据32/64位系统进行选择安装MinGW或者MinGW-w64 23 | 24 | ## 3. 运行环境 25 | - Linux:将`libarcsoft_face.so`、`libarcsoft_face_engine.so`放入`/usr/lib64`目录下 26 | - Windows:将`libarcsoft_face.dll`、`libarcsoft_face_engine.dll`放入MinGW安装目录下的lib目录中,同时需要将这两个文件放入`%WINDIR%`或者`%WINDIR/System32%`目录下 27 | 28 | # 三、代码结构说明 29 | ```bash 30 | ├─examples 31 | │ └─example1.go 32 | ├─include 33 | │ ├─amcomdef.h 34 | │ └─arcsoft_face_sdk.h 35 | │ └─asvloffscreen.h 36 | │ └─merror.h 37 | ├─util 38 | │ └─image_util.go 39 | ├─go.mod 40 | ├─engine.go 41 | ├─mask.jpg 42 | ├─test.jpg 43 | examples目录中是示例代码 44 | include是SDK的头文件 45 | util下的image_util.go是使用golang原生API处理图片的工具 46 | engine.go是封装的SDK 47 | 两张JPEG格式的图片是给示例代码用的 48 | ``` 49 | # 四、代码调用示例 50 | ```go 51 | package main 52 | 53 | import ( 54 | "fmt" 55 | 56 | . "github.com/windosx/face-engine/v4" 57 | "github.com/windosx/face-engine/v4/util" 58 | ) 59 | 60 | // 获取处理好的图片信息 61 | var imageInfo = util.GetResizedImageInfo("./mask.jpg") 62 | 63 | func main() { 64 | // 激活SDK 65 | if err := OnlineActivation("YourAppID", "YourSDKKey", "YourActiveCode"); err != nil { 66 | fmt.Printf("%#v\n", err) 67 | return 68 | } 69 | // 初始化引擎 70 | engine, err := NewFaceEngine(DetectModeImage, 71 | OrientPriority0, 72 | 10, // 4.0最大支持10个人脸 73 | EnableFaceDetect|EnableFaceRecognition|EnableFace3DAngle|EnableLiveness|EnableIRLiveness|EnableAge|EnableGender|EnableMaskDetect|EnableFaceLandMark) 74 | if err != nil { 75 | fmt.Printf("%#v\n", err) 76 | return 77 | } 78 | deviceInfo, err := GetActiveDeviceInfo() 79 | if err != nil { 80 | fmt.Printf("%#v\n", err) 81 | } 82 | fmt.Printf("设备信息:%s\n", deviceInfo) 83 | // 检测人脸 84 | info, err := engine.DetectFaces(imageInfo.Width, imageInfo.Height, ColorFormatBGR24, imageInfo.DataUInt8) 85 | if err != nil { 86 | fmt.Printf("%#v\n", err) 87 | return 88 | } 89 | // 处理人脸数据 90 | if err = engine.Process(imageInfo.Width, imageInfo.Height, ColorFormatBGR24, imageInfo.DataUInt8, info, EnableAge|EnableGender|EnableFace3DAngle|EnableLiveness|EnableMaskDetect|EnableFaceLandMark); err != nil { 91 | fmt.Printf("%#v\n", err) 92 | return 93 | } 94 | // 获取年龄 95 | ageInfo, err := engine.GetAge() 96 | if err != nil { 97 | fmt.Printf("%#v\n", err) 98 | return 99 | } 100 | fmt.Printf("ageInfo: %v\n", ageInfo) 101 | // 获取口罩信息 102 | maskInfo, err := engine.GetMask() 103 | if err != nil { 104 | fmt.Printf("%#v\n", err) 105 | return 106 | } 107 | fmt.Printf("口罩信息:%#v\n", maskInfo) 108 | // 获取额头点位 109 | landMark, err := engine.GetFaceLandMarkInfo() 110 | if err != nil { 111 | fmt.Printf("%#v\n", err) 112 | return 113 | } 114 | fmt.Printf("额头点位:%#v\n", landMark) 115 | // 销毁引擎 116 | if err = engine.Destroy(); err != nil { 117 | fmt.Printf("%#v\n", err) 118 | return 119 | } 120 | } 121 | ``` 122 | # 五、注意事项 123 | 1. 通过`FaceFeatureExtract`或`FaceFeatureExtractEx`方法提取到人脸特征信息,使用完毕后应调用其`Release()`方法释放内存,避免导致内存溢出,这是由于cgo的一些局限性导致的。 124 | 125 | # 六、更多示例代码 126 | - [ArcFace+gocv处理视频流](https://github.com/windosx/arcface-gocv-examples) 127 | 128 | ***(如果您想分享自己的示例,欢迎PR)*** 129 | 130 | # 七、开源说明 131 | 本项目使用MIT协议,如果对您有帮助,请点亮star支持一下 :) 132 | -------------------------------------------------------------------------------- /engine.go: -------------------------------------------------------------------------------- 1 | package faceengine 2 | 3 | /* 4 | #cgo CFLAGS : -I./include 5 | #cgo LDFLAGS : -larcsoft_face_engine 6 | #include 7 | #include "merror.h" 8 | #include "asvloffscreen.h" 9 | #include "arcsoft_face_sdk.h" 10 | */ 11 | import "C" 12 | 13 | import ( 14 | "unsafe" 15 | ) 16 | 17 | // FaceEngine 引擎结构体 18 | type FaceEngine struct { 19 | handle C.MHandle 20 | } 21 | 22 | // MultiFaceInfo 多人脸信息结构体 23 | type MultiFaceInfo struct { 24 | FaceRect []Rect // 人脸框信息 25 | FaceOrient []int32 // 输入图像的角度 26 | FaceNum int32 // 检测到的人脸个数 27 | FaceID []int32 // face ID,IMAGE模式下不返回FaceID 28 | WearGlasses float32 // 带眼镜置信度[0-1],推荐阈值0.5 29 | LeftEyeClosed int32 // 左眼状态 0 未闭眼 1 闭眼 30 | RightEyeClosed int32 // 右眼状态 0 未闭眼 1 闭眼 31 | FaceDataInfoList []C.ASF_FaceDataInfo // 多张人脸信息 32 | native *C.ASF_MultiFaceInfo 33 | } 34 | 35 | // Rect 人脸坐标结构体 36 | type Rect struct { 37 | Left int32 38 | Top int32 39 | Right int32 40 | Bottom int32 41 | } 42 | 43 | // LivenessThreshold 活体置信度结构体 44 | type LivenessThreshold struct { 45 | ThresholdModelBGR float32 46 | ThresholdModelIR float32 47 | } 48 | 49 | // ActiveFileInfo 激活文件信息结构体 50 | type ActiveFileInfo struct { 51 | StartTime string //开始时间 52 | EndTime string //截止时间 53 | ActiveKey string //激活码 54 | Platform string //平台 55 | SdkType string //sdk类型 56 | AppID string //APPID 57 | SdkKey string //SDKKEY 58 | SdkVersion string //SDK版本号 59 | FileVersion string //激活文件版本号 60 | } 61 | 62 | // Version 版本信息结构体 63 | type Version struct { 64 | Version string // 版本号 65 | BuildDate string // 构建日期 66 | CopyRight string // Copyright 67 | } 68 | 69 | // SingleFaceInfo 单人脸信息结构体 70 | type SingleFaceInfo struct { 71 | FaceRect Rect // 人脸框信息 72 | FaceOrient int32 // 输入图像的角度,可以参考 ArcFaceCompare_OrientCode 73 | DataInfo C.ASF_FaceDataInfo 74 | } 75 | 76 | // FaceFeature 人脸特征结构体 77 | type FaceFeature struct { 78 | Feature []byte // 人脸特征信息 79 | FeatureSize int32 // 人脸特征信息长度 80 | native *C.ASF_FaceFeature 81 | featurePtr *C.MByte 82 | } 83 | 84 | // ImageData 对应ASVLOFFSCREEN结构体 85 | type ImageData struct { 86 | PixelArrayFormat C.MUInt32 87 | Width int 88 | Height int 89 | ImageData [4][]uint8 90 | WidthStep [4]int 91 | } 92 | 93 | // AgeInfo 年龄信息结构体 94 | type AgeInfo struct { 95 | AgeArray []int32 // "0" 代表不确定,大于0的数值代表检测出来的年龄结果 96 | Num int32 // 检测的人脸个数 97 | } 98 | 99 | // GenderInfo 性别信息结构体 100 | type GenderInfo struct { 101 | GenderArray []int32 // "0" 表示 男性, "1" 表示 女性, "-1" 表示不确定 102 | Num int32 // 检测的人脸个数 103 | } 104 | 105 | // Face3DAngle 人脸3D角度信息结构体 106 | type Face3DAngle struct { 107 | Roll []float32 108 | Yaw []float32 109 | Pitch []float32 110 | Status []int32 // 0: 正常,其他数值:出错 111 | Num int32 112 | } 113 | 114 | // LivenessInfo 活体信息 115 | type LivenessInfo struct { 116 | IsLive []int32 // 0:非真人 1:真人 -1:不确定 -2:传入人脸数>1 117 | Num int32 118 | } 119 | 120 | // FaceLandMark 特征点信息结构体 121 | type FaceLandMark struct { 122 | PosX float32 123 | PosY float32 124 | } 125 | 126 | // LandMarkInfo 额头区域点位 127 | type LandMarkInfo struct { 128 | Point []FaceLandMark 129 | Num int32 130 | } 131 | 132 | // MaskInfo 口罩信息结构体 133 | type MaskInfo struct { 134 | MaskArray []int32 // 0代表没有带口罩 1代表带口罩 -1表示不确定 135 | Num int32 // 检测的人脸个数 136 | } 137 | 138 | // EngineError SDK错误码 139 | type EngineError struct { 140 | Code int 141 | Text string 142 | } 143 | 144 | const ( 145 | // DetectModeVideo 视频模式 146 | DetectModeVideo = C.ASF_DETECT_MODE_VIDEO 147 | // DetectModeImage 图片模式 148 | DetectModeImage = C.ASF_DETECT_MODE_IMAGE 149 | // OrientPriority0 不旋转 150 | OrientPriority0 = C.ASF_OP_0_ONLY 151 | // OrientPriority90 旋转90度 152 | OrientPriority90 = C.ASF_OP_90_ONLY 153 | // OrientPriority270 旋转270度 154 | OrientPriority270 = C.ASF_OP_270_ONLY 155 | // OrientPriority180 旋转180度 156 | OrientPriority180 = C.ASF_OP_180_ONLY 157 | // OrientPriorityAllOut 角度不限 158 | OrientPriorityAllOut = C.ASF_OP_ALL_OUT 159 | // EnableNone 不开启任何功能 160 | EnableNone = C.ASF_NONE 161 | // EnableFaceDetect 开启人脸检测 162 | EnableFaceDetect = C.ASF_FACE_DETECT 163 | // EnableFaceRecognition 开启人脸识别 164 | EnableFaceRecognition = C.ASF_FACERECOGNITION 165 | // EnableAge 开启年龄检测 166 | EnableAge = C.ASF_AGE 167 | // EnableGender 开启性别检测 168 | EnableGender = C.ASF_GENDER 169 | // EnableFace3DAngle 开启人脸3D角度检测 170 | EnableFace3DAngle = C.ASF_FACE3DANGLE 171 | // EnableLiveness 开启活体检测 172 | EnableLiveness = C.ASF_LIVENESS 173 | // EnableIRLiveness 开启IR活体检测 174 | EnableIRLiveness = C.ASF_IR_LIVENESS 175 | // EnableFaceLandMark 开启人脸特征点检测 176 | EnableFaceLandMark = C.ASF_FACELANDMARK 177 | // EnableImageQuality 开启单人脸图片质量检测 178 | EnableImageQuality = C.ASF_IMAGEQUALITY 179 | // EnableFaceShelter 开启遮挡检测 180 | EnableFaceShelter = C.ASF_FACESHELTER 181 | // EnableMaskDetect 开启口罩检测 182 | EnableMaskDetect = C.ASF_MASKDETECT 183 | // EnableUpdateFaceData 开启人脸数据更新 184 | EnableUpdateFaceData = C.ASF_UPDATE_FACEDATA 185 | // ColorFormatBGR24 BGR24格式 186 | ColorFormatBGR24 = C.ASVL_PAF_RGB24_B8G8R8 187 | // ColorFormatNV12 NV12格式 188 | ColorFormatNV12 = C.ASVL_PAF_NV12 189 | // ColorFormatNV21 NV21格式 190 | ColorFormatNV21 = C.ASVL_PAF_NV21 191 | // ColorFormatI420 I420格式 192 | ColorFormatI420 = C.ASVL_PAF_I420 193 | // ColorFormatYUYV YUYV格式 194 | ColorFormatYUYV = C.ASVL_PAF_YUYV 195 | // RecognitionPhoto 识别照片 196 | RecognitionPhoto = C.ASF_RECOGNITION 197 | // RegisterPhoto 注册照片 198 | RegisterPhoto = C.ASF_REGISTER 199 | ) 200 | 201 | // NewFaceEngine 创建一个新的引擎实例 202 | // 203 | // 如果调用初始化函数失败则返回一个错误 204 | func NewFaceEngine( 205 | detectMode C.ASF_DetectMode, // 检测模式 206 | orientPriority C.ASF_OrientPriority, // 检测角度 207 | maxFaceNum C.MInt32, // 最大人脸数[1-10] 208 | combinedMask C.MInt32, // 检测选项 209 | ) (*FaceEngine, error) { 210 | engine, err := &FaceEngine{}, error(nil) 211 | r := C.ASFInitEngine(detectMode, orientPriority, maxFaceNum, combinedMask, &engine.handle) 212 | if r != C.MOK { 213 | err = newError(int(r), "初始化引擎失败") 214 | } 215 | return engine, err 216 | } 217 | 218 | // GetActiveFileInfo 获取激活文件信息接口 219 | func GetActiveFileInfo() (ActiveFileInfo, error) { 220 | asfActiveFileInfo := &C.ASF_ActiveFileInfo{} 221 | r := C.ASFGetActiveFileInfo(asfActiveFileInfo) 222 | if r != C.MOK { 223 | return ActiveFileInfo{}, newError(int(r), "获取激活文件信息失败") 224 | } 225 | info := ActiveFileInfo{ 226 | StartTime: C.GoString(asfActiveFileInfo.startTime), 227 | EndTime: C.GoString(asfActiveFileInfo.endTime), 228 | Platform: C.GoString(asfActiveFileInfo.platform), 229 | SdkType: C.GoString(asfActiveFileInfo.sdkType), 230 | AppID: C.GoString(asfActiveFileInfo.appId), 231 | SdkKey: C.GoString(asfActiveFileInfo.sdkKey), 232 | SdkVersion: C.GoString(asfActiveFileInfo.sdkVersion), 233 | FileVersion: C.GoString(asfActiveFileInfo.fileVersion), 234 | } 235 | return info, nil 236 | } 237 | 238 | // OnlineActivation 在线激活接口 239 | func OnlineActivation(appID, sdkKey, activeKey string) (err error) { 240 | id := C.CString(appID) 241 | sk := C.CString(sdkKey) 242 | ak := C.CString(activeKey) 243 | defer func() { 244 | C.free(unsafe.Pointer(id)) 245 | C.free(unsafe.Pointer(sk)) 246 | C.free(unsafe.Pointer(ak)) 247 | }() 248 | r := C.ASFOnlineActivation(id, sk, ak) 249 | if r != C.MOK && r != C.MERR_ASF_ALREADY_ACTIVATED { 250 | err = newError(int(r), "激活SDK失败") 251 | } 252 | return 253 | } 254 | 255 | // OfflineActivation 离线激活接口 256 | func OfflineActivation(filePath string) (err error) { 257 | cFilePath := C.CString(filePath) 258 | defer C.free(unsafe.Pointer(cFilePath)) 259 | r := C.ASFOfflineActivation(cFilePath) 260 | if r != C.MOK { 261 | err = newError(int(r), "离线激活失败") 262 | } 263 | return 264 | } 265 | 266 | // GetActiveDeviceInfo 采集当前设备信息(可离线) 267 | func GetActiveDeviceInfo() ([]byte, error) { 268 | deviceInfo := C.CString("") 269 | defer C.free(unsafe.Pointer(deviceInfo)) 270 | r := C.ASFGetActiveDeviceInfo((*C.MPChar)(unsafe.Pointer(&deviceInfo))) 271 | if r != C.MOK { 272 | return nil, newError(int(r), "采集当前设备信息失败") 273 | } 274 | str := C.GoString(deviceInfo) 275 | b := make([]byte, len(str)) 276 | copy(b, str) 277 | return b, nil 278 | } 279 | 280 | // DetectFaces 人脸检测,目前不支持IR图像数据检测 281 | func (engine *FaceEngine) DetectFaces( 282 | width int, // 宽度 283 | height int, // 高度 284 | format C.MInt32, // 图像格式 285 | imgData []byte, // 图片数据 286 | ) (faceInfo MultiFaceInfo, err error) { 287 | asfFaceInfo := &C.ASF_MultiFaceInfo{} 288 | r := C.ASFDetectFaces(engine.handle, 289 | C.MInt32(width), 290 | C.MInt32(height), 291 | format, 292 | (*C.MUInt8)(unsafe.Pointer(&imgData[0])), 293 | asfFaceInfo, 294 | C.ASF_DETECT_MODEL_RGB, 295 | ) 296 | if r != C.MOK { 297 | return faceInfo, newError(int(r), "人脸检测失败") 298 | } 299 | faceNum := int32(asfFaceInfo.faceNum) 300 | faceInfo.FaceNum = faceNum 301 | if faceNum > 0 { 302 | faceInfo.FaceRect = (*[10]Rect)(unsafe.Pointer(asfFaceInfo.faceRect))[:faceNum:faceNum] 303 | faceInfo.FaceOrient = (*[10]int32)(unsafe.Pointer(asfFaceInfo.faceOrient))[:faceNum:faceNum] 304 | } 305 | if asfFaceInfo.faceID != nil { 306 | faceInfo.FaceID = (*[10]int32)(unsafe.Pointer(asfFaceInfo.faceID))[:faceNum:faceNum] 307 | } 308 | if asfFaceInfo.faceDataInfoList != nil { 309 | faceInfo.FaceDataInfoList = (*[10]C.ASF_FaceDataInfo)(unsafe.Pointer(asfFaceInfo.faceDataInfoList))[:faceNum:faceNum] 310 | } 311 | faceInfo.native = asfFaceInfo 312 | return 313 | } 314 | 315 | // DetectFacesEx 检测人脸信息 316 | // 317 | // 该接口与 DetectFaces 功能一致,但采用结构体的形式传入图像数据,对更高精度的图像兼容性更好。 318 | func (engine *FaceEngine) DetectFacesEx(imageData ImageData) (faceInfo MultiFaceInfo, err error) { 319 | asfFaceInfo := &C.ASF_MultiFaceInfo{} 320 | r := C.ASFDetectFacesEx(engine.handle, imageDataToASVLOFFSCREEN(imageData), asfFaceInfo, C.ASF_DETECT_MODEL_RGB) 321 | if r != C.MOK { 322 | return faceInfo, newError(int(r), "人脸检测失败") 323 | } 324 | faceNum := int32(asfFaceInfo.faceNum) 325 | faceInfo.FaceNum = faceNum 326 | if faceNum > 0 { 327 | faceInfo.FaceRect = (*[10]Rect)(unsafe.Pointer(asfFaceInfo.faceRect))[:faceNum:faceNum] 328 | faceInfo.FaceOrient = (*[10]int32)(unsafe.Pointer(asfFaceInfo.faceOrient))[:faceNum:faceNum] 329 | } 330 | if asfFaceInfo.faceID != nil { 331 | faceInfo.FaceID = (*[10]int32)(unsafe.Pointer(asfFaceInfo.faceID))[:faceNum:faceNum] 332 | } 333 | if asfFaceInfo.faceDataInfoList != nil { 334 | faceInfo.FaceDataInfoList = (*[10]C.ASF_FaceDataInfo)(unsafe.Pointer(asfFaceInfo.faceDataInfoList))[:faceNum:faceNum] 335 | } 336 | faceInfo.native = asfFaceInfo 337 | return 338 | } 339 | 340 | // Process 年龄/性别/人脸3D角度(该接口仅支持RGB图像),最多支持4张人脸信息检测,超过部分返回未知 341 | // RGB活体仅支持单人脸检测,该接口不支持检测IR活体 342 | func (engine *FaceEngine) Process( 343 | width int, // 宽度 344 | height int, // 高度 345 | format C.MInt32, // 图像格式 346 | imgData []byte, // 图片数据 347 | detectedFaces MultiFaceInfo, // 多人脸信息 348 | combinedMask C.MInt32, // 检测选项 349 | ) error { 350 | r := C.ASFProcess(engine.handle, 351 | C.MInt32(width), 352 | C.MInt32(height), 353 | format, 354 | (*C.MUInt8)(unsafe.Pointer(&imgData[0])), 355 | detectedFaces.native, 356 | combinedMask) 357 | if r != C.MOK { 358 | return newError(int(r), "检测人脸信息失败") 359 | } 360 | return nil 361 | } 362 | 363 | // ProcessEx 人脸信息检测(年龄/性别/人脸3D角度),最多支持4张人脸信息检测,超过部分返回未知(活体仅支持单张人脸检测,超出返回未知),接口仅支持可见光图像检测 364 | // 365 | // 该接口与 Process 功能一致,但采用结构体的形式传入图像数据,对更高精度的图像兼容性更好 366 | func (engine *FaceEngine) ProcessEx(imageData ImageData, faceInfo MultiFaceInfo, combinedMask C.MInt32) error { 367 | r := C.ASFProcessEx(engine.handle, imageDataToASVLOFFSCREEN(imageData), faceInfo.native, combinedMask) 368 | if r != C.MOK { 369 | return newError(int(r), "检测人脸信息失败") 370 | } 371 | return nil 372 | } 373 | 374 | // ProcessIR 该接口目前仅支持单人脸IR活体检测(不支持年龄、性别、3D角度的检测),默认取第一张人脸 375 | func (engine *FaceEngine) ProcessIR( 376 | width int, // 宽度 377 | height int, // 高度 378 | format C.MInt32, // 图像格式 379 | imgData []byte, // 图片数据 380 | detectedFaces MultiFaceInfo, // 多人脸信息 381 | combinedMask C.MInt32, // 检测选项 382 | ) (err error) { 383 | r := C.ASFProcess(engine.handle, 384 | C.MInt32(width), 385 | C.MInt32(height), 386 | format, 387 | (*C.MUInt8)(unsafe.Pointer(&imgData[0])), 388 | detectedFaces.native, 389 | combinedMask) 390 | if r != C.MOK { 391 | return newError(int(r), "检测人脸IR活体信息失败") 392 | } 393 | return nil 394 | } 395 | 396 | // ProcessExIR 该接口目前仅支持单人脸IR活体检测(不支持年龄、性别、3D角度的检测),默认取第一张人脸 397 | // 398 | // 该接口与 ProcessIR 功能一致,但采用结构体的形式传入图像数据,对更高精度的图像兼容性更好 399 | func (engine *FaceEngine) ProcessExIR( 400 | imageData ImageData, // 图像数据 401 | faceInfo MultiFaceInfo, // 多人脸信息 402 | combinedMask C.MInt32, // 检测选项 403 | ) (err error) { 404 | r := C.ASFProcessEx_IR(engine.handle, imageDataToASVLOFFSCREEN(imageData), faceInfo.native, combinedMask) 405 | if r != C.MOK { 406 | return newError(int(r), "检测人脸IR活体信息失败") 407 | } 408 | return nil 409 | } 410 | 411 | // SetLivenessParam 设置活体置信度 412 | // 413 | // 取值范围[0-1]内部默认数值RGB-0.75,IR-0.7, 用户可以根据实际需求,设置不同的阈值 414 | func (engine *FaceEngine) SetLivenessParam(threshold LivenessThreshold) error { 415 | asfLivenessThreshold := &C.ASF_LivenessThreshold{ 416 | thresholdmodel_BGR: C.MFloat(threshold.ThresholdModelBGR), 417 | thresholdmodel_IR: C.MFloat(threshold.ThresholdModelIR), 418 | } 419 | r := C.ASFSetLivenessParam(engine.handle, asfLivenessThreshold) 420 | if r != C.MOK { 421 | return newError(int(r), "设置活体置信度失败") 422 | } 423 | return nil 424 | } 425 | 426 | // GetVersion 获取版本信息 427 | func (engine *FaceEngine) GetVersion() Version { 428 | info := C.ASFGetVersion() 429 | return Version{ 430 | Version: C.GoString(info.Version), 431 | BuildDate: C.GoString(info.BuildDate), 432 | CopyRight: C.GoString(info.CopyRight), 433 | } 434 | } 435 | 436 | // FaceFeatureExtract 单人脸特征提取 437 | func (engine *FaceEngine) FaceFeatureExtract( 438 | width int, // 宽度 439 | height int, // 高度 440 | format C.MInt32, // 图像格式 441 | imgData []byte, // 图片数据 442 | faceInfo SingleFaceInfo, // 单人脸信息 443 | registerOrNot int, // 图片模式 444 | mask int, // 是否带口罩 445 | ) (faceFeature FaceFeature, err error) { 446 | asfFaceFeature := &C.ASF_FaceFeature{} 447 | asfFaceInfo := &C.ASF_SingleFaceInfo{ 448 | C.MRECT{ 449 | C.MInt32(faceInfo.FaceRect.Left), 450 | C.MInt32(faceInfo.FaceRect.Top), 451 | C.MInt32(faceInfo.FaceRect.Right), 452 | C.MInt32(faceInfo.FaceRect.Bottom)}, 453 | C.MInt32(faceInfo.FaceOrient), 454 | faceInfo.DataInfo} 455 | r := C.ASFFaceFeatureExtract( 456 | engine.handle, 457 | C.MInt32(width), 458 | C.MInt32(height), 459 | format, 460 | (*C.MUInt8)(unsafe.Pointer(&imgData[0])), 461 | asfFaceInfo, 462 | C.ASF_RegisterOrNot(registerOrNot), 463 | C.MInt32(mask), 464 | asfFaceFeature) 465 | if r != C.MOK { 466 | return FaceFeature{}, newError(int(r), "提取人脸特征失败") 467 | } 468 | length := int32(asfFaceFeature.featureSize) 469 | faceFeature.FeatureSize = length 470 | faceFeature.Feature = make([]byte, length) 471 | byteArr := (*[1 << 12]byte)(unsafe.Pointer(asfFaceFeature.feature))[:length:length] 472 | arr := (*C.MByte)(C.malloc(C.size_t(int32(asfFaceFeature.featureSize)))) 473 | faceFeature.featurePtr = arr 474 | ps := (*[1 << 12]C.MByte)(unsafe.Pointer(arr))[:length:length] 475 | for i := 0; i < len(ps); i++ { 476 | ps[i] = C.MByte(byteArr[i]) 477 | faceFeature.Feature[i] = byteArr[i] 478 | } 479 | asfFaceFeature.feature = arr 480 | faceFeature.native = asfFaceFeature 481 | return faceFeature, err 482 | } 483 | 484 | // FaceFeatureExtractEx 单人脸特征提取 485 | // 486 | // 该接口与 ASFFaceFeatureExtract 功能一致,但采用结构体的形式传入图像数据,对更高精度的图像兼容性更好 487 | func (engine *FaceEngine) FaceFeatureExtractEx( 488 | imageData ImageData, // 图片数据 489 | faceInfo SingleFaceInfo, // 单人脸信息 490 | registerOrNot int, // 图片模式 491 | mask int, // 是否带口罩 492 | ) (feature FaceFeature, err error) { 493 | asfFaceFeature := &C.ASF_FaceFeature{} 494 | asfFaceInfo := &C.ASF_SingleFaceInfo{ 495 | C.MRECT{ 496 | C.MInt32(faceInfo.FaceRect.Left), 497 | C.MInt32(faceInfo.FaceRect.Top), 498 | C.MInt32(faceInfo.FaceRect.Right), 499 | C.MInt32(faceInfo.FaceRect.Bottom)}, 500 | C.MInt32(faceInfo.FaceOrient), 501 | faceInfo.DataInfo} 502 | r := C.ASFFaceFeatureExtractEx(engine.handle, imageDataToASVLOFFSCREEN(imageData), asfFaceInfo, C.ASF_RegisterOrNot(registerOrNot), C.MInt32(mask), asfFaceFeature) 503 | if r != C.MOK { 504 | return FaceFeature{}, newError(int(r), "提取人脸特征失败") 505 | } 506 | length := int32(asfFaceFeature.featureSize) 507 | feature.FeatureSize = length 508 | feature.Feature = make([]byte, length) 509 | byteArr := (*[1 << 12]byte)(unsafe.Pointer(asfFaceFeature.feature))[:length:length] 510 | arr := (*C.MByte)(C.malloc(C.size_t(int32(asfFaceFeature.featureSize)))) 511 | feature.featurePtr = arr 512 | ps := (*[1 << 12]C.MByte)(unsafe.Pointer(arr))[:length:length] 513 | for i := 0; i < len(ps); i++ { 514 | ps[i] = C.MByte(byteArr[i]) 515 | feature.Feature[i] = byteArr[i] 516 | } 517 | asfFaceFeature.feature = arr 518 | feature.native = asfFaceFeature 519 | return 520 | } 521 | 522 | // FaceFeatureCompare 人脸特征比对 523 | func (engine *FaceEngine) FaceFeatureCompare(feature1, feature2 FaceFeature) (confidenceLevel float32, err error) { 524 | r := C.ASFFaceFeatureCompare(engine.handle, 525 | feature1.native, 526 | feature2.native, 527 | (*C.MFloat)(unsafe.Pointer(&confidenceLevel)), 528 | C.ASF_DETECT_MODEL_RGB, 529 | ) 530 | if r != C.MOK { 531 | err = newError(int(r), "人脸特征比对失败!") 532 | } 533 | return 534 | } 535 | 536 | // GetAge 获取年龄信息 537 | func (engine *FaceEngine) GetAge() (AgeInfo, error) { 538 | asfAgeInfo := &C.ASF_AgeInfo{} 539 | r := C.ASFGetAge((C.MHandle)(engine.handle), asfAgeInfo) 540 | if r != C.MOK { 541 | return AgeInfo{}, newError(int(r), "获取年龄信息失败") 542 | } 543 | num := int32(asfAgeInfo.num) 544 | return AgeInfo{ 545 | AgeArray: (*[10]int32)(unsafe.Pointer(asfAgeInfo.ageArray))[:num:num], 546 | Num: num, 547 | }, nil 548 | } 549 | 550 | // GetGender 获取性别信息 551 | func (engine *FaceEngine) GetGender() (GenderInfo, error) { 552 | asfGenderInfo := &C.ASF_GenderInfo{} 553 | r := C.ASFGetGender((C.MHandle)(engine.handle), asfGenderInfo) 554 | if r != C.MOK { 555 | return GenderInfo{}, newError(int(r), "获取性别信息失败") 556 | } 557 | num := int32(asfGenderInfo.num) 558 | return GenderInfo{ 559 | GenderArray: (*[10]int32)(unsafe.Pointer(asfGenderInfo.genderArray))[:num:num], 560 | Num: num, 561 | }, nil 562 | } 563 | 564 | // GetFace3DAngle 获取3D角度信息 565 | func (engine *FaceEngine) GetFace3DAngle() (Face3DAngle, error) { 566 | asfFace3DAngle := &C.ASF_Face3DAngle{} 567 | r := C.ASFGetFace3DAngle((C.MHandle)(engine.handle), asfFace3DAngle) 568 | if r != C.MOK { 569 | return Face3DAngle{}, newError(int(r), "获取3D角度信息失败") 570 | } 571 | num := int32(asfFace3DAngle.num) 572 | return Face3DAngle{ 573 | Roll: (*[10]float32)(unsafe.Pointer(asfFace3DAngle.roll))[:num:num], 574 | Yaw: (*[10]float32)(unsafe.Pointer(asfFace3DAngle.yaw))[:num:num], 575 | Pitch: (*[10]float32)(unsafe.Pointer(asfFace3DAngle.pitch))[:num:num], 576 | Status: (*[10]int32)(unsafe.Pointer(asfFace3DAngle.status))[:num:num], 577 | Num: int32(asfFace3DAngle.num), 578 | }, nil 579 | } 580 | 581 | // GetLivenessScore 获取RGB活体结果 582 | func (engine *FaceEngine) GetLivenessScore() (LivenessInfo, error) { 583 | asfLivenessInfo := &C.ASF_LivenessInfo{} 584 | r := C.ASFGetLivenessScore((C.MHandle)(engine.handle), asfLivenessInfo) 585 | if r != C.MOK { 586 | return LivenessInfo{}, newError(int(r), "获取活体信息失败") 587 | } 588 | num := int32(asfLivenessInfo.num) 589 | return LivenessInfo{ 590 | IsLive: (*[10]int32)(unsafe.Pointer(asfLivenessInfo.isLive))[:num:num], 591 | Num: num, 592 | }, nil 593 | } 594 | 595 | // GetLivenessScoreIR 获取IR活体结果 596 | func (engine *FaceEngine) GetLivenessScoreIR() (LivenessInfo, error) { 597 | asfLivenessInfo := &C.ASF_LivenessInfo{} 598 | r := C.ASFGetLivenessScore_IR((C.MHandle)(engine.handle), asfLivenessInfo) 599 | if r != C.MOK { 600 | return LivenessInfo{}, newError(int(r), "获取活体信息失败") 601 | } 602 | num := int32(asfLivenessInfo.num) 603 | return LivenessInfo{ 604 | IsLive: (*[10]int32)(unsafe.Pointer(asfLivenessInfo.isLive))[:num:num], 605 | Num: num, 606 | }, nil 607 | } 608 | 609 | // GetMask 获取口罩信息 610 | func (engine *FaceEngine) GetMask() (maskInfo MaskInfo, err error) { 611 | asfMaskInfo := &C.ASF_MaskInfo{} 612 | r := C.ASFGetMask(engine.handle, (*C.ASF_MaskInfo)(unsafe.Pointer(asfMaskInfo))) 613 | if r != C.MOK { 614 | return maskInfo, newError(int(r), "获取口罩信息失败") 615 | } 616 | num := int32(asfMaskInfo.num) 617 | return MaskInfo{ 618 | MaskArray: (*[10]int32)(unsafe.Pointer(asfMaskInfo.maskArray))[:num:num], 619 | Num: num, 620 | }, nil 621 | } 622 | 623 | // GetFaceLandMarkInfo 获取额头区域位置 624 | func (engine *FaceEngine) GetFaceLandMarkInfo() (landMarkInfo LandMarkInfo, err error) { 625 | asfLandMarkInfo := &C.ASF_LandMarkInfo{} 626 | r := C.ASFGetFaceLandMark(engine.handle, asfLandMarkInfo) 627 | if r != C.MOK { 628 | return landMarkInfo, newError(int(r), "获取额头区域位置失败") 629 | } 630 | num := int32(asfLandMarkInfo.num) 631 | asfPoint := (*[10]C.ASF_FaceLandmark)(unsafe.Pointer(asfLandMarkInfo.point))[:num:num] 632 | point := make([]FaceLandMark, num) 633 | for i := int32(0); i < num; i++ { 634 | point[i] = FaceLandMark{ 635 | PosX: float32(asfPoint[i].x), 636 | PosY: float32(asfPoint[i].y), 637 | } 638 | } 639 | return LandMarkInfo{ 640 | Point: point, 641 | Num: num, 642 | }, nil 643 | } 644 | 645 | // UpdateFaceData 更新人脸数据 646 | func (engine *FaceEngine) UpdateFaceData( 647 | width int, // 宽度 648 | height int, // 高度 649 | format C.MInt32, // 图像格式 650 | imgData []byte, // 图片数据 651 | faceInfo MultiFaceInfo, // 多人脸信息 652 | ) (err error) { 653 | r := C.ASFUpdateFaceData(engine.handle, C.MInt32(width), C.MInt32(height), format, (*C.MUInt8)(unsafe.Pointer(&imgData[0])), faceInfo.native) 654 | if r != C.MOK { 655 | err = newError(int(r), "更新人脸数据失败") 656 | } 657 | return 658 | } 659 | 660 | // ImageQualityDetect 单人脸图片质量检测 661 | func (engine *FaceEngine) ImageQualityDetect( 662 | width int, // 宽度 663 | height int, // 高度 664 | format C.MInt32, // 图像格式 665 | imgData []byte, // 图片数据 666 | faceInfo SingleFaceInfo, // 单人脸信息 667 | isMask int, // 是否带口罩 668 | ) (confidenceLevel float32, err error) { 669 | asfFaceInfo := &C.ASF_SingleFaceInfo{ 670 | C.MRECT{ 671 | C.MInt32(faceInfo.FaceRect.Left), 672 | C.MInt32(faceInfo.FaceRect.Top), 673 | C.MInt32(faceInfo.FaceRect.Right), 674 | C.MInt32(faceInfo.FaceRect.Bottom)}, 675 | C.MInt32(faceInfo.FaceOrient), 676 | faceInfo.DataInfo} 677 | r := C.ASFImageQualityDetect( 678 | engine.handle, 679 | C.MInt32(width), 680 | C.MInt32(height), 681 | format, 682 | (*C.MUInt8)(unsafe.Pointer(&imgData[0])), 683 | asfFaceInfo, 684 | C.MInt32(isMask), 685 | (*C.MFloat)(unsafe.Pointer(&confidenceLevel)), 686 | C.ASF_DETECT_MODEL_RGB, 687 | ) 688 | if r != C.MOK { 689 | err = newError(int(r), "单人脸图片质量检测失败") 690 | } 691 | return confidenceLevel, err 692 | } 693 | 694 | // SetFaceShelterParam 设置遮挡算法检测的阈值 695 | func (engine *FaceEngine) SetFaceShelterParam(shelterThreshhold float32) (err error) { 696 | r := C.ASFSetFaceShelterParam(engine.handle, C.MFloat(shelterThreshhold)) 697 | if r != C.MOK { 698 | err = newError(int(r), "设置遮挡算法检测阈值失败") 699 | } 700 | return 701 | } 702 | 703 | // Destroy 销毁引擎 704 | func (engine *FaceEngine) Destroy() (err error) { 705 | r := C.ASFUninitEngine(engine.handle) 706 | if r != C.MOK { 707 | err = newError(int(r), "销毁引擎失败") 708 | } 709 | return 710 | } 711 | 712 | // GetSingleFaceInfo 从多人脸结构体中提取单人脸信息 713 | func GetSingleFaceInfo(multiFaceInfo MultiFaceInfo) (faceInfo []SingleFaceInfo) { 714 | faceInfo = make([]SingleFaceInfo, multiFaceInfo.FaceNum) 715 | for i := 0; i < len(faceInfo); i++ { 716 | faceInfo[i].FaceRect = Rect{ 717 | Left: multiFaceInfo.FaceRect[i].Left, 718 | Top: multiFaceInfo.FaceRect[i].Top, 719 | Right: multiFaceInfo.FaceRect[i].Right, 720 | Bottom: multiFaceInfo.FaceRect[i].Bottom, 721 | } 722 | faceInfo[i].FaceOrient = multiFaceInfo.FaceOrient[i] 723 | faceInfo[i].DataInfo = multiFaceInfo.FaceDataInfoList[i] 724 | } 725 | return 726 | } 727 | 728 | // ReadFaceFeatureFromBytes 将字节数据转为人脸特征数据 729 | func ReadFaceFeatureFromBytes(bytes []byte) (feature FaceFeature) { 730 | asfFaceFeature := &C.ASF_FaceFeature{} 731 | arr := (*C.MByte)(C.malloc(C.size_t(int32(len(bytes))))) 732 | featurePtr := (*C.uchar)(unsafe.Pointer(C.CString(string(bytes)))) 733 | asfFaceFeature.feature = featurePtr 734 | asfFaceFeature.featureSize = C.int(len(bytes)) 735 | return FaceFeature{ 736 | Feature: bytes, 737 | FeatureSize: int32(len(bytes)), 738 | featurePtr: arr, 739 | native: asfFaceFeature, 740 | } 741 | } 742 | 743 | // Release 释放内存 744 | func (feature *FaceFeature) Release() { 745 | if feature.featurePtr != nil { 746 | C.free(unsafe.Pointer(feature.featurePtr)) 747 | } 748 | } 749 | 750 | // 实现Error接口 751 | func (err EngineError) Error() string { 752 | return err.Text 753 | } 754 | 755 | func newError(code int, text string) EngineError { 756 | return EngineError{ 757 | Code: code, 758 | Text: text, 759 | } 760 | } 761 | 762 | func imageDataToASVLOFFSCREEN(imageData ImageData) C.LPASVLOFFSCREEN { 763 | var pi32Pitch [4](C.MInt32) 764 | for i := 0; i < 4; i++ { 765 | pi32Pitch[i] = C.MInt32(imageData.WidthStep[0]) 766 | } 767 | var ppu8Plane [4](*C.MUInt8) 768 | for i := 0; i < 4; i++ { 769 | if len(imageData.ImageData[i]) > 0 { 770 | ppu8Plane[i] = (*C.MUInt8)(unsafe.Pointer(&imageData.ImageData[i][0])) 771 | } 772 | } 773 | return &C.ASVLOFFSCREEN{ 774 | imageData.PixelArrayFormat, 775 | C.MInt32(imageData.Width), 776 | C.MInt32(imageData.Height), 777 | ppu8Plane, 778 | pi32Pitch} 779 | } 780 | -------------------------------------------------------------------------------- /examples/example1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | . "github.com/windosx/face-engine/v4" 7 | "github.com/windosx/face-engine/v4/util" 8 | ) 9 | 10 | var imageInfo = util.GetResizedImageInfo("./mask.jpg") 11 | 12 | func main() { 13 | // 激活SDK 14 | if err := OnlineActivation("YourAppID", "YourSDKKey", "YourActiveCode"); err != nil { 15 | fmt.Printf("%#v\n", err) 16 | return 17 | } 18 | // 初始化引擎 19 | engine, err := NewFaceEngine(DetectModeImage, 20 | OrientPriority0, 21 | 10, // 4.0最大支持10个人脸 22 | EnableFaceDetect|EnableFaceRecognition|EnableFace3DAngle|EnableLiveness|EnableIRLiveness|EnableAge|EnableGender|EnableMaskDetect|EnableFaceLandMark) 23 | if err != nil { 24 | fmt.Printf("%#v\n", err) 25 | return 26 | } 27 | deviceInfo, err := GetActiveDeviceInfo() 28 | if err != nil { 29 | fmt.Printf("%#v\n", err) 30 | } 31 | fmt.Printf("设备信息:%s\n", deviceInfo) 32 | // 检测人脸 33 | info, err := engine.DetectFaces(imageInfo.Width, imageInfo.Height, ColorFormatBGR24, imageInfo.DataUInt8) 34 | if err != nil { 35 | fmt.Printf("%#v\n", err) 36 | return 37 | } 38 | // 处理人脸数据 39 | if err = engine.Process(imageInfo.Width, imageInfo.Height, ColorFormatBGR24, imageInfo.DataUInt8, info, EnableAge|EnableGender|EnableFace3DAngle|EnableLiveness|EnableMaskDetect|EnableFaceLandMark); err != nil { 40 | fmt.Printf("%#v\n", err) 41 | return 42 | } 43 | // 获取年龄 44 | ageInfo, err := engine.GetAge() 45 | if err != nil { 46 | fmt.Printf("%#v\n", err) 47 | return 48 | } 49 | fmt.Printf("ageInfo: %v\n", ageInfo) 50 | // 获取口罩信息 51 | maskInfo, err := engine.GetMask() 52 | if err != nil { 53 | fmt.Printf("%#v\n", err) 54 | return 55 | } 56 | fmt.Printf("口罩信息:%#v\n", maskInfo) 57 | // 获取额头点位 58 | landMark, err := engine.GetFaceLandMarkInfo() 59 | if err != nil { 60 | fmt.Printf("%#v\n", err) 61 | return 62 | } 63 | fmt.Printf("额头点位:%#v\n", landMark) 64 | // 销毁引擎 65 | if err = engine.Destroy(); err != nil { 66 | fmt.Printf("%#v\n", err) 67 | return 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/windosx/face-engine/v4 2 | 3 | go 1.15 4 | -------------------------------------------------------------------------------- /include/amcomdef.h: -------------------------------------------------------------------------------- 1 | #ifndef __AMCOMDEF_H__ 2 | #define __AMCOMDEF_H__ 3 | 4 | 5 | #if defined(WINCE) || defined(WIN32) 6 | 7 | #ifndef _WCHAR_T_DEFINED 8 | typedef unsigned short wchar_t; 9 | #define _WCHAR_T_DEFINED 10 | #endif//#ifndef _WCHAR_T_DEFINED 11 | 12 | #elif (defined(EKA2) && defined(__GCCE__)) 13 | #ifndef _STDDEF_H_ 14 | #ifndef __cplusplus 15 | typedef unsigned short wchar_t; 16 | #define __wchar_t_defined 17 | #endif 18 | #endif 19 | 20 | 21 | #elif defined(__GCCE__) || defined(__GCC32__) 22 | #ifndef _STDDEF_H_ 23 | typedef unsigned short wchar_t; 24 | #endif 25 | 26 | #endif//#if defined(WINCE) 27 | 28 | 29 | #if defined(__GCC32__) || defined(__GCCE__) || defined(WINCE) || defined(WIN32) 30 | typedef wchar_t MWChar; 31 | #else 32 | typedef unsigned short MWChar; 33 | #endif 34 | 35 | 36 | typedef long MLong; 37 | typedef float MFloat; 38 | typedef double MDouble; 39 | typedef unsigned char MByte; 40 | typedef unsigned short MWord; 41 | typedef unsigned int MDWord; 42 | typedef void* MHandle; 43 | typedef char MChar; 44 | typedef long MBool; 45 | typedef void MVoid; 46 | typedef void* MPVoid; 47 | typedef char* MPChar; 48 | typedef short MShort; 49 | typedef const char* MPCChar; 50 | typedef MLong MRESULT; 51 | typedef MDWord MCOLORREF; 52 | typedef signed char MInt8; 53 | typedef unsigned char MUInt8; 54 | typedef signed short MInt16; 55 | typedef unsigned short MUInt16; 56 | typedef signed int MInt32; 57 | typedef unsigned int MUInt32; 58 | 59 | #if !defined(M_UNSUPPORT64) 60 | #if defined(_MSC_VER) 61 | typedef signed __int64 MInt64; 62 | typedef unsigned __int64 MUInt64; 63 | #else 64 | typedef signed long long MInt64; 65 | typedef unsigned long long MUInt64; 66 | #endif 67 | #endif 68 | 69 | typedef struct __tag_rect 70 | { 71 | MInt32 left; 72 | MInt32 top; 73 | MInt32 right; 74 | MInt32 bottom; 75 | } MRECT, *PMRECT; 76 | 77 | typedef struct __tag_point 78 | { 79 | MInt32 x; 80 | MInt32 y; 81 | } MPOINT, *PMPOINT; 82 | 83 | 84 | #define MNull 0 85 | #define MFalse 0 86 | #define MTrue 1 87 | 88 | //#ifndef MAX_PATH 89 | //#define MAX_PATH 256 90 | //#endif 91 | 92 | #ifdef M_WIDE_CHAR 93 | #define MTChar MWChar 94 | #else 95 | #define MTChar MChar 96 | #endif 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /include/arcsoft_face_sdk.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright(c) ArcSoft, All right reserved. 3 | * 4 | * This file is ArcSoft's property. It contains ArcSoft's trade secret, proprietary 5 | * and confidential information. 6 | * 7 | * DO NOT DISTRIBUTE, DO NOT DUPLICATE OR TRANSMIT IN ANY FORM WITHOUT PROPER 8 | * AUTHORIZATION. 9 | * 10 | * If you are not an intended recipient of this file, you must not copy, 11 | * distribute, modify, or take any action in reliance on it. 12 | * 13 | * If you have received this file in error, please immediately notify ArcSoft and 14 | * permanently delete the original and any copy of any file and any printout 15 | * thereof. 16 | *********************************************************************************/ 17 | 18 | #ifndef _ARCSOFT_SDK_ASF_H_ 19 | #define _ARCSOFT_SDK_ASF_H_ 20 | 21 | #include "amcomdef.h" 22 | #include "asvloffscreen.h" 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | #define ASF_NONE 0x00000000 //������ 29 | #define ASF_FACE_DETECT 0x00000001 //�˴�detect������tracking����detection��������֮һ�������ѡ����detect mode ȷ�� 30 | #define ASF_FACERECOGNITION 0x00000004 //�������� 31 | #define ASF_AGE 0x00000008 //���� 32 | #define ASF_GENDER 0x00000010 //�Ա� 33 | #define ASF_FACE3DANGLE 0x00000020 //3D�Ƕ� 34 | #define ASF_FACELANDMARK 0x00000040 //��ͷ������ 35 | #define ASF_LIVENESS 0x00000080 //RGB���� 36 | #define ASF_IMAGEQUALITY 0x00000200 //ͼ��������� 37 | #define ASF_IR_LIVENESS 0x00000400 //IR���� 38 | #define ASF_FACESHELTER 0x00000800 //�����ڵ� 39 | #define ASF_MASKDETECT 0x00001000 //���ּ�� 40 | #define ASF_UPDATE_FACEDATA 0x00002000 //������Ϣ 41 | 42 | 43 | #define ASF_MAX_DETECTFACENUM 10 //�ð汾���֧��ͬʱ���10������ 44 | 45 | //���ģʽ 46 | typedef enum __tag_ASF_DetectMode{ 47 | ASF_DETECT_MODE_VIDEO = 0x00000000, //Videoģʽ��һ�����ڶ�֡������� 48 | ASF_DETECT_MODE_IMAGE = 0xFFFFFFFF //Imageģʽ��һ�����ھ�̬ͼ�ĵ��μ�� 49 | } ASF_DetectMode; 50 | 51 | //���ʱ�������Ƕȵ����ȼ������ĵ��г�ʼ���ӿ�����ͼʾ˵������ο� 52 | typedef enum __tag_ASF_OrientPriority { 53 | ASF_OP_0_ONLY = 0x1, // ����Ԥ���������� 54 | ASF_OP_90_ONLY = 0x2, // ����0����ʱ����ת90��ķ��� 55 | ASF_OP_270_ONLY = 0x3, // ����0����ʱ����ת270��ķ��� 56 | ASF_OP_180_ONLY = 0x4, // ����0����ת180��ķ�����ʱ�롢˳ʱ��Ч��һ���� 57 | ASF_OP_ALL_OUT = 0x5 // ȫ�Ƕ� 58 | } ASF_OrientPriority; 59 | 60 | //orientation �Ƕȣ���ʱ�뷽�� 61 | typedef enum __tag_ASF_OrientCode { 62 | ASF_OC_0 = 0x1, // 0 degree 63 | ASF_OC_90 = 0x2, // 90 degree 64 | ASF_OC_270 = 0x3, // 270 degree 65 | ASF_OC_180 = 0x4, // 180 degree 66 | ASF_OC_30 = 0x5, // 30 degree 67 | ASF_OC_60 = 0x6, // 60 degree 68 | ASF_OC_120 = 0x7, // 120 degree 69 | ASF_OC_150 = 0x8, // 150 degree 70 | ASF_OC_210 = 0x9, // 210 degree 71 | ASF_OC_240 = 0xa, // 240 degree 72 | ASF_OC_300 = 0xb, // 300 degree 73 | ASF_OC_330 = 0xc // 330 degree 74 | } ASF_OrientCode; 75 | 76 | //���ģ�� 77 | typedef enum __tag_ASF_DetectModel { 78 | ASF_DETECT_MODEL_RGB = 0x1 //RGBͼ����ģ�� 79 | //Ԥ����չ�������ģ�� 80 | } ASF_DetectModel; 81 | 82 | //�����ȶԿ�ѡ��ģ�� 83 | typedef enum __tag_ASF_CompareModel{ 84 | ASF_LIFE_PHOTO = 0x1, //����������֮��������ȶԣ��Ƽ���ֵ0.80 85 | ASF_ID_PHOTO = 0x2 //����֤���ջ���������֤����֮��������ȶԣ��Ƽ���ֵ0.82 86 | } ASF_CompareModel; 87 | 88 | typedef enum __tag_ASF_RegisterOrNot{ 89 | ASF_RECOGNITION = 0x0, //����ʶ��������������ȡ 90 | ASF_REGISTER = 0x1 //����ע��������������ȡ 91 | } ASF_RegisterOrNot; 92 | 93 | //�汾��Ϣ 94 | typedef struct { 95 | MPChar Version; // �汾�� 96 | MPChar BuildDate; // �������� 97 | MPChar CopyRight; // Copyright 98 | }ASF_VERSION, *LPASF_VERSION; 99 | 100 | //ͼ������ 101 | typedef LPASVLOFFSCREEN LPASF_ImageData; 102 | 103 | //������Ϣ 104 | typedef struct{ 105 | MPVoid data; // ������Ϣ 106 | MInt32 dataSize; // ������Ϣ���� 107 | } ASF_FaceDataInfo, *LPASF_FaceDataInfo; 108 | 109 | //��������Ϣ 110 | typedef struct SingleFaceInfo { 111 | MRECT faceRect; // ��������Ϣ 112 | MInt32 faceOrient; // ����ͼ��ĽǶȣ����Բο� ArcFaceCompare_OrientCode 113 | ASF_FaceDataInfo faceDataInfo; // ����������Ϣ 114 | } ASF_SingleFaceInfo, *LPASF_SingleFaceInfo; 115 | 116 | //��������Ϣ 117 | typedef struct MultiFaceInfo { 118 | MRECT* faceRect; // ��������Ϣ 119 | MInt32* faceOrient; // ����ͼ��ĽǶȣ����Բο� ArcFaceCompare_OrientCode . 120 | MInt32 faceNum; // ��⵽���������� 121 | MInt32* faceID; // face ID��IMAGEģʽ�²�����FaceID 122 | MFloat* wearGlasses; // ���۾����Ŷ�[0-1],�Ƽ���ֵ0.5 123 | MInt32* leftEyeClosed; // ����״̬ 0 δ���ۣ�1 ���� 124 | MInt32* rightEyeClosed; // ����״̬ 0 δ���ۣ�1 ���� 125 | MInt32* faceShelter; // "1" ��ʾ �ڵ�, "0" ��ʾ δ�ڵ�, "-1" ��ʾ��ȷ�� 126 | LPASF_FaceDataInfo faceDataInfoList; // ����������Ϣ 127 | }ASF_MultiFaceInfo, *LPASF_MultiFaceInfo; 128 | 129 | // �����ļ���Ϣ 130 | typedef struct ActiveFileInfo { 131 | MPChar startTime; //��ʼʱ�� 132 | MPChar endTime; //��ֹʱ�� 133 | MPChar activeKey; //������ 134 | MPChar platform; //ƽ̨ 135 | MPChar sdkType; //sdk���� 136 | MPChar appId; //APPID 137 | MPChar sdkKey; //SDKKEY 138 | MPChar sdkVersion; //SDK�汾�� 139 | MPChar fileVersion; //�����ļ��汾�� 140 | }ASF_ActiveFileInfo, *LPASF_ActiveFileInfo; 141 | 142 | /******************************************************************************************* 143 | * ��ȡ�����ļ���Ϣ�ӿ� 144 | *******************************************************************************************/ 145 | MRESULT ASFGetActiveFileInfo( 146 | LPASF_ActiveFileInfo activeFileInfo // [out] �����ļ���Ϣ 147 | ); 148 | 149 | /******************************************************************************************* 150 | * ���߼���ӿ� 151 | *******************************************************************************************/ 152 | MRESULT ASFOnlineActivation( 153 | MPChar AppId, // [in] APPID �������� 154 | MPChar SDKKey, // [in] SDKKEY �������� 155 | MPChar ActiveKey // [in] ActiveKey �������� 156 | ); 157 | 158 | /******************************************************************************************* 159 | * ��ȡ�豸��Ϣ�ӿ� 160 | *******************************************************************************************/ 161 | MRESULT ASFGetActiveDeviceInfo( 162 | MPChar* deviceInfo // [out] �ɼ����豸��Ϣ�����ڵ����������������߼������������Ȩ�ļ� 163 | ); 164 | 165 | /******************************************************************************************* 166 | * ���߼���ӿ� 167 | *******************************************************************************************/ 168 | MRESULT ASFOfflineActivation( 169 | MPChar filePath // [in] �����ļ�·��(������Ȩ�ļ�)����Ҫ��дȨ�� 170 | ); 171 | 172 | /************************************************************************ 173 | * ��ʼ������ 174 | ************************************************************************/ 175 | MRESULT ASFInitEngine( 176 | ASF_DetectMode detectMode, // [in] AF_DETECT_MODE_VIDEO ��Ƶģʽ������������ͷԤ������Ƶ�ļ�ʶ�� 177 | // AF_DETECT_MODE_IMAGE ͼƬģʽ�������ھ�̬ͼƬ��ʶ�� 178 | ASF_OrientPriority detectFaceOrientPriority, // [in] ��������ĽǶ�����ֵ���ο� ArcFaceCompare_OrientPriority 179 | MInt32 detectFaceMaxNum, // [in] �����Ҫ������������ 180 | MInt32 combinedMask, // [in] �û�ѡ����Ҫ���Ĺ�����ϣ��ɵ������� 181 | MHandle* hEngine // [out] ��ʼ�����ص�����handle 182 | ); 183 | 184 | /************************************************************************ 185 | * ȡֵ��Χ[0-1]�� Ĭ����ֵ:0.8�� �û����Ը���ʵ�����������ڵ���Χ 186 | ************************************************************************/ 187 | MRESULT ASFSetFaceShelterParam( 188 | MHandle hEngine, // [in] ����handle 189 | MFloat ShelterThreshhold // [in] �ڵ���ֵ 190 | ); 191 | 192 | /****************************************************** 193 | * VIDEOģʽ:����׷�� IMAGEģʽ:������� 194 | ******************************************************/ 195 | MRESULT ASFDetectFaces( 196 | MHandle hEngine, // [in] ����handle 197 | MInt32 width, // [in] ͼƬ���� 198 | MInt32 height, // [in] ͼƬ�߶� 199 | MInt32 format, // [in] ��ɫ�ռ��ʽ 200 | MUInt8* imgData, // [in] ͼƬ���� 201 | LPASF_MultiFaceInfo detectedFaces, // [out]��⵽��������Ϣ 202 | ASF_DetectModel detectModel // [in] Ԥ���ֶΣ���ǰ�汾ʹ��Ĭ�ϲ������� 203 | ); 204 | 205 | /****************************************************** 206 | * VIDEOģʽ:����׷�� IMAGEģʽ:������� 207 | * ͼ�������Խṹ����ʽ���룬�Բ��ø����ֽڶ��뷽ʽ��ͼ������Ը��� 208 | ******************************************************/ 209 | MRESULT ASFDetectFacesEx( 210 | MHandle hEngine, // [in] ����handle 211 | LPASF_ImageData imgData, // [in] ͼƬ���� 212 | LPASF_MultiFaceInfo detectedFaces, // [out] ��⵽��������Ϣ 213 | ASF_DetectModel detectModel // [in] Ԥ���ֶΣ���ǰ�汾ʹ��Ĭ�ϲ������� 214 | ); 215 | 216 | /****************************************************** 217 | * �����޸ĺ�������򣬸���������Ϣ��������˫Ŀ������������� 218 | * ע�⣺LPASF_MultiFaceInfo�ڸýӿ��м������Ҳ�dz��� 219 | ******************************************************/ 220 | MRESULT ASFUpdateFaceData( 221 | MHandle hEngine, // [in] ����handle 222 | MInt32 width, // [in] ͼƬ���� 223 | MInt32 height, // [in] ͼƬ�߶� 224 | MInt32 format, // [in] ��ɫ�ռ��ʽ 225 | MUInt8 * imgData, // [in] ͼƬ���� 226 | LPASF_MultiFaceInfo detectedFaces // [in/out]��⵽��������Ϣ 227 | ); 228 | 229 | /****************************************************** 230 | * �����޸ĺ�������򣬸���������Ϣ��������˫Ŀ������������� 231 | * ע�⣺LPASF_MultiFaceInfo�ڸýӿ��м������Ҳ�dz��� 232 | * ͼ�������Խṹ����ʽ���룬�Բ��ø����ֽڶ��뷽ʽ��ͼ������Ը��� 233 | ******************************************************/ 234 | MRESULT ASFUpdateFaceDataEx( 235 | MHandle hEngine, // [in] ����handle 236 | LPASF_ImageData imgData, // [in] ͼ������ 237 | LPASF_MultiFaceInfo detectedFaces // [in/out] ��⵽��������Ϣ 238 | ); 239 | 240 | /****************************************************** 241 | * ͼ��������⣬��RGBģʽ�� ʶ����ֵ��0.49 ע����ֵ��0.63 ����ģʽ��ʶ����ֵ��0.29�� 242 | ******************************************************/ 243 | MRESULT ASFImageQualityDetect( 244 | MHandle hEngine, // [in] ����handle 245 | MInt32 width, // [in] ͼƬ���� 246 | MInt32 height, // [in] ͼƬ�߶� 247 | MInt32 format, // [in] ��ɫ�ռ��ʽ 248 | MUInt8 * imgData, // [in] ͼƬ���� 249 | LPASF_SingleFaceInfo faceInfo, // [in] ����λ����Ϣ 250 | MInt32 isMask, // [in] ��֧�ִ���1��0��-1�������� 1��������Ϊδ������ 251 | MFloat* confidenceLevel, // [out] ͼ����������� 252 | ASF_DetectModel detectModel // [in] Ԥ���ֶΣ���ǰ�汾ʹ��Ĭ�ϲ������� 253 | ); 254 | 255 | /****************************************************** 256 | * ͼ��������⣬��RGBģʽ�� ʶ����ֵ��0.49 ע����ֵ��0.63 ����ģʽ��ʶ����ֵ��0.29�� 257 | * ͼ�������Խṹ����ʽ���룬�Բ��ø����ֽڶ��뷽ʽ��ͼ������Ը��� 258 | ******************************************************/ 259 | MRESULT ASFImageQualityDetectEx( 260 | MHandle hEngine, // [in] ����handle 261 | LPASF_ImageData imgData, // [in] ͼƬ���� 262 | LPASF_SingleFaceInfo faceInfo, // [in] ����λ����Ϣ 263 | MInt32 isMask, // [in] ��֧�ִ���1��0��-1�������� 1��������Ϊδ������ 264 | MFloat* confidenceLevel, // [out] ͼ����������� 265 | ASF_DetectModel detectModel // [in] Ԥ���ֶΣ���ǰ�汾ʹ��Ĭ�ϲ������� 266 | ); 267 | 268 | /************************************************************************ 269 | * ����/�Ա�/����3D�Ƕ�/����/�ڵ�/��ͷ���򣨸ýӿڽ�֧��RGBͼ�񣩣����֧��4��������Ϣ��⣬�������ַ���δ֪ 270 | * RGB�����֧�ֵ�������⣬�ýӿڲ�֧�ּ��IR���� 271 | ************************************************************************/ 272 | MRESULT ASFProcess( 273 | MHandle hEngine, // [in] ����handle 274 | MInt32 width, // [in] ͼƬ���� 275 | MInt32 height, // [in] ͼƬ�߶� 276 | MInt32 format, // [in] ��ɫ�ռ��ʽ 277 | MUInt8* imgData, // [in] ͼƬ���� 278 | LPASF_MultiFaceInfo detectedFaces, // [in] ������Ϣ���û����ݴ����Ĺ���ѡ����Ҫʹ�õ������� 279 | MInt32 combinedMask // [in] ֻ֧�ֳ�ʼ��ʱ��ָ����Ҫ���Ĺ��ܣ���processʱ��һ��������Ѿ�ָ���Ĺ��ܼ��м���ɸѡ 280 | // �����ʼ����ʱ��ָ�����������Ա���process��ʱ�����ֻ������䣬���Dz��ܼ���������Ա�֮��Ĺ��� 281 | ); 282 | 283 | /************************************************************************ 284 | * ����/�Ա�/����3D�Ƕ�/����/�ڵ�/��ͷ���򣨸ýӿڽ�֧��RGBͼ�񣩣����֧��4��������Ϣ��⣬�������ַ���δ֪ 285 | * RGB�����֧�ֵ�������⣬�ýӿڲ�֧�ּ��IR���� 286 | * ͼ�������Խṹ����ʽ���룬�Բ��ø����ֽڶ��뷽ʽ��ͼ������Ը��� 287 | ************************************************************************/ 288 | MRESULT ASFProcessEx( 289 | MHandle hEngine, // [in] ����handle 290 | LPASF_ImageData imgData, // [in] ͼƬ���� 291 | LPASF_MultiFaceInfo detectedFaces, // [in] ������Ϣ���û����ݴ����Ĺ���ѡ����Ҫʹ�õ������� 292 | MInt32 combinedMask // [in] ֻ֧�ֳ�ʼ��ʱ��ָ����Ҫ���Ĺ��ܣ���processʱ��һ��������Ѿ�ָ���Ĺ��ܼ��м���ɸѡ 293 | // �����ʼ����ʱ��ָ�����������Ա���process��ʱ�����ֻ������䣬���Dz��ܼ���������Ա�֮��Ĺ��� 294 | ); 295 | 296 | /************************************************************************ 297 | * �ýӿ�Ŀǰ��֧�ֵ�����IR�����⣬Ĭ��ȡ��һ������ 298 | ************************************************************************/ 299 | MRESULT ASFProcess_IR( 300 | MHandle hEngine, // [in] ����handle 301 | MInt32 width, // [in] ͼƬ���� 302 | MInt32 height, // [in] ͼƬ�߶� 303 | MInt32 format, // [in] ��ɫ�ռ��ʽ 304 | MUInt8* imgData, // [in] ͼƬ���� 305 | LPASF_MultiFaceInfo detectedFaces, // [in] ������Ϣ���û����ݴ����Ĺ���ѡ����Ҫʹ�õ������� 306 | MInt32 combinedMask // [in] Ŀǰֻ֧�ִ���ASF_IR_LIVENESS���ԵĴ��룬�ҳ�ʼ���ӿ���Ҫ���� 307 | ); 308 | 309 | /************************************************************************ 310 | * �ýӿ�Ŀǰ��֧�ֵ�����IR�����⣬Ĭ��ȡ��һ������ 311 | * ͼ�������Խṹ����ʽ���룬�Բ��ø����ֽڶ��뷽ʽ��ͼ������Ը��� 312 | ************************************************************************/ 313 | MRESULT ASFProcessEx_IR( 314 | MHandle hEngine, // [in] ����handle 315 | LPASF_ImageData imgData, // [in] ͼƬ���� 316 | LPASF_MultiFaceInfo detectedFaces, // [in] ������Ϣ���û����ݴ����Ĺ���ѡ����Ҫʹ�õ������� 317 | MInt32 combinedMask // [in] Ŀǰֻ֧�ִ���ASF_IR_LIVENESS���ԵĴ��룬�ҳ�ʼ���ӿ���Ҫ���� 318 | ); 319 | 320 | //******************************** ����ʶ����� ********************************************* 321 | typedef struct FaceFeature { 322 | MByte* feature; // ����������Ϣ 323 | MInt32 featureSize; // ����������Ϣ���� 324 | }ASF_FaceFeature, *LPASF_FaceFeature; 325 | 326 | /************************************************************************ 327 | * ������������ȡ 328 | ************************************************************************/ 329 | MRESULT ASFFaceFeatureExtract( 330 | MHandle hEngine, // [in] ����handle 331 | MInt32 width, // [in] ͼƬ���� 332 | MInt32 height, // [in] ͼƬ�߶� 333 | MInt32 format, // [in] ��ɫ�ռ��ʽ 334 | MUInt8* imgData, // [in] ͼƬ���� 335 | LPASF_SingleFaceInfo faceInfo, // [in] ��������λ�úͽǶ���Ϣ 336 | ASF_RegisterOrNot registerOrNot, // [in] ע�� 1 ʶ��Ϊ 0 337 | MInt32 mask, // [in] ������ 1������0 338 | LPASF_FaceFeature feature // [out] �������� 339 | ); 340 | 341 | /************************************************************************ 342 | * ������������ȡ 343 | * ͼ�������Խṹ����ʽ���룬�Բ��ø����ֽڶ��뷽ʽ��ͼ������Ը��� 344 | ************************************************************************/ 345 | MRESULT ASFFaceFeatureExtractEx( 346 | MHandle hEngine, // [in] ����handle 347 | LPASF_ImageData imgData, // [in] ͼ������ 348 | LPASF_SingleFaceInfo faceInfo, // [in] ��������λ�úͽǶ���Ϣ 349 | ASF_RegisterOrNot registerOrNot, // [in] ע�� 1 ʶ��Ϊ 0 350 | MInt32 mask, // [in] ������ 1������0 351 | LPASF_FaceFeature feature // [out] �������� 352 | ); 353 | 354 | /************************************************************************ 355 | * ���������ȶԣ��Ƽ���ֵ ASF_LIFE_PHOTO��0.80 ASF_ID_PHOTO��0.82 356 | ************************************************************************/ 357 | MRESULT ASFFaceFeatureCompare( 358 | MHandle hEngine, // [in] ����handle 359 | LPASF_FaceFeature feature1, // [in] ���Ƚ���������1 360 | LPASF_FaceFeature feature2, // [in] ���Ƚ���������2 361 | MFloat* confidenceLevel, // [out] �ȽϽ�������Ŷ���ֵ 362 | ASF_CompareModel compareModel // [in] ASF_LIFE_PHOTO������������֮��������ȶ� 363 | // ASF_ID_PHOTO������֤���ջ�֤���պ�������֮��������ȶ� 364 | ); 365 | 366 | //******************************** ������� ********************************************** 367 | typedef struct AgeInfo { 368 | MInt32* ageArray; // "0" ������ȷ��������0����ֵ������������������ 369 | MInt32 num; // ������������ 370 | }ASF_AgeInfo, *LPASF_AgeInfo; 371 | 372 | /************************************************************************ 373 | * ��ȡ������Ϣ 374 | ************************************************************************/ 375 | MRESULT ASFGetAge( 376 | MHandle hEngine, // [in] ����handle 377 | LPASF_AgeInfo ageInfo // [out] ��⵽��������Ϣ 378 | ); 379 | 380 | //******************************** �Ա���� ********************************************** 381 | typedef struct GenderInfo { 382 | MInt32* genderArray; // "0" ��ʾ ����, "1" ��ʾ Ů��, "-1" ��ʾ��ȷ�� 383 | MInt32 num; // ������������ 384 | }ASF_GenderInfo, *LPASF_GenderInfo; 385 | 386 | /************************************************************************ 387 | * ��ȡ�Ա���Ϣ 388 | ************************************************************************/ 389 | MRESULT ASFGetGender( 390 | MHandle hEngine, // [in] ����handle 391 | LPASF_GenderInfo genderInfo // [out] ��⵽���Ա���Ϣ 392 | ); 393 | 394 | //******************************** ����3D �Ƕ���Ϣ *********************************** 395 | typedef struct Face3DAngle { 396 | MFloat* roll; 397 | MFloat* yaw; 398 | MFloat* pitch; 399 | MInt32* status; 400 | MInt32 num; 401 | }ASF_Face3DAngle, *LPASF_Face3DAngle; 402 | 403 | /************************************************************************ 404 | * ��ȡ3D�Ƕ���Ϣ 405 | ************************************************************************/ 406 | MRESULT ASFGetFace3DAngle( 407 | MHandle hEngine, // [in] ����handle 408 | LPASF_Face3DAngle p3DAngleInfo // [out] ��⵽����3D �Ƕ���Ϣ 409 | ); 410 | 411 | //******************************** ������Ϣ *********************************** 412 | typedef struct LivenessThreshold { 413 | MFloat thresholdmodel_BGR; 414 | MFloat thresholdmodel_IR; 415 | }ASF_LivenessThreshold, *LPASF_LivenessThreshold; 416 | 417 | /************************************************************************ 418 | * ȡֵ��Χ[0-1]��Ĭ��ֵ BGR:0.5 IR:0.7�� �û����Ը���ʵ���������ò�ͬ����ֵ 419 | ************************************************************************/ 420 | MRESULT ASFSetLivenessParam( 421 | MHandle hEngine, // [in] ����handle 422 | LPASF_LivenessThreshold threshold // [in] �������Ŷ� 423 | ); 424 | 425 | typedef struct LivenessInfo { 426 | MInt32* isLive; // [out] �ж��Ƿ����ˣ� 0�������ˣ� 427 | // 1�����ˣ� 428 | // -1����ȷ���� 429 | // -2:����������>1�� 430 | // -3: ������С 431 | // -4: �Ƕȹ��� 432 | // -5: ���������߽� 433 | // -6: ���ͼ���� 434 | // -7: ����ͼ̫���� 435 | MInt32 num; 436 | }ASF_LivenessInfo, *LPASF_LivenessInfo; 437 | 438 | /************************************************************************ 439 | * ��ȡRGB������ 440 | ************************************************************************/ 441 | MRESULT ASFGetLivenessScore( 442 | MHandle hEngine, // [in] ����handle 443 | LPASF_LivenessInfo livenessInfo // [out] ���RGB������ 444 | ); 445 | 446 | /************************************************************************ 447 | * ��ȡIR������ 448 | ************************************************************************/ 449 | MRESULT ASFGetLivenessScore_IR( 450 | MHandle hEngine, // [in] ����handle 451 | LPASF_LivenessInfo irLivenessInfo // [out] ��⵽IR������ 452 | ); 453 | 454 | //******************************** ���ּ����� ********************************************** 455 | typedef struct MaskInfo 456 | { 457 | MInt32* maskArray; // "0" ����û�д����֣�"1"���������� ,"-1"����ȷ�� 458 | MInt32 num; // ������������ 459 | }ASF_MaskInfo, *LPASF_MaskInfo; 460 | 461 | /************************************************************************ 462 | * ��ȡ���ּ��Ľ�� 463 | ************************************************************************/ 464 | MRESULT ASFGetMask( 465 | MHandle hEngine, // [in] ����handle 466 | LPASF_MaskInfo maskInfo // [out] ��⵽�Ŀ��ּ����� 467 | ); 468 | 469 | //******************************** ��ͷ��������� ********************************************** 470 | 471 | #define LANDMARKS_NUM 4 //��������� 472 | 473 | typedef struct 474 | { 475 | MFloat x; 476 | MFloat y; 477 | }ASF_FaceLandmark, *LPASF_FaceLandmark; 478 | 479 | typedef struct LandMarkInfo 480 | { 481 | ASF_FaceLandmark *point; //��ͷ��λ 482 | MInt32 num; //�������� 483 | }ASF_LandMarkInfo, *LPASF_LandMarkInfo; 484 | 485 | /************************************************************************ 486 | * ��ȡ��ͷ������������ǰֻ֧��0, 90, 180, 270�ȽǼ�⣩ 487 | ************************************************************************/ 488 | MRESULT ASFGetFaceLandMark( 489 | MHandle engine, // [in] ����handle 490 | LPASF_LandMarkInfo LandMarkInfo // [out]������ͷ�����飬ÿ��������ͷ����ͨ���ĸ����ʾ 491 | ); 492 | 493 | /************************************************************************ 494 | * �������� 495 | ************************************************************************/ 496 | MRESULT ASFUninitEngine( 497 | MHandle hEngine 498 | ); 499 | 500 | /************************************************************************ 501 | * ��ȡ�汾��Ϣ 502 | ************************************************************************/ 503 | const ASF_VERSION ASFGetVersion(); 504 | 505 | #ifdef __cplusplus 506 | } 507 | #endif 508 | #endif -------------------------------------------------------------------------------- /include/asvloffscreen.h: -------------------------------------------------------------------------------- 1 | #ifndef __ASVL_OFFSCREEN_H__ 2 | #define __ASVL_OFFSCREEN_H__ 3 | 4 | #include "amcomdef.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | 11 | /*31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 */ 12 | 13 | 14 | /* R R R R R G G G G G G B B B B B */ 15 | #define ASVL_PAF_RGB16_B5G6R5 0x101 16 | /* X R R R R R G G G G G B B B B B */ 17 | #define ASVL_PAF_RGB16_B5G5R5 0x102 18 | /* X X X X R R R R G G G G B B B B */ 19 | #define ASVL_PAF_RGB16_B4G4R4 0x103 20 | /* T R R R R R G G G G G B B B B B */ 21 | #define ASVL_PAF_RGB16_B5G5R5T 0x104 22 | /* B B B B B G G G G G G R R R R R */ 23 | #define ASVL_PAF_RGB16_R5G6B5 0x105 24 | /* X B B B B B G G G G G R R R R R */ 25 | #define ASVL_PAF_RGB16_R5G5B5 0x106 26 | /* X X X X B B B B G G G G R R R R */ 27 | #define ASVL_PAF_RGB16_R4G4B4 0x107 28 | 29 | 30 | /* R R R R R R R R G G G G G G G G B B B B B B B B */ 31 | #define ASVL_PAF_RGB24_B8G8R8 0x201 32 | /* X X X X X X R R R R R R G G G G G G B B B B B B */ 33 | #define ASVL_PAF_RGB24_B6G6R6 0x202 34 | /* X X X X X T R R R R R R G G G G G G B B B B B B */ 35 | #define ASVL_PAF_RGB24_B6G6R6T 0x203 36 | /* B B B B B B B B G G G G G G G G R R R R R R R R */ 37 | #define ASVL_PAF_RGB24_R8G8B8 0x204 38 | /* X X X X X X B B B B B B G G G G G G R R R R R R */ 39 | #define ASVL_PAF_RGB24_R6G6B6 0x205 40 | 41 | /* X X X X X X X X R R R R R R R R G G G G G G G G B B B B B B B B */ 42 | #define ASVL_PAF_RGB32_B8G8R8 0x301 43 | /* A A A A A A A A R R R R R R R R G G G G G G G G B B B B B B B B */ 44 | #define ASVL_PAF_RGB32_B8G8R8A8 0x302 45 | /* X X X X X X X X B B B B B B B B G G G G G G G G R R R R R R R R */ 46 | #define ASVL_PAF_RGB32_R8G8B8 0x303 47 | /* B B B B B B B B G G G G G G G G R R R R R R R R A A A A A A A A */ 48 | #define ASVL_PAF_RGB32_A8R8G8B8 0x304 49 | /* A A A A A A A A B B B B B B B B G G G G G G G G R R R R R R R R */ 50 | #define ASVL_PAF_RGB32_R8G8B8A8 0x305 51 | 52 | /*Y0, U0, V0*/ 53 | #define ASVL_PAF_YUV 0x401 54 | /*Y0, V0, U0*/ 55 | #define ASVL_PAF_YVU 0x402 56 | /*U0, V0, Y0*/ 57 | #define ASVL_PAF_UVY 0x403 58 | /*V0, U0, Y0*/ 59 | #define ASVL_PAF_VUY 0x404 60 | 61 | /*Y0, U0, Y1, V0*/ 62 | #define ASVL_PAF_YUYV 0x501 63 | /*Y0, V0, Y1, U0*/ 64 | #define ASVL_PAF_YVYU 0x502 65 | /*U0, Y0, V0, Y1*/ 66 | #define ASVL_PAF_UYVY 0x503 67 | /*V0, Y0, U0, Y1*/ 68 | #define ASVL_PAF_VYUY 0x504 69 | /*Y1, U0, Y0, V0*/ 70 | #define ASVL_PAF_YUYV2 0x505 71 | /*Y1, V0, Y0, U0*/ 72 | #define ASVL_PAF_YVYU2 0x506 73 | /*U0, Y1, V0, Y0*/ 74 | #define ASVL_PAF_UYVY2 0x507 75 | /*V0, Y1, U0, Y0*/ 76 | #define ASVL_PAF_VYUY2 0x508 77 | /*Y0, Y1, U0, V0*/ 78 | #define ASVL_PAF_YYUV 0x509 79 | 80 | /*8 bit Y plane followed by 8 bit 2x2 subsampled U and V planes*/ 81 | #define ASVL_PAF_I420 0x601 82 | /*8 bit Y plane followed by 8 bit 1x2 subsampled U and V planes*/ 83 | #define ASVL_PAF_I422V 0x602 84 | /*8 bit Y plane followed by 8 bit 2x1 subsampled U and V planes*/ 85 | #define ASVL_PAF_I422H 0x603 86 | /*8 bit Y plane followed by 8 bit U and V planes*/ 87 | #define ASVL_PAF_I444 0x604 88 | /*8 bit Y plane followed by 8 bit 2x2 subsampled V and U planes*/ 89 | #define ASVL_PAF_YV12 0x605 90 | /*8 bit Y plane followed by 8 bit 1x2 subsampled V and U planes*/ 91 | #define ASVL_PAF_YV16V 0x606 92 | /*8 bit Y plane followed by 8 bit 2x1 subsampled V and U planes*/ 93 | #define ASVL_PAF_YV16H 0x607 94 | /*8 bit Y plane followed by 8 bit V and U planes*/ 95 | #define ASVL_PAF_YV24 0x608 96 | /*8 bit Y plane only*/ 97 | #define ASVL_PAF_GRAY 0x701 98 | 99 | 100 | /*8 bit Y plane followed by 8 bit 2x2 subsampled UV planes*/ 101 | #define ASVL_PAF_NV12 0x801 102 | /*8 bit Y plane followed by 8 bit 2x2 subsampled VU planes*/ 103 | #define ASVL_PAF_NV21 0x802 104 | /*8 bit Y plane followed by 8 bit 2x1 subsampled UV planes*/ 105 | #define ASVL_PAF_LPI422H 0x803 106 | /*8 bit Y plane followed by 8 bit 2x1 subsampled VU planes*/ 107 | #define ASVL_PAF_LPI422H2 0x804 108 | 109 | /*8 bit Y plane followed by 8 bit 4x4 subsampled VU planes*/ 110 | #define ASVL_PAF_NV41 0x805 111 | 112 | /*Negative UYVY, U0, Y0, V0, Y1*/ 113 | #define ASVL_PAF_NEG_UYVY 0x901 114 | /*Negative I420, 8 bit Y plane followed by 8 bit 2x2 subsampled U and V planes*/ 115 | #define ASVL_PAF_NEG_I420 0x902 116 | 117 | 118 | /*Mono UYVY, UV values are fixed, gray image in U0, Y0, V0, Y1*/ 119 | #define ASVL_PAF_MONO_UYVY 0xa01 120 | /*Mono I420, UV values are fixed, 8 bit Y plane followed by 8 bit 2x2 subsampled U and V planes*/ 121 | #define ASVL_PAF_MONO_I420 0xa02 122 | 123 | /*P8_YUYV, 8 pixels a group, Y0Y1Y2Y3Y4Y5Y6Y7U0U1U2U3V0V1V2V3*/ 124 | #define ASVL_PAF_P8_YUYV 0xb03 125 | 126 | /*P16_YUYV, 16*16 pixels a group, Y0Y1Y2Y3...U0U1...V0V1...*/ 127 | #define ASVL_PAF_SP16UNIT 0xc01 128 | 129 | #define ASVL_PAF_DEPTH_U16 0xc02 130 | 131 | /*10 bits RGGB CFA raw data, each data has 2 bytes*/ 132 | 133 | 134 | #define ASVL_PAF_RAW10_RGGB_10B 0xd01 135 | #define ASVL_PAF_RAW10_GRBG_10B 0xd02 136 | #define ASVL_PAF_RAW10_GBRG_10B 0xd03 137 | #define ASVL_PAF_RAW10_BGGR_10B 0xd04 138 | 139 | #define ASVL_PAF_RAW12_RGGB_12B 0xd05 140 | #define ASVL_PAF_RAW12_GRBG_12B 0xd06 141 | #define ASVL_PAF_RAW12_GBRG_12B 0xd07 142 | #define ASVL_PAF_RAW12_BGGR_12B 0xd08 143 | 144 | #define ASVL_PAF_RAW10_RGGB_16B 0xd09 145 | #define ASVL_PAF_RAW10_GRBG_16B 0xd0A 146 | #define ASVL_PAF_RAW10_GBRG_16B 0xd0B 147 | #define ASVL_PAF_RAW10_BGGR_16B 0xd0C 148 | 149 | /*10 bits gray raw data*/ 150 | #define ASVL_PAF_RAW10_GRAY_10B 0xe01 151 | 152 | /*10 bits gray raw data, each data has 2 bytes*/ 153 | #define ASVL_PAF_RAW10_GRAY_16B 0xe81 154 | 155 | 156 | /*Define the image format space*/ 157 | typedef struct __tag_ASVL_OFFSCREEN 158 | { 159 | MUInt32 u32PixelArrayFormat; 160 | MInt32 i32Width; 161 | MInt32 i32Height; 162 | MUInt8* ppu8Plane[4]; 163 | MInt32 pi32Pitch[4]; 164 | }ASVLOFFSCREEN, *LPASVLOFFSCREEN; 165 | 166 | /*Define the SDK Version infos. This is the template!!!*/ 167 | typedef struct __tag_ASVL_VERSION 168 | { 169 | MLong lCodebase; // Codebase version number 170 | MLong lMajor; // major version number 171 | MLong lMinor; // minor version number 172 | MLong lBuild; // Build version number, increasable only 173 | const MChar *Version; // version in string form 174 | const MChar *BuildDate; // latest build Date 175 | const MChar *CopyRight; // copyright 176 | }ASVL_VERSION; 177 | const ASVL_VERSION *ASVL_GetVersion(); 178 | 179 | #ifdef __cplusplus 180 | } 181 | #endif 182 | 183 | #endif /*__ASVL_OFFSCREEN_H__*/ 184 | -------------------------------------------------------------------------------- /include/merror.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------------------------- 2 | * 3 | * This file is ArcSoft's property. It contains ArcSoft's trade secret, proprietary and 4 | * confidential information. 5 | * 6 | * The information and code contained in this file is only for authorized ArcSoft employees 7 | * to design, create, modify, or review. 8 | * 9 | * DO NOT DISTRIBUTE, DO NOT DUPLICATE OR TRANSMIT IN ANY FORM WITHOUT PROPER AUTHORIZATION. 10 | * 11 | * If you are not an intended recipient of this file, you must not copy, distribute, modify, 12 | * or take any action in reliance on it. 13 | * 14 | * If you have received this file in error, please immediately notify ArcSoft and 15 | * permanently delete the original and any copy of any file and any printout thereof. 16 | * 17 | *-------------------------------------------------------------------------------------------------*/ 18 | 19 | 20 | #ifndef __MERROR_H__ 21 | #define __MERROR_H__ 22 | 23 | 24 | #define MERR_NONE (0) 25 | #define MOK (0) 26 | 27 | #define MERR_BASIC_BASE 0X0001 //通用错误类型 28 | #define MERR_UNKNOWN MERR_BASIC_BASE //错误原因不明 29 | #define MERR_INVALID_PARAM (MERR_BASIC_BASE+1) //无效的参数 30 | #define MERR_UNSUPPORTED (MERR_BASIC_BASE+2) //引擎不支持 31 | #define MERR_NO_MEMORY (MERR_BASIC_BASE+3) //内存不足 32 | #define MERR_BAD_STATE (MERR_BASIC_BASE+4) //状态错误 33 | #define MERR_USER_CANCEL (MERR_BASIC_BASE+5) //用户取消相关操作 34 | #define MERR_EXPIRED (MERR_BASIC_BASE+6) //操作时间过期 35 | #define MERR_USER_PAUSE (MERR_BASIC_BASE+7) //用户暂停操作 36 | #define MERR_BUFFER_OVERFLOW (MERR_BASIC_BASE+8) //缓冲上溢 37 | #define MERR_BUFFER_UNDERFLOW (MERR_BASIC_BASE+9) //缓冲下溢 38 | #define MERR_NO_DISKSPACE (MERR_BASIC_BASE+10) //存贮空间不足 39 | #define MERR_COMPONENT_NOT_EXIST (MERR_BASIC_BASE+11) //组件不存在 40 | #define MERR_GLOBAL_DATA_NOT_EXIST (MERR_BASIC_BASE+12) //全局数据不存在 41 | 42 | #define MERR_FSDK_BASE 0X7000 //Free SDK通用错误类型 43 | #define MERR_FSDK_INVALID_APP_ID (MERR_FSDK_BASE+1) //无效的App Id 44 | #define MERR_FSDK_INVALID_SDK_ID (MERR_FSDK_BASE+2) //无效的SDK key 45 | #define MERR_FSDK_INVALID_ID_PAIR (MERR_FSDK_BASE+3) //AppId和SDKKey不匹配 46 | #define MERR_FSDK_MISMATCH_ID_AND_SDK (MERR_FSDK_BASE+4) //SDKKey 和使用的SDK 不匹配 47 | #define MERR_FSDK_SYSTEM_VERSION_UNSUPPORTED (MERR_FSDK_BASE+5) //系统版本不被当前SDK所支持 48 | #define MERR_FSDK_LICENCE_EXPIRED (MERR_FSDK_BASE+6) //SDK有效期过期,需要重新下载更新 49 | 50 | #define MERR_FSDK_APS_ERROR_BASE 0x11000 //PhotoStyling 错误类型 51 | #define MERR_FSDK_APS_ENGINE_HANDLE (MERR_FSDK_APS_ERROR_BASE+1) //引擎句柄非法 52 | #define MERR_FSDK_APS_MEMMGR_HANDLE (MERR_FSDK_APS_ERROR_BASE+2) //内存句柄非法 53 | #define MERR_FSDK_APS_DEVICEID_INVALID (MERR_FSDK_APS_ERROR_BASE+3) //Device ID 非法 54 | #define MERR_FSDK_APS_DEVICEID_UNSUPPORTED (MERR_FSDK_APS_ERROR_BASE+4) //Device ID 不支持 55 | #define MERR_FSDK_APS_MODEL_HANDLE (MERR_FSDK_APS_ERROR_BASE+5) //模板数据指针非法 56 | #define MERR_FSDK_APS_MODEL_SIZE (MERR_FSDK_APS_ERROR_BASE+6) //模板数据长度非法 57 | #define MERR_FSDK_APS_IMAGE_HANDLE (MERR_FSDK_APS_ERROR_BASE+7) //图像结构体指针非法 58 | #define MERR_FSDK_APS_IMAGE_FORMAT_UNSUPPORTED (MERR_FSDK_APS_ERROR_BASE+8) //图像格式不支持 59 | #define MERR_FSDK_APS_IMAGE_PARAM (MERR_FSDK_APS_ERROR_BASE+9) //图像参数非法 60 | #define MERR_FSDK_APS_IMAGE_SIZE (MERR_FSDK_APS_ERROR_BASE+10) //图像尺寸大小超过支持范围 61 | #define MERR_FSDK_APS_DEVICE_AVX2_UNSUPPORTED (MERR_FSDK_APS_ERROR_BASE+11) //处理器不支持AVX2指令 62 | 63 | #define MERR_FSDK_FR_ERROR_BASE 0x12000 //Face Recognition错误类型 64 | #define MERR_FSDK_FR_INVALID_MEMORY_INFO (MERR_FSDK_FR_ERROR_BASE+1) //无效的输入内存 65 | #define MERR_FSDK_FR_INVALID_IMAGE_INFO (MERR_FSDK_FR_ERROR_BASE+2) //无效的输入图像参数 66 | #define MERR_FSDK_FR_INVALID_FACE_INFO (MERR_FSDK_FR_ERROR_BASE+3) //无效的脸部信息 67 | #define MERR_FSDK_FR_NO_GPU_AVAILABLE (MERR_FSDK_FR_ERROR_BASE+4) //当前设备无GPU可用 68 | #define MERR_FSDK_FR_MISMATCHED_FEATURE_LEVEL (MERR_FSDK_FR_ERROR_BASE+5) //待比较的两个人脸特征的版本不一致 69 | 70 | #define MERR_FSDK_FACEFEATURE_ERROR_BASE 0x14000 //人脸特征检测错误类型 71 | #define MERR_FSDK_FACEFEATURE_UNKNOWN (MERR_FSDK_FACEFEATURE_ERROR_BASE+1) //人脸特征检测错误未知 72 | #define MERR_FSDK_FACEFEATURE_MEMORY (MERR_FSDK_FACEFEATURE_ERROR_BASE+2) //人脸特征检测内存错误 73 | #define MERR_FSDK_FACEFEATURE_INVALID_FORMAT (MERR_FSDK_FACEFEATURE_ERROR_BASE+3) //人脸特征检测格式错误 74 | #define MERR_FSDK_FACEFEATURE_INVALID_PARAM (MERR_FSDK_FACEFEATURE_ERROR_BASE+4) //人脸特征检测参数错误 75 | #define MERR_FSDK_FACEFEATURE_LOW_CONFIDENCE_LEVEL (MERR_FSDK_FACEFEATURE_ERROR_BASE+5) //人脸特征检测结果置信度低 76 | #define MERR_FSDK_FACEFEATURE_EXPIRED (MERR_FSDK_FACEFEATURE_ERROR_BASE+6) //人脸特征检测结果操作过期 77 | #define MERR_FSDK_FACEFEATURE_MISSFACE (MERR_FSDK_FACEFEATURE_ERROR_BASE+7) //人脸特征检测人脸丢失 78 | #define MERR_FSDK_FACEFEATURE_NO_FACE (MERR_FSDK_FACEFEATURE_ERROR_BASE+8) //人脸特征检测没有人脸 79 | #define MERR_FSDK_FACEFEATURE_FACEDATE (MERR_FSDK_FACEFEATURE_ERROR_BASE+9) //人脸特征检测人脸信息错误 80 | 81 | #define MERR_ASF_EX_BASE 0x15000 //ASF错误类型 82 | #define MERR_ASF_EX_FEATURE_UNSUPPORTED_ON_INIT (MERR_ASF_EX_BASE+1) //Engine不支持的检测属性 83 | #define MERR_ASF_EX_FEATURE_UNINITED (MERR_ASF_EX_BASE+2) //需要检测的属性未初始化 84 | #define MERR_ASF_EX_FEATURE_UNPROCESSED (MERR_ASF_EX_BASE+3) //待获取的属性未在process中处理过 85 | #define MERR_ASF_EX_FEATURE_UNSUPPORTED_ON_PROCESS (MERR_ASF_EX_BASE+4) //PROCESS不支持的检测属性组合,例如FR,有自己独立的处理函数 86 | #define MERR_ASF_EX_INVALID_IMAGE_INFO (MERR_ASF_EX_BASE+5) //无效的输入图像 87 | #define MERR_ASF_EX_INVALID_FACE_INFO (MERR_ASF_EX_BASE+6) //无效的脸部信息 88 | 89 | 90 | #define MERR_ASF_BASE 0x16000 //人脸比对基础错误类型 91 | #define MERR_ASF_ACTIVATION_FAIL (MERR_ASF_BASE+1) //SDK激活失败,请打开读写权限 92 | #define MERR_ASF_ALREADY_ACTIVATED (MERR_ASF_BASE+2) //SDK已激活 93 | #define MERR_ASF_NOT_ACTIVATED (MERR_ASF_BASE+3) //SDK未激活 94 | #define MERR_ASF_SCALE_NOT_SUPPORT (MERR_ASF_BASE+4) //detectFaceScaleVal 不支持 95 | #define MERR_ASF_ACTIVEFILE_SDKTYPE_MISMATCH (MERR_ASF_BASE+5) //激活文件与SDK类型不匹配,请确认使用的sdk 96 | #define MERR_ASF_DEVICE_MISMATCH (MERR_ASF_BASE+6) //设备不匹配 97 | #define MERR_ASF_UNIQUE_IDENTIFIER_ILLEGAL (MERR_ASF_BASE+7) //唯一标识不合法 98 | #define MERR_ASF_PARAM_NULL (MERR_ASF_BASE+8) //参数为空 99 | #define MERR_ASF_LIVENESS_EXPIRED (MERR_ASF_BASE+9) //活体已过期 100 | #define MERR_ASF_VERSION_NOT_SUPPORT (MERR_ASF_BASE+10) //版本不支持 101 | #define MERR_ASF_SIGN_ERROR (MERR_ASF_BASE+11) //签名错误 102 | #define MERR_ASF_DATABASE_ERROR (MERR_ASF_BASE+12) //激活信息保存异常 103 | #define MERR_ASF_UNIQUE_CHECKOUT_FAIL (MERR_ASF_BASE+13) //唯一标识符校验失败 104 | #define MERR_ASF_COLOR_SPACE_NOT_SUPPORT (MERR_ASF_BASE+14) //颜色空间不支持 105 | #define MERR_ASF_IMAGE_WIDTH_HEIGHT_NOT_SUPPORT (MERR_ASF_BASE+15) //图片宽高不支持,宽度需四字节对齐 106 | 107 | #define MERR_ASF_BASE_EXTEND 0x16010 //人脸比对基础错误类型 108 | #define MERR_ASF_READ_PHONE_STATE_DENIED (MERR_ASF_BASE_EXTEND) //android.permission.READ_PHONE_STATE权限被拒绝 109 | #define MERR_ASF_ACTIVATION_DATA_DESTROYED (MERR_ASF_BASE_EXTEND+1) //激活数据被破坏,请删除激活文件,重新进行激活 110 | #define MERR_ASF_SERVER_UNKNOWN_ERROR (MERR_ASF_BASE_EXTEND+2) //服务端未知错误 111 | #define MERR_ASF_INTERNET_DENIED (MERR_ASF_BASE_EXTEND+3) //INTERNET权限被拒绝 112 | #define MERR_ASF_ACTIVEFILE_SDK_MISMATCH (MERR_ASF_BASE_EXTEND+4) //激活文件与SDK版本不匹配,请重新激活 113 | #define MERR_ASF_DEVICEINFO_LESS (MERR_ASF_BASE_EXTEND+5) //设备信息太少,不足以生成设备指纹 114 | #define MERR_ASF_LOCAL_TIME_NOT_CALIBRATED (MERR_ASF_BASE_EXTEND+6) //客户端时间与服务器时间(即北京时间)前后相差在30分钟以上 115 | #define MERR_ASF_APPID_DATA_DECRYPT (MERR_ASF_BASE_EXTEND+7) //数据校验异常 116 | #define MERR_ASF_APPID_APPKEY_SDK_MISMATCH (MERR_ASF_BASE_EXTEND+8) //传入的AppId和AppKey与使用的SDK版本不一致 117 | #define MERR_ASF_NO_REQUEST (MERR_ASF_BASE_EXTEND+9) //短时间大量请求会被禁止请求,30分钟之后解封 118 | #define MERR_ASF_ACTIVE_FILE_NO_EXIST (MERR_ASF_BASE_EXTEND+10) //激活文件不存在 119 | #define MERR_ASF_DETECT_MODEL_UNSUPPORTED (MERR_ASF_BASE_EXTEND+11) //检测模型不支持,请查看对应接口说明,使用当前支持的检测模型 120 | #define MERR_ASF_CURRENT_DEVICE_TIME_INCORRECT (MERR_ASF_BASE_EXTEND+12) //当前设备时间不正确,请调整设备时间 121 | #define MERR_ASF_ACTIVATION_QUANTITY_OUT_OF_LIMIT (MERR_ASF_BASE_EXTEND+13) //年度激活数量超出限制,次年清零 122 | 123 | #define MERR_ASF_NETWORK_BASE 0x17000 //网络错误类型 124 | #define MERR_ASF_NETWORK_COULDNT_RESOLVE_HOST (MERR_ASF_NETWORK_BASE+1) //无法解析主机地址 125 | #define MERR_ASF_NETWORK_COULDNT_CONNECT_SERVER (MERR_ASF_NETWORK_BASE+2) //无法连接服务器 126 | #define MERR_ASF_NETWORK_CONNECT_TIMEOUT (MERR_ASF_NETWORK_BASE+3) //网络连接超时 127 | #define MERR_ASF_NETWORK_UNKNOWN_ERROR (MERR_ASF_NETWORK_BASE+4) //网络未知错误 128 | 129 | #define MERR_ASF_ACTIVEKEY_BASE 0x18000 //激活码错误类型 130 | #define MERR_ASF_ACTIVEKEY_COULDNT_CONNECT_SERVER (MERR_ASF_ACTIVEKEY_BASE+1) //无法连接激活服务器 131 | #define MERR_ASF_ACTIVEKEY_SERVER_SYSTEM_ERROR (MERR_ASF_ACTIVEKEY_BASE+2) //服务器系统错误 132 | #define MERR_ASF_ACTIVEKEY_POST_PARM_ERROR (MERR_ASF_ACTIVEKEY_BASE+3) //请求参数错误 133 | #define MERR_ASF_ACTIVEKEY_PARM_MISMATCH (MERR_ASF_ACTIVEKEY_BASE+4) //ACTIVEKEY与APPID、SDKKEY不匹配 134 | #define MERR_ASF_ACTIVEKEY_ACTIVEKEY_ACTIVATED (MERR_ASF_ACTIVEKEY_BASE+5) //ACTIVEKEY已经被使用 135 | #define MERR_ASF_ACTIVEKEY_ACTIVEKEY_FORMAT_ERROR (MERR_ASF_ACTIVEKEY_BASE+6) //ACTIVEKEY信息异常 136 | #define MERR_ASF_ACTIVEKEY_APPID_PARM_MISMATCH (MERR_ASF_ACTIVEKEY_BASE+7) //ACTIVEKEY与APPID不匹配 137 | #define MERR_ASF_ACTIVEKEY_SDK_FILE_MISMATCH (MERR_ASF_ACTIVEKEY_BASE+8) //SDK与激活文件版本不匹配 138 | #define MERR_ASF_ACTIVEKEY_EXPIRED (MERR_ASF_ACTIVEKEY_BASE+9) //ACTIVEKEY已过期 139 | #define MERR_ASF_ACTIVEKEY_DEVICE_OUT_OF_LIMIT (MERR_ASF_ACTIVEKEY_BASE+10) //批量授权激活码设备数超过限制 140 | 141 | 142 | #define MERR_ASF_OFFLINE_BASE 0x19000 //离线激活错误码类型 143 | #define MERR_ASF_LICENSE_FILE_NOT_EXIST (MERR_ASF_OFFLINE_BASE+1) //离线授权文件不存在或无读写权限 144 | #define MERR_ASF_LICENSE_FILE_DATA_DESTROYED (MERR_ASF_OFFLINE_BASE+2) //离线授权文件已损坏 145 | #define MERR_ASF_LICENSE_FILE_SDK_MISMATCH (MERR_ASF_OFFLINE_BASE+3) //离线授权文件与SDK版本不匹配 146 | #define MERR_ASF_LICENSE_FILEINFO_SDKINFO_MISMATCH (MERR_ASF_OFFLINE_BASE+4) //离线授权文件与SDK信息不匹配 147 | #define MERR_ASF_LICENSE_FILE_FINGERPRINT_MISMATCH (MERR_ASF_OFFLINE_BASE+5) //离线授权文件与设备指纹不匹配 148 | #define MERR_ASF_LICENSE_FILE_EXPIRED (MERR_ASF_OFFLINE_BASE+6) //离线授权文件已过期 149 | #define MERR_ASF_LOCAL_EXIST_USEFUL_ACTIVE_FILE (MERR_ASF_OFFLINE_BASE+7) //离线授权文件不可用,本地原有激活文件可继续使用 150 | #define MERR_ASF_LICENSE_FILE_VERSION_TOO_LOW (MERR_ASF_OFFLINE_BASE+8) //离线授权文件版本过低,请使用新版本激活助手重新进行离线激活 151 | 152 | 153 | #endif 154 | 155 | -------------------------------------------------------------------------------- /mask.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/windosx/face-engine/06a226024b8523e9d2b5896048688e01d4597cfc/mask.jpg -------------------------------------------------------------------------------- /util/image_util.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "os" 7 | "runtime" 8 | 9 | _ "image/jpeg" 10 | _ "image/png" 11 | 12 | "image" 13 | "image/color" 14 | ) 15 | 16 | type resamplingFilter struct { 17 | Support float64 18 | Kernel func(float64) float64 19 | } 20 | 21 | // GetImageHeight 获取图片高度 22 | func GetImageHeight(img image.Image) int { 23 | return img.Bounds().Max.Y 24 | } 25 | 26 | // GetImageWidth 获取图片宽度 27 | func GetImageWidth(img image.Image) int { 28 | return img.Bounds().Max.X 29 | } 30 | 31 | // DecodeImage decode a image and retrun golang image interface 32 | func DecodeImage(filePath string) (img image.Image, err error) { 33 | reader, err := os.Open(filePath) 34 | if err != nil { 35 | return nil, err 36 | } 37 | defer reader.Close() 38 | 39 | img, _, err = image.Decode(reader) 40 | 41 | return 42 | } 43 | 44 | // NewRGBAMatrix create a new rgba matrix 45 | func NewRGBAMatrix(height int, width int) (rgbaMatrix [][][]uint8) { 46 | rgbaMatrix = New3DSlice(height, width, 4) 47 | return 48 | } 49 | 50 | // ImageInfo 包含图片数据和宽高信息的结构体 51 | type ImageInfo struct { 52 | DataUInt8 []uint8 53 | Width int 54 | Height int 55 | } 56 | 57 | // GetResizedImageInfo 获取适配SDK大小的图片,并转为BGR格式的数据 58 | func GetResizedImageInfo(filename string) (imageInfo ImageInfo) { 59 | img, err := DecodeImage(filename) 60 | if err != nil { 61 | fmt.Printf("%v\n", err) 62 | } 63 | height := GetImageHeight(img) 64 | width := GetImageWidth(img) 65 | newWidth := width - width%4 66 | imgMatrix, err := ResizeForMatrix(filename, newWidth, height) 67 | if err != nil { 68 | panic(err) 69 | } 70 | var bgrData []uint8 71 | for starty := 0; starty < height; starty++ { 72 | for startx := 0; startx < newWidth; startx++ { 73 | R := imgMatrix[starty][startx][0] 74 | G := imgMatrix[starty][startx][1] 75 | B := imgMatrix[starty][startx][2] 76 | bgrData = append(bgrData, B, G, R) 77 | } 78 | } 79 | return ImageInfo{bgrData, width, height} 80 | } 81 | 82 | // GetImageWidthAndHeight 获取图片宽高 83 | func GetImageWidthAndHeight(filename string) (width, height int) { 84 | img, err := DecodeImage(filename) 85 | if err != nil { 86 | return 0, 0 87 | } 88 | return GetImageWidth(img), GetImageHeight(img) 89 | } 90 | 91 | // ResizeForMatrix 缩放图片 92 | func ResizeForMatrix(filepath string, width int, height int) (imgMatrix [][][]uint8, err error) { 93 | img, err1 := DecodeImage(filepath) 94 | 95 | if err1 != nil { 96 | err = err1 97 | return 98 | } 99 | 100 | nrgba := convertToNRGBA(img) 101 | src := Resize(nrgba, width, height) 102 | 103 | imgMatrix = NewRGBAMatrix(height, width) 104 | 105 | for i := 0; i < height; i++ { 106 | for j := 0; j < width; j++ { 107 | c := src.At(j, i) 108 | r, g, b, a := c.RGBA() 109 | imgMatrix[i][j][0] = uint8(r) 110 | imgMatrix[i][j][1] = uint8(g) 111 | imgMatrix[i][j][2] = uint8(b) 112 | imgMatrix[i][j][3] = uint8(a) 113 | 114 | } 115 | } 116 | 117 | return 118 | } 119 | 120 | // Resize 缩放图片 121 | func Resize(src *image.NRGBA, width int, height int) *image.NRGBA { 122 | dstW, dstH := width, height 123 | 124 | if dstW < 0 || dstH < 0 { 125 | return src 126 | } 127 | if dstW == 0 && dstH == 0 { 128 | return src 129 | } 130 | 131 | srcW := src.Rect.Max.X 132 | srcH := src.Rect.Max.Y 133 | 134 | if srcW <= 0 || srcH <= 0 { 135 | return src 136 | } 137 | 138 | // if new width or height is 0 then preserve aspect ratio, minimum 1px 139 | if dstW == 0 { 140 | tmpW := float64(dstH) * float64(srcW) / float64(srcH) 141 | dstW = int(math.Max(1.0, math.Floor(tmpW+0.5))) 142 | } 143 | if dstH == 0 { 144 | tmpH := float64(dstW) * float64(srcH) / float64(srcW) 145 | dstH = int(math.Max(1.0, math.Floor(tmpH+0.5))) 146 | } 147 | 148 | var dst *image.NRGBA 149 | 150 | var sinc = func(x float64) float64 { 151 | if x == 0 { 152 | return 1 153 | } 154 | return math.Sin(math.Pi*x) / (math.Pi * x) 155 | } 156 | 157 | var filter resamplingFilter = resamplingFilter{ 158 | Support: 3.0, 159 | Kernel: func(x float64) float64 { 160 | x = math.Abs(x) 161 | if x < 3.0 { 162 | return sinc(x) * sinc(x/3.0) 163 | } 164 | return 0 165 | }, 166 | } 167 | 168 | if filter.Support <= 0.0 { 169 | // nearest-neighbor special case 170 | dst = resizeNearest(src, dstW, dstH) 171 | 172 | } else { 173 | // two-pass resize 174 | if srcW != dstW { 175 | dst = resizeHorizontal(src, dstW, filter) 176 | } else { 177 | dst = src 178 | } 179 | 180 | if srcH != dstH { 181 | dst = resizeVertical(dst, dstH, filter) 182 | } 183 | } 184 | 185 | return dst 186 | } 187 | 188 | //convert image to NRGBA 189 | func convertToNRGBA(src image.Image) *image.NRGBA { 190 | srcBounds := src.Bounds() 191 | dstBounds := srcBounds.Sub(srcBounds.Min) 192 | 193 | dst := image.NewNRGBA(dstBounds) 194 | 195 | dstMinX := dstBounds.Min.X 196 | dstMinY := dstBounds.Min.Y 197 | 198 | srcMinX := srcBounds.Min.X 199 | srcMinY := srcBounds.Min.Y 200 | srcMaxX := srcBounds.Max.X 201 | srcMaxY := srcBounds.Max.Y 202 | 203 | switch src0 := src.(type) { 204 | 205 | case *image.NRGBA: 206 | rowSize := srcBounds.Dx() * 4 207 | numRows := srcBounds.Dy() 208 | 209 | i0 := dst.PixOffset(dstMinX, dstMinY) 210 | j0 := src0.PixOffset(srcMinX, srcMinY) 211 | 212 | di := dst.Stride 213 | dj := src0.Stride 214 | 215 | for row := 0; row < numRows; row++ { 216 | copy(dst.Pix[i0:i0+rowSize], src0.Pix[j0:j0+rowSize]) 217 | i0 += di 218 | j0 += dj 219 | } 220 | 221 | case *image.NRGBA64: 222 | i0 := dst.PixOffset(dstMinX, dstMinY) 223 | for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride { 224 | for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 { 225 | 226 | j := src0.PixOffset(x, y) 227 | 228 | dst.Pix[i+0] = src0.Pix[j+0] 229 | dst.Pix[i+1] = src0.Pix[j+2] 230 | dst.Pix[i+2] = src0.Pix[j+4] 231 | dst.Pix[i+3] = src0.Pix[j+6] 232 | 233 | } 234 | } 235 | 236 | case *image.RGBA: 237 | i0 := dst.PixOffset(dstMinX, dstMinY) 238 | for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride { 239 | for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 { 240 | 241 | j := src0.PixOffset(x, y) 242 | a := src0.Pix[j+3] 243 | dst.Pix[i+3] = a 244 | 245 | switch a { 246 | case 0: 247 | dst.Pix[i+0] = 0 248 | dst.Pix[i+1] = 0 249 | dst.Pix[i+2] = 0 250 | case 0xff: 251 | dst.Pix[i+0] = src0.Pix[j+0] 252 | dst.Pix[i+1] = src0.Pix[j+1] 253 | dst.Pix[i+2] = src0.Pix[j+2] 254 | default: 255 | dst.Pix[i+0] = uint8(uint16(src0.Pix[j+0]) * 0xff / uint16(a)) 256 | dst.Pix[i+1] = uint8(uint16(src0.Pix[j+1]) * 0xff / uint16(a)) 257 | dst.Pix[i+2] = uint8(uint16(src0.Pix[j+2]) * 0xff / uint16(a)) 258 | } 259 | } 260 | } 261 | 262 | case *image.RGBA64: 263 | i0 := dst.PixOffset(dstMinX, dstMinY) 264 | for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride { 265 | for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 { 266 | 267 | j := src0.PixOffset(x, y) 268 | a := src0.Pix[j+6] 269 | dst.Pix[i+3] = a 270 | 271 | switch a { 272 | case 0: 273 | dst.Pix[i+0] = 0 274 | dst.Pix[i+1] = 0 275 | dst.Pix[i+2] = 0 276 | case 0xff: 277 | dst.Pix[i+0] = src0.Pix[j+0] 278 | dst.Pix[i+1] = src0.Pix[j+2] 279 | dst.Pix[i+2] = src0.Pix[j+4] 280 | default: 281 | dst.Pix[i+0] = uint8(uint16(src0.Pix[j+0]) * 0xff / uint16(a)) 282 | dst.Pix[i+1] = uint8(uint16(src0.Pix[j+2]) * 0xff / uint16(a)) 283 | dst.Pix[i+2] = uint8(uint16(src0.Pix[j+4]) * 0xff / uint16(a)) 284 | } 285 | } 286 | } 287 | 288 | case *image.Gray: 289 | i0 := dst.PixOffset(dstMinX, dstMinY) 290 | for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride { 291 | for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 { 292 | 293 | j := src0.PixOffset(x, y) 294 | c := src0.Pix[j] 295 | dst.Pix[i+0] = c 296 | dst.Pix[i+1] = c 297 | dst.Pix[i+2] = c 298 | dst.Pix[i+3] = 0xff 299 | 300 | } 301 | } 302 | 303 | case *image.Gray16: 304 | i0 := dst.PixOffset(dstMinX, dstMinY) 305 | for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride { 306 | for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 { 307 | 308 | j := src0.PixOffset(x, y) 309 | c := src0.Pix[j] 310 | dst.Pix[i+0] = c 311 | dst.Pix[i+1] = c 312 | dst.Pix[i+2] = c 313 | dst.Pix[i+3] = 0xff 314 | 315 | } 316 | } 317 | 318 | case *image.YCbCr: 319 | i0 := dst.PixOffset(dstMinX, dstMinY) 320 | for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride { 321 | for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 { 322 | 323 | yj := src0.YOffset(x, y) 324 | cj := src0.COffset(x, y) 325 | r, g, b := color.YCbCrToRGB(src0.Y[yj], src0.Cb[cj], src0.Cr[cj]) 326 | 327 | dst.Pix[i+0] = r 328 | dst.Pix[i+1] = g 329 | dst.Pix[i+2] = b 330 | dst.Pix[i+3] = 0xff 331 | 332 | } 333 | } 334 | 335 | default: 336 | i0 := dst.PixOffset(dstMinX, dstMinY) 337 | for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride { 338 | for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 { 339 | 340 | c := color.NRGBAModel.Convert(src.At(x, y)).(color.NRGBA) 341 | 342 | dst.Pix[i+0] = c.R 343 | dst.Pix[i+1] = c.G 344 | dst.Pix[i+2] = c.B 345 | dst.Pix[i+3] = c.A 346 | 347 | } 348 | } 349 | } 350 | 351 | return dst 352 | } 353 | 354 | func resizeHorizontal(src *image.NRGBA, width int, filter resamplingFilter) *image.NRGBA { 355 | srcBounds := src.Bounds() 356 | srcW := srcBounds.Dx() 357 | srcH := srcBounds.Dy() 358 | srcMinX := srcBounds.Min.X 359 | srcMinY := srcBounds.Min.Y 360 | srcMaxX := srcBounds.Max.X 361 | 362 | dstW := width 363 | dstH := srcH 364 | 365 | dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) 366 | 367 | dX := float64(srcW) / float64(dstW) 368 | scaleX := math.Max(dX, 1.0) 369 | rX := math.Ceil(scaleX * filter.Support) 370 | 371 | // divide image to parts for parallel processing 372 | numGoroutines := runtime.NumCPU() 373 | goMaxProcs := runtime.GOMAXPROCS(0) 374 | if numGoroutines > goMaxProcs { 375 | numGoroutines = goMaxProcs 376 | } 377 | if numGoroutines > dstW { 378 | numGoroutines = dstW 379 | } 380 | partSize := dstW / numGoroutines 381 | 382 | doneChan := make(chan bool, numGoroutines) 383 | 384 | for part := 0; part < numGoroutines; part++ { 385 | partStart := part * partSize 386 | partEnd := (part + 1) * partSize 387 | if part == numGoroutines-1 { 388 | partEnd = dstW 389 | } 390 | 391 | go func(partStart, partEnd int) { 392 | 393 | for dstX := partStart; dstX < partEnd; dstX++ { 394 | fX := float64(srcMinX) + (float64(dstX)+0.5)*dX - 0.5 395 | 396 | startX := int(math.Ceil(fX - rX)) 397 | if startX < srcMinX { 398 | startX = srcMinX 399 | } 400 | endX := int(math.Floor(fX + rX)) 401 | if endX > srcMaxX-1 { 402 | endX = srcMaxX - 1 403 | } 404 | 405 | // cache weights 406 | weightSum := 0.0 407 | weights := make([]float64, int(rX+2)*2) 408 | for x := startX; x <= endX; x++ { 409 | w := filter.Kernel((float64(x) - fX) / scaleX) 410 | weightSum += w 411 | weights[x-startX] = w 412 | } 413 | 414 | for dstY := 0; dstY < dstH; dstY++ { 415 | srcY := srcMinY + dstY 416 | 417 | r, g, b, a := 0.0, 0.0, 0.0, 0.0 418 | for x := startX; x <= endX; x++ { 419 | weight := weights[x-startX] 420 | i := src.PixOffset(x, srcY) 421 | r += float64(src.Pix[i+0]) * weight 422 | g += float64(src.Pix[i+1]) * weight 423 | b += float64(src.Pix[i+2]) * weight 424 | a += float64(src.Pix[i+3]) * weight 425 | } 426 | 427 | r = math.Min(math.Max(r/weightSum, 0.0), 255.0) 428 | g = math.Min(math.Max(g/weightSum, 0.0), 255.0) 429 | b = math.Min(math.Max(b/weightSum, 0.0), 255.0) 430 | a = math.Min(math.Max(a/weightSum, 0.0), 255.0) 431 | 432 | j := dst.PixOffset(dstX, dstY) 433 | dst.Pix[j+0] = uint8(r + 0.5) 434 | dst.Pix[j+1] = uint8(g + 0.5) 435 | dst.Pix[j+2] = uint8(b + 0.5) 436 | dst.Pix[j+3] = uint8(a + 0.5) 437 | } 438 | } 439 | 440 | doneChan <- true 441 | }(partStart, partEnd) 442 | 443 | } 444 | 445 | // wait for goroutines to finish 446 | for part := 0; part < numGoroutines; part++ { 447 | <-doneChan 448 | } 449 | 450 | return dst 451 | } 452 | 453 | func resizeVertical(src *image.NRGBA, height int, filter resamplingFilter) *image.NRGBA { 454 | srcBounds := src.Bounds() 455 | srcW := srcBounds.Dx() 456 | srcH := srcBounds.Dy() 457 | srcMinX := srcBounds.Min.X 458 | srcMinY := srcBounds.Min.Y 459 | srcMaxY := srcBounds.Max.Y 460 | 461 | dstW := srcW 462 | dstH := height 463 | 464 | dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) 465 | 466 | dY := float64(srcH) / float64(dstH) 467 | scaleY := math.Max(dY, 1.0) 468 | rY := math.Ceil(scaleY * filter.Support) 469 | 470 | // divide image to parts for parallel processing 471 | numGoroutines := runtime.NumCPU() 472 | goMaxProcs := runtime.GOMAXPROCS(0) 473 | if numGoroutines > goMaxProcs { 474 | numGoroutines = goMaxProcs 475 | } 476 | if numGoroutines > dstH { 477 | numGoroutines = dstH 478 | } 479 | partSize := dstH / numGoroutines 480 | 481 | doneChan := make(chan bool, numGoroutines) 482 | 483 | for part := 0; part < numGoroutines; part++ { 484 | partStart := part * partSize 485 | partEnd := (part + 1) * partSize 486 | if part == numGoroutines-1 { 487 | partEnd = dstH 488 | } 489 | 490 | go func(partStart, partEnd int) { 491 | 492 | for dstY := partStart; dstY < partEnd; dstY++ { 493 | fY := float64(srcMinY) + (float64(dstY)+0.5)*dY - 0.5 494 | 495 | startY := int(math.Ceil(fY - rY)) 496 | if startY < srcMinY { 497 | startY = srcMinY 498 | } 499 | endY := int(math.Floor(fY + rY)) 500 | if endY > srcMaxY-1 { 501 | endY = srcMaxY - 1 502 | } 503 | 504 | // cache weights 505 | weightSum := 0.0 506 | weights := make([]float64, int(rY+2)*2) 507 | for y := startY; y <= endY; y++ { 508 | w := filter.Kernel((float64(y) - fY) / scaleY) 509 | weightSum += w 510 | weights[y-startY] = w 511 | } 512 | 513 | for dstX := 0; dstX < dstW; dstX++ { 514 | srcX := srcMinX + dstX 515 | 516 | r, g, b, a := 0.0, 0.0, 0.0, 0.0 517 | for y := startY; y <= endY; y++ { 518 | weight := weights[y-startY] 519 | i := src.PixOffset(srcX, y) 520 | r += float64(src.Pix[i+0]) * weight 521 | g += float64(src.Pix[i+1]) * weight 522 | b += float64(src.Pix[i+2]) * weight 523 | a += float64(src.Pix[i+3]) * weight 524 | } 525 | 526 | r = math.Min(math.Max(r/weightSum, 0.0), 255.0) 527 | g = math.Min(math.Max(g/weightSum, 0.0), 255.0) 528 | b = math.Min(math.Max(b/weightSum, 0.0), 255.0) 529 | a = math.Min(math.Max(a/weightSum, 0.0), 255.0) 530 | 531 | j := dst.PixOffset(dstX, dstY) 532 | dst.Pix[j+0] = uint8(r + 0.5) 533 | dst.Pix[j+1] = uint8(g + 0.5) 534 | dst.Pix[j+2] = uint8(b + 0.5) 535 | dst.Pix[j+3] = uint8(a + 0.5) 536 | } 537 | } 538 | 539 | doneChan <- true 540 | }(partStart, partEnd) 541 | 542 | } 543 | 544 | // wait for goroutines to finish 545 | for part := 0; part < numGoroutines; part++ { 546 | <-doneChan 547 | } 548 | 549 | return dst 550 | } 551 | 552 | // fast nearest-neighbor resize, no filtering 553 | func resizeNearest(src *image.NRGBA, width, height int) *image.NRGBA { 554 | dstW, dstH := width, height 555 | 556 | srcBounds := src.Bounds() 557 | srcW := srcBounds.Dx() 558 | srcH := srcBounds.Dy() 559 | srcMinX := srcBounds.Min.X 560 | srcMinY := srcBounds.Min.Y 561 | srcMaxX := srcBounds.Max.X 562 | srcMaxY := srcBounds.Max.Y 563 | 564 | dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) 565 | 566 | dx := float64(srcW) / float64(dstW) 567 | dy := float64(srcH) / float64(dstH) 568 | 569 | // divide image to parts for parallel processing 570 | numGoroutines := runtime.NumCPU() 571 | goMaxProcs := runtime.GOMAXPROCS(0) 572 | if numGoroutines > goMaxProcs { 573 | numGoroutines = goMaxProcs 574 | } 575 | if numGoroutines > dstH { 576 | numGoroutines = dstH 577 | } 578 | partSize := dstH / numGoroutines 579 | 580 | doneChan := make(chan bool, numGoroutines) 581 | 582 | for part := 0; part < numGoroutines; part++ { 583 | partStart := part * partSize 584 | partEnd := (part + 1) * partSize 585 | if part == numGoroutines-1 { 586 | partEnd = dstH 587 | } 588 | 589 | go func(partStart, partEnd int) { 590 | 591 | for dstY := partStart; dstY < partEnd; dstY++ { 592 | fy := float64(srcMinY) + (float64(dstY)+0.5)*dy - 0.5 593 | 594 | for dstX := 0; dstX < dstW; dstX++ { 595 | fx := float64(srcMinX) + (float64(dstX)+0.5)*dx - 0.5 596 | 597 | srcX := int(math.Min(math.Max(math.Floor(fx+0.5), float64(srcMinX)), float64(srcMaxX))) 598 | srcY := int(math.Min(math.Max(math.Floor(fy+0.5), float64(srcMinY)), float64(srcMaxY))) 599 | 600 | srcOffset := src.PixOffset(srcX, srcY) 601 | dstOffset := dst.PixOffset(dstX, dstY) 602 | 603 | dst.Pix[dstOffset+0] = src.Pix[srcOffset+0] 604 | dst.Pix[dstOffset+1] = src.Pix[srcOffset+1] 605 | dst.Pix[dstOffset+2] = src.Pix[srcOffset+2] 606 | dst.Pix[dstOffset+3] = src.Pix[srcOffset+3] 607 | } 608 | } 609 | 610 | doneChan <- true 611 | }(partStart, partEnd) 612 | } 613 | 614 | // wait for goroutines to finish 615 | for part := 0; part < numGoroutines; part++ { 616 | <-doneChan 617 | } 618 | 619 | return dst 620 | } 621 | 622 | // New3DSlice 创建矩阵 623 | func New3DSlice(x int, y int, z int) (theSlice [][][]uint8) { 624 | theSlice = make([][][]uint8, x, x) 625 | for i := 0; i < x; i++ { 626 | s2 := make([][]uint8, y, y) 627 | for j := 0; j < y; j++ { 628 | s3 := make([]uint8, z, z) 629 | s2[j] = s3 630 | } 631 | theSlice[i] = s2 632 | } 633 | return 634 | } 635 | --------------------------------------------------------------------------------