diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..7f0a149 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.h linguist-language=Go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1b8d538 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +.idea/ +.vscode/ + +*.exe +*.test +*.prof + +*.dat +*.dll + +face-engine +go.sum \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..2d68ff3 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,15 @@ +language: go + +go: + - 1.15.x + +before_install: + - wget -O lib.zip https://github.com/windosx/face-engine/releases/download/v4.0.4/libarcsoft_linux_x64.zip + - unzip lib.zip -d ./arcsoftlib/ + - sudo cp ./arcsoftlib/libarcsoft_face.so /usr/lib + - sudo cp ./arcsoftlib/libarcsoft_face_engine.so /usr/lib + +script: + - go build -o test github.com/windosx/face-engine/v4/examples + - chmod +x test + - ./test diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f640ea4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,6 @@ +Copyright (C) 2021 WindOSX + +  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: +   +  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..0ebeaf6 --- /dev/null +++ b/README.md @@ -0,0 +1,131 @@ +# 虹软人脸检测SDK Go语言版 +![LICENSE](https://img.shields.io/github/license/windosx/face-engine) +![Supported platform](https://img.shields.io/badge/platform-win%20%7C%20linux-lightgrey) +[![Build Status](https://travis-ci.org/windosx/face-engine.svg?branch=master)](https://travis-ci.org/windosx/face-engine) +[![GoDoc](http://godoc.org/github.com/windosx/face-engine?status.svg)](http://godoc.org/github.com/windosx/face-engine) + +# 一、项目简介 + +由于公司是虹软的重度用户,出于工作需要和个人兴趣,寻思着用golang封装一下C++的SDK,利用golang的跨平台特性达到跨平台的效果(当然前提是SDK支持的平台) + +目前支持的SDK版本有:[v2.x](https://github.com/windosx/face-engine/tree/v2.2.0) [v3.x](https://github.com/windosx/face-engine/tree/v3.0.7) [v4.0.0](https://github.com/windosx/face-engine) + +# 二、编译环境与运行环境的准备 + +## 1. 安装go版本SDK +推荐使用go module的方式进行安装(需要哪个版本修改版本号即可): + +```bash +go get -u -d github.com/windosx/face-engine/v4 +``` +## 2. 安装gcc环境 +Linux下可以通过对应的包管理器进行安装,Windows下根据32/64位系统进行选择安装MinGW或者MinGW-w64 + +## 3. 运行环境 + - Linux:将`libarcsoft_face.so`、`libarcsoft_face_engine.so`放入`/usr/lib64`目录下 + - Windows:将`libarcsoft_face.dll`、`libarcsoft_face_engine.dll`放入MinGW安装目录下的lib目录中,同时需要将这两个文件放入`%WINDIR%`或者`%WINDIR/System32%`目录下 + +# 三、代码结构说明 +```bash +├─examples +│ └─example1.go +├─include +│ ├─amcomdef.h +│ └─arcsoft_face_sdk.h +│ └─asvloffscreen.h +│ └─merror.h +├─util +│ └─image_util.go +├─go.mod +├─engine.go +├─mask.jpg +├─test.jpg +examples目录中是示例代码 +include是SDK的头文件 +util下的image_util.go是使用golang原生API处理图片的工具 +engine.go是封装的SDK +两张JPEG格式的图片是给示例代码用的 +``` +# 四、代码调用示例 +```go +package main + +import ( + "fmt" + + . "github.com/windosx/face-engine/v4" + "github.com/windosx/face-engine/v4/util" +) + +// 获取处理好的图片信息 +var imageInfo = util.GetResizedImageInfo("./mask.jpg") + +func main() { + // 激活SDK + if err := OnlineActivation("YourAppID", "YourSDKKey", "YourActiveCode"); err != nil { + fmt.Printf("%#v\n", err) + return + } + // 初始化引擎 + engine, err := NewFaceEngine(DetectModeImage, + OrientPriority0, + 10, // 4.0最大支持10个人脸 + EnableFaceDetect|EnableFaceRecognition|EnableFace3DAngle|EnableLiveness|EnableIRLiveness|EnableAge|EnableGender|EnableMaskDetect|EnableFaceLandMark) + if err != nil { + fmt.Printf("%#v\n", err) + return + } + deviceInfo, err := GetActiveDeviceInfo() + if err != nil { + fmt.Printf("%#v\n", err) + } + fmt.Printf("设备信息:%s\n", deviceInfo) + // 检测人脸 + info, err := engine.DetectFaces(imageInfo.Width, imageInfo.Height, ColorFormatBGR24, imageInfo.DataUInt8) + if err != nil { + fmt.Printf("%#v\n", err) + return + } + // 处理人脸数据 + if err = engine.Process(imageInfo.Width, imageInfo.Height, ColorFormatBGR24, imageInfo.DataUInt8, info, EnableAge|EnableGender|EnableFace3DAngle|EnableLiveness|EnableMaskDetect|EnableFaceLandMark); err != nil { + fmt.Printf("%#v\n", err) + return + } + // 获取年龄 + ageInfo, err := engine.GetAge() + if err != nil { + fmt.Printf("%#v\n", err) + return + } + fmt.Printf("ageInfo: %v\n", ageInfo) + // 获取口罩信息 + maskInfo, err := engine.GetMask() + if err != nil { + fmt.Printf("%#v\n", err) + return + } + fmt.Printf("口罩信息:%#v\n", maskInfo) + // 获取额头点位 + landMark, err := engine.GetFaceLandMarkInfo() + if err != nil { + fmt.Printf("%#v\n", err) + return + } + fmt.Printf("额头点位:%#v\n", landMark) + // 销毁引擎 + if err = engine.Destroy(); err != nil { + fmt.Printf("%#v\n", err) + return + } +} +``` +# 五、注意事项 +1. 通过`FaceFeatureExtract`或`FaceFeatureExtractEx`方法提取到人脸特征信息,使用完毕后应调用其`Release()`方法释放内存,避免导致内存溢出,这是由于cgo的一些局限性导致的。 + +# 六、更多示例代码 +- [ArcFace+gocv处理视频流](https://github.com/windosx/arcface-gocv-examples) + +***(如果您想分享自己的示例,欢迎PR)*** + +# 七、开源说明 +本项目使用MIT协议,如果对您有帮助,请点亮star支持一下 :) \ No newline at end of file diff --git a/engine.go b/engine.go new file mode 100644 index 0000000..a473b97 --- /dev/null +++ b/engine.go @@ -0,0 +1,779 @@ +package faceengine + +/* +#cgo CFLAGS : -I./include +#cgo LDFLAGS : -larcsoft_face_engine +#include +#include "merror.h" +#include "asvloffscreen.h" +#include "arcsoft_face_sdk.h" +*/ +import "C" + +import ( + "unsafe" +) + +// FaceEngine 引擎结构体 +type FaceEngine struct { + handle C.MHandle +} + +// MultiFaceInfo 多人脸信息结构体 +type MultiFaceInfo struct { + FaceRect []Rect // 人脸框信息 + FaceOrient []int32 // 输入图像的角度 + FaceNum int32 // 检测到的人脸个数 + FaceID []int32 // face ID,IMAGE模式下不返回FaceID + WearGlasses float32 // 带眼镜置信度[0-1],推荐阈值0.5 + LeftEyeClosed int32 // 左眼状态 0 未闭眼 1 闭眼 + RightEyeClosed int32 // 右眼状态 0 未闭眼 1 闭眼 + FaceDataInfoList []C.ASF_FaceDataInfo // 多张人脸信息 + native *C.ASF_MultiFaceInfo +} + +// Rect 人脸坐标结构体 +type Rect struct { + Left int32 + Top int32 + Right int32 + Bottom int32 +} + +// LivenessThreshold 活体置信度结构体 +type LivenessThreshold struct { + ThresholdModelBGR float32 + ThresholdModelIR float32 +} + +// ActiveFileInfo 激活文件信息结构体 +type ActiveFileInfo struct { + StartTime string //开始时间 + EndTime string //截止时间 + ActiveKey string //激活码 + Platform string //平台 + SdkType string //sdk类型 + AppID string //APPID + SdkKey string //SDKKEY + SdkVersion string //SDK版本号 + FileVersion string //激活文件版本号 +} + +// Version 版本信息结构体 +type Version struct { + Version string // 版本号 + BuildDate string // 构建日期 + CopyRight string // Copyright +} + +// SingleFaceInfo 单人脸信息结构体 +type SingleFaceInfo struct { + FaceRect Rect // 人脸框信息 + FaceOrient int32 // 输入图像的角度,可以参考 ArcFaceCompare_OrientCode + DataInfo C.ASF_FaceDataInfo +} + +// FaceFeature 人脸特征结构体 +type FaceFeature struct { + Feature []byte // 人脸特征信息 + FeatureSize int32 // 人脸特征信息长度 + native *C.ASF_FaceFeature + featurePtr *C.MByte +} + +// ImageData 对应ASVLOFFSCREEN结构体 +type ImageData struct { + PixelArrayFormat C.MUInt32 + Width int + Height int + ImageData [4][]uint8 + WidthStep [4]int +} + +// AgeInfo 年龄信息结构体 +type AgeInfo struct { + AgeArray []int32 // "0" 代表不确定,大于0的数值代表检测出来的年龄结果 + Num int32 // 检测的人脸个数 +} + +// GenderInfo 性别信息结构体 +type GenderInfo struct { + GenderArray []int32 // "0" 表示 男性, "1" 表示 女性, "-1" 表示不确定 + Num int32 // 检测的人脸个数 +} + +// Face3DAngle 人脸3D角度信息结构体 +type Face3DAngle struct { + Roll []float32 + Yaw []float32 + Pitch []float32 + Status []int32 // 0: 正常,其他数值:出错 + Num int32 +} + +// LivenessInfo 活体信息 +type LivenessInfo struct { + IsLive []int32 // 0:非真人 1:真人 -1:不确定 -2:传入人脸数>1 + Num int32 +} + +// FaceLandMark 特征点信息结构体 +type FaceLandMark struct { + PosX float32 + PosY float32 +} + +// LandMarkInfo 额头区域点位 +type LandMarkInfo struct { + Point []FaceLandMark + Num int32 +} + +// MaskInfo 口罩信息结构体 +type MaskInfo struct { + MaskArray []int32 // 0代表没有带口罩 1代表带口罩 -1表示不确定 + Num int32 // 检测的人脸个数 +} + +// EngineError SDK错误码 +type EngineError struct { + Code int + Text string +} + +const ( + // DetectModeVideo 视频模式 + DetectModeVideo = C.ASF_DETECT_MODE_VIDEO + // DetectModeImage 图片模式 + DetectModeImage = C.ASF_DETECT_MODE_IMAGE + // OrientPriority0 不旋转 + OrientPriority0 = C.ASF_OP_0_ONLY + // OrientPriority90 旋转90度 + OrientPriority90 = C.ASF_OP_90_ONLY + // OrientPriority270 旋转270度 + OrientPriority270 = C.ASF_OP_270_ONLY + // OrientPriority180 旋转180度 + OrientPriority180 = C.ASF_OP_180_ONLY + // OrientPriorityAllOut 角度不限 + OrientPriorityAllOut = C.ASF_OP_ALL_OUT + // EnableNone 不开启任何功能 + EnableNone = C.ASF_NONE + // EnableFaceDetect 开启人脸检测 + EnableFaceDetect = C.ASF_FACE_DETECT + // EnableFaceRecognition 开启人脸识别 + EnableFaceRecognition = C.ASF_FACERECOGNITION + // EnableAge 开启年龄检测 + EnableAge = C.ASF_AGE + // EnableGender 开启性别检测 + EnableGender = C.ASF_GENDER + // EnableFace3DAngle 开启人脸3D角度检测 + EnableFace3DAngle = C.ASF_FACE3DANGLE + // EnableLiveness 开启活体检测 + EnableLiveness = C.ASF_LIVENESS + // EnableIRLiveness 开启IR活体检测 + EnableIRLiveness = C.ASF_IR_LIVENESS + // EnableFaceLandMark 开启人脸特征点检测 + EnableFaceLandMark = C.ASF_FACELANDMARK + // EnableImageQuality 开启单人脸图片质量检测 + EnableImageQuality = C.ASF_IMAGEQUALITY + // EnableFaceShelter 开启遮挡检测 + EnableFaceShelter = C.ASF_FACESHELTER + // EnableMaskDetect 开启口罩检测 + EnableMaskDetect = C.ASF_MASKDETECT + // EnableUpdateFaceData 开启人脸数据更新 + EnableUpdateFaceData = C.ASF_UPDATE_FACEDATA + // ColorFormatBGR24 BGR24格式 + ColorFormatBGR24 = C.ASVL_PAF_RGB24_B8G8R8 + // ColorFormatNV12 NV12格式 + ColorFormatNV12 = C.ASVL_PAF_NV12 + // ColorFormatNV21 NV21格式 + ColorFormatNV21 = C.ASVL_PAF_NV21 + // ColorFormatI420 I420格式 + ColorFormatI420 = C.ASVL_PAF_I420 + // ColorFormatYUYV YUYV格式 + ColorFormatYUYV = C.ASVL_PAF_YUYV + // RecognitionPhoto 识别照片 + RecognitionPhoto = C.ASF_RECOGNITION + // RegisterPhoto 注册照片 + RegisterPhoto = C.ASF_REGISTER +) + +// NewFaceEngine 创建一个新的引擎实例 +// +// 如果调用初始化函数失败则返回一个错误 +func NewFaceEngine( + detectMode C.ASF_DetectMode, // 检测模式 + orientPriority C.ASF_OrientPriority, // 检测角度 + maxFaceNum C.MInt32, // 最大人脸数[1-10] + combinedMask C.MInt32, // 检测选项 +) (*FaceEngine, error) { + engine, err := &FaceEngine{}, error(nil) + r := C.ASFInitEngine(detectMode, orientPriority, maxFaceNum, combinedMask, &engine.handle) + if r != C.MOK { + err = newError(int(r), "初始化引擎失败") + } + return engine, err +} + +// GetActiveFileInfo 获取激活文件信息接口 +func GetActiveFileInfo() (ActiveFileInfo, error) { + asfActiveFileInfo := &C.ASF_ActiveFileInfo{} + r := C.ASFGetActiveFileInfo(asfActiveFileInfo) + if r != C.MOK { + return ActiveFileInfo{}, newError(int(r), "获取激活文件信息失败") + } + info := ActiveFileInfo{ + StartTime: C.GoString(asfActiveFileInfo.startTime), + EndTime: C.GoString(asfActiveFileInfo.endTime), + Platform: C.GoString(asfActiveFileInfo.platform), + SdkType: C.GoString(asfActiveFileInfo.sdkType), + AppID: C.GoString(asfActiveFileInfo.appId), + SdkKey: C.GoString(asfActiveFileInfo.sdkKey), + SdkVersion: C.GoString(asfActiveFileInfo.sdkVersion), + FileVersion: C.GoString(asfActiveFileInfo.fileVersion), + } + return info, nil +} + +// OnlineActivation 在线激活接口 +func OnlineActivation(appID, sdkKey, activeKey string) (err error) { + id := C.CString(appID) + sk := C.CString(sdkKey) + ak := C.CString(activeKey) + defer func() { + C.free(unsafe.Pointer(id)) + C.free(unsafe.Pointer(sk)) + C.free(unsafe.Pointer(ak)) + }() + r := C.ASFOnlineActivation(id, sk, ak) + if r != C.MOK && r != C.MERR_ASF_ALREADY_ACTIVATED { + err = newError(int(r), "激活SDK失败") + } + return +} + +// OfflineActivation 离线激活接口 +func OfflineActivation(filePath string) (err error) { + cFilePath := C.CString(filePath) + defer C.free(unsafe.Pointer(cFilePath)) + r := C.ASFOfflineActivation(cFilePath) + if r != C.MOK { + err = newError(int(r), "离线激活失败") + } + return +} + +// GetActiveDeviceInfo 采集当前设备信息(可离线) +func GetActiveDeviceInfo() ([]byte, error) { + deviceInfo := C.CString("") + defer C.free(unsafe.Pointer(deviceInfo)) + r := C.ASFGetActiveDeviceInfo((*C.MPChar)(unsafe.Pointer(&deviceInfo))) + if r != C.MOK { + return nil, newError(int(r), "采集当前设备信息失败") + } + str := C.GoString(deviceInfo) + b := make([]byte, len(str)) + copy(b, str) + return b, nil +} + +// DetectFaces 人脸检测,目前不支持IR图像数据检测 +func (engine *FaceEngine) DetectFaces( + width int, // 宽度 + height int, // 高度 + format C.MInt32, // 图像格式 + imgData []byte, // 图片数据 +) (faceInfo MultiFaceInfo, err error) { + asfFaceInfo := &C.ASF_MultiFaceInfo{} + r := C.ASFDetectFaces(engine.handle, + C.MInt32(width), + C.MInt32(height), + format, + (*C.MUInt8)(unsafe.Pointer(&imgData[0])), + asfFaceInfo, + C.ASF_DETECT_MODEL_RGB, + ) + if r != C.MOK { + return faceInfo, newError(int(r), "人脸检测失败") + } + faceNum := int32(asfFaceInfo.faceNum) + faceInfo.FaceNum = faceNum + if faceNum > 0 { + faceInfo.FaceRect = (*[10]Rect)(unsafe.Pointer(asfFaceInfo.faceRect))[:faceNum:faceNum] + faceInfo.FaceOrient = (*[10]int32)(unsafe.Pointer(asfFaceInfo.faceOrient))[:faceNum:faceNum] + } + if asfFaceInfo.faceID != nil { + faceInfo.FaceID = (*[10]int32)(unsafe.Pointer(asfFaceInfo.faceID))[:faceNum:faceNum] + } + if asfFaceInfo.faceDataInfoList != nil { + faceInfo.FaceDataInfoList = (*[10]C.ASF_FaceDataInfo)(unsafe.Pointer(asfFaceInfo.faceDataInfoList))[:faceNum:faceNum] + } + faceInfo.native = asfFaceInfo + return +} + +// DetectFacesEx 检测人脸信息 +// +// 该接口与 DetectFaces 功能一致,但采用结构体的形式传入图像数据,对更高精度的图像兼容性更好。 +func (engine *FaceEngine) DetectFacesEx(imageData ImageData) (faceInfo MultiFaceInfo, err error) { + asfFaceInfo := &C.ASF_MultiFaceInfo{} + r := C.ASFDetectFacesEx(engine.handle, imageDataToASVLOFFSCREEN(imageData), asfFaceInfo, C.ASF_DETECT_MODEL_RGB) + if r != C.MOK { + return faceInfo, newError(int(r), "人脸检测失败") + } + faceNum := int32(asfFaceInfo.faceNum) + faceInfo.FaceNum = faceNum + if faceNum > 0 { + faceInfo.FaceRect = (*[10]Rect)(unsafe.Pointer(asfFaceInfo.faceRect))[:faceNum:faceNum] + faceInfo.FaceOrient = (*[10]int32)(unsafe.Pointer(asfFaceInfo.faceOrient))[:faceNum:faceNum] + } + if asfFaceInfo.faceID != nil { + faceInfo.FaceID = (*[10]int32)(unsafe.Pointer(asfFaceInfo.faceID))[:faceNum:faceNum] + } + if asfFaceInfo.faceDataInfoList != nil { + faceInfo.FaceDataInfoList = (*[10]C.ASF_FaceDataInfo)(unsafe.Pointer(asfFaceInfo.faceDataInfoList))[:faceNum:faceNum] + } + faceInfo.native = asfFaceInfo + return +} + +// Process 年龄/性别/人脸3D角度(该接口仅支持RGB图像),最多支持4张人脸信息检测,超过部分返回未知 +// RGB活体仅支持单人脸检测,该接口不支持检测IR活体 +func (engine *FaceEngine) Process( + width int, // 宽度 + height int, // 高度 + format C.MInt32, // 图像格式 + imgData []byte, // 图片数据 + detectedFaces MultiFaceInfo, // 多人脸信息 + combinedMask C.MInt32, // 检测选项 +) error { + r := C.ASFProcess(engine.handle, + C.MInt32(width), + C.MInt32(height), + format, + (*C.MUInt8)(unsafe.Pointer(&imgData[0])), + detectedFaces.native, + combinedMask) + if r != C.MOK { + return newError(int(r), "检测人脸信息失败") + } + return nil +} + +// ProcessEx 人脸信息检测(年龄/性别/人脸3D角度),最多支持4张人脸信息检测,超过部分返回未知(活体仅支持单张人脸检测,超出返回未知),接口仅支持可见光图像检测 +// +// 该接口与 Process 功能一致,但采用结构体的形式传入图像数据,对更高精度的图像兼容性更好 +func (engine *FaceEngine) ProcessEx(imageData ImageData, faceInfo MultiFaceInfo, combinedMask C.MInt32) error { + r := C.ASFProcessEx(engine.handle, imageDataToASVLOFFSCREEN(imageData), faceInfo.native, combinedMask) + if r != C.MOK { + return newError(int(r), "检测人脸信息失败") + } + return nil +} + +// ProcessIR 该接口目前仅支持单人脸IR活体检测(不支持年龄、性别、3D角度的检测),默认取第一张人脸 +func (engine *FaceEngine) ProcessIR( + width int, // 宽度 + height int, // 高度 + format C.MInt32, // 图像格式 + imgData []byte, // 图片数据 + detectedFaces MultiFaceInfo, // 多人脸信息 + combinedMask C.MInt32, // 检测选项 +) (err error) { + r := C.ASFProcess(engine.handle, + C.MInt32(width), + C.MInt32(height), + format, + (*C.MUInt8)(unsafe.Pointer(&imgData[0])), + detectedFaces.native, + combinedMask) + if r != C.MOK { + return newError(int(r), "检测人脸IR活体信息失败") + } + return nil +} + +// ProcessExIR 该接口目前仅支持单人脸IR活体检测(不支持年龄、性别、3D角度的检测),默认取第一张人脸 +// +// 该接口与 ProcessIR 功能一致,但采用结构体的形式传入图像数据,对更高精度的图像兼容性更好 +func (engine *FaceEngine) ProcessExIR( + imageData ImageData, // 图像数据 + faceInfo MultiFaceInfo, // 多人脸信息 + combinedMask C.MInt32, // 检测选项 +) (err error) { + r := C.ASFProcessEx_IR(engine.handle, imageDataToASVLOFFSCREEN(imageData), faceInfo.native, combinedMask) + if r != C.MOK { + return newError(int(r), "检测人脸IR活体信息失败") + } + return nil +} + +// SetLivenessParam 设置活体置信度 +// +// 取值范围[0-1]内部默认数值RGB-0.75,IR-0.7, 用户可以根据实际需求,设置不同的阈值 +func (engine *FaceEngine) SetLivenessParam(threshold LivenessThreshold) error { + asfLivenessThreshold := &C.ASF_LivenessThreshold{ + thresholdmodel_BGR: C.MFloat(threshold.ThresholdModelBGR), + thresholdmodel_IR: C.MFloat(threshold.ThresholdModelIR), + } + r := C.ASFSetLivenessParam(engine.handle, asfLivenessThreshold) + if r != C.MOK { + return newError(int(r), "设置活体置信度失败") + } + return nil +} + +// GetVersion 获取版本信息 +func (engine *FaceEngine) GetVersion() Version { + info := C.ASFGetVersion() + return Version{ + Version: C.GoString(info.Version), + BuildDate: C.GoString(info.BuildDate), + CopyRight: C.GoString(info.CopyRight), + } +} + +// FaceFeatureExtract 单人脸特征提取 +func (engine *FaceEngine) FaceFeatureExtract( + width int, // 宽度 + height int, // 高度 + format C.MInt32, // 图像格式 + imgData []byte, // 图片数据 + faceInfo SingleFaceInfo, // 单人脸信息 + registerOrNot int, // 图片模式 + mask int, // 是否带口罩 +) (faceFeature FaceFeature, err error) { + asfFaceFeature := &C.ASF_FaceFeature{} + asfFaceInfo := &C.ASF_SingleFaceInfo{ + C.MRECT{ + C.MInt32(faceInfo.FaceRect.Left), + C.MInt32(faceInfo.FaceRect.Top), + C.MInt32(faceInfo.FaceRect.Right), + C.MInt32(faceInfo.FaceRect.Bottom)}, + C.MInt32(faceInfo.FaceOrient), + faceInfo.DataInfo} + r := C.ASFFaceFeatureExtract( + engine.handle, + C.MInt32(width), + C.MInt32(height), + format, + (*C.MUInt8)(unsafe.Pointer(&imgData[0])), + asfFaceInfo, + C.ASF_RegisterOrNot(registerOrNot), + C.MInt32(mask), + asfFaceFeature) + if r != C.MOK { + return FaceFeature{}, newError(int(r), "提取人脸特征失败") + } + length := int32(asfFaceFeature.featureSize) + faceFeature.FeatureSize = length + faceFeature.Feature = make([]byte, length) + byteArr := (*[1 << 12]byte)(unsafe.Pointer(asfFaceFeature.feature))[:length:length] + arr := (*C.MByte)(C.malloc(C.size_t(int32(asfFaceFeature.featureSize)))) + faceFeature.featurePtr = arr + ps := (*[1 << 12]C.MByte)(unsafe.Pointer(arr))[:length:length] + for i := 0; i < len(ps); i++ { + ps[i] = C.MByte(byteArr[i]) + faceFeature.Feature[i] = byteArr[i] + } + asfFaceFeature.feature = arr + faceFeature.native = asfFaceFeature + return faceFeature, err +} + +// FaceFeatureExtractEx 单人脸特征提取 +// +// 该接口与 ASFFaceFeatureExtract 功能一致,但采用结构体的形式传入图像数据,对更高精度的图像兼容性更好 +func (engine *FaceEngine) FaceFeatureExtractEx( + imageData ImageData, // 图片数据 + faceInfo SingleFaceInfo, // 单人脸信息 + registerOrNot int, // 图片模式 + mask int, // 是否带口罩 +) (feature FaceFeature, err error) { + asfFaceFeature := &C.ASF_FaceFeature{} + asfFaceInfo := &C.ASF_SingleFaceInfo{ + C.MRECT{ + C.MInt32(faceInfo.FaceRect.Left), + C.MInt32(faceInfo.FaceRect.Top), + C.MInt32(faceInfo.FaceRect.Right), + C.MInt32(faceInfo.FaceRect.Bottom)}, + C.MInt32(faceInfo.FaceOrient), + faceInfo.DataInfo} + r := C.ASFFaceFeatureExtractEx(engine.handle, imageDataToASVLOFFSCREEN(imageData), asfFaceInfo, C.ASF_RegisterOrNot(registerOrNot), C.MInt32(mask), asfFaceFeature) + if r != C.MOK { + return FaceFeature{}, newError(int(r), "提取人脸特征失败") + } + length := int32(asfFaceFeature.featureSize) + feature.FeatureSize = length + feature.Feature = make([]byte, length) + byteArr := (*[1 << 12]byte)(unsafe.Pointer(asfFaceFeature.feature))[:length:length] + arr := (*C.MByte)(C.malloc(C.size_t(int32(asfFaceFeature.featureSize)))) + feature.featurePtr = arr + ps := (*[1 << 12]C.MByte)(unsafe.Pointer(arr))[:length:length] + for i := 0; i < len(ps); i++ { + ps[i] = C.MByte(byteArr[i]) + feature.Feature[i] = byteArr[i] + } + asfFaceFeature.feature = arr + feature.native = asfFaceFeature + return +} + +// FaceFeatureCompare 人脸特征比对 +func (engine *FaceEngine) FaceFeatureCompare(feature1, feature2 FaceFeature) (confidenceLevel float32, err error) { + r := C.ASFFaceFeatureCompare(engine.handle, + feature1.native, + feature2.native, + (*C.MFloat)(unsafe.Pointer(&confidenceLevel)), + C.ASF_DETECT_MODEL_RGB, + ) + if r != C.MOK { + err = newError(int(r), "人脸特征比对失败!") + } + return +} + +// GetAge 获取年龄信息 +func (engine *FaceEngine) GetAge() (AgeInfo, error) { + asfAgeInfo := &C.ASF_AgeInfo{} + r := C.ASFGetAge((C.MHandle)(engine.handle), asfAgeInfo) + if r != C.MOK { + return AgeInfo{}, newError(int(r), "获取年龄信息失败") + } + num := int32(asfAgeInfo.num) + return AgeInfo{ + AgeArray: (*[10]int32)(unsafe.Pointer(asfAgeInfo.ageArray))[:num:num], + Num: num, + }, nil +} + +// GetGender 获取性别信息 +func (engine *FaceEngine) GetGender() (GenderInfo, error) { + asfGenderInfo := &C.ASF_GenderInfo{} + r := C.ASFGetGender((C.MHandle)(engine.handle), asfGenderInfo) + if r != C.MOK { + return GenderInfo{}, newError(int(r), "获取性别信息失败") + } + num := int32(asfGenderInfo.num) + return GenderInfo{ + GenderArray: (*[10]int32)(unsafe.Pointer(asfGenderInfo.genderArray))[:num:num], + Num: num, + }, nil +} + +// GetFace3DAngle 获取3D角度信息 +func (engine *FaceEngine) GetFace3DAngle() (Face3DAngle, error) { + asfFace3DAngle := &C.ASF_Face3DAngle{} + r := C.ASFGetFace3DAngle((C.MHandle)(engine.handle), asfFace3DAngle) + if r != C.MOK { + return Face3DAngle{}, newError(int(r), "获取3D角度信息失败") + } + num := int32(asfFace3DAngle.num) + return Face3DAngle{ + Roll: (*[10]float32)(unsafe.Pointer(asfFace3DAngle.roll))[:num:num], + Yaw: (*[10]float32)(unsafe.Pointer(asfFace3DAngle.yaw))[:num:num], + Pitch: (*[10]float32)(unsafe.Pointer(asfFace3DAngle.pitch))[:num:num], + Status: (*[10]int32)(unsafe.Pointer(asfFace3DAngle.status))[:num:num], + Num: int32(asfFace3DAngle.num), + }, nil +} + +// GetLivenessScore 获取RGB活体结果 +func (engine *FaceEngine) GetLivenessScore() (LivenessInfo, error) { + asfLivenessInfo := &C.ASF_LivenessInfo{} + r := C.ASFGetLivenessScore((C.MHandle)(engine.handle), asfLivenessInfo) + if r != C.MOK { + return LivenessInfo{}, newError(int(r), "获取活体信息失败") + } + num := int32(asfLivenessInfo.num) + return LivenessInfo{ + IsLive: (*[10]int32)(unsafe.Pointer(asfLivenessInfo.isLive))[:num:num], + Num: num, + }, nil +} + +// GetLivenessScoreIR 获取IR活体结果 +func (engine *FaceEngine) GetLivenessScoreIR() (LivenessInfo, error) { + asfLivenessInfo := &C.ASF_LivenessInfo{} + r := C.ASFGetLivenessScore_IR((C.MHandle)(engine.handle), asfLivenessInfo) + if r != C.MOK { + return LivenessInfo{}, newError(int(r), "获取活体信息失败") + } + num := int32(asfLivenessInfo.num) + return LivenessInfo{ + IsLive: (*[10]int32)(unsafe.Pointer(asfLivenessInfo.isLive))[:num:num], + Num: num, + }, nil +} + +// GetMask 获取口罩信息 +func (engine *FaceEngine) GetMask() (maskInfo MaskInfo, err error) { + asfMaskInfo := &C.ASF_MaskInfo{} + r := C.ASFGetMask(engine.handle, (*C.ASF_MaskInfo)(unsafe.Pointer(asfMaskInfo))) + if r != C.MOK { + return maskInfo, newError(int(r), "获取口罩信息失败") + } + num := int32(asfMaskInfo.num) + return MaskInfo{ + MaskArray: (*[10]int32)(unsafe.Pointer(asfMaskInfo.maskArray))[:num:num], + Num: num, + }, nil +} + +// GetFaceLandMarkInfo 获取额头区域位置 +func (engine *FaceEngine) GetFaceLandMarkInfo() (landMarkInfo LandMarkInfo, err error) { + asfLandMarkInfo := &C.ASF_LandMarkInfo{} + r := C.ASFGetFaceLandMark(engine.handle, asfLandMarkInfo) + if r != C.MOK { + return landMarkInfo, newError(int(r), "获取额头区域位置失败") + } + num := int32(asfLandMarkInfo.num) + asfPoint := (*[10]C.ASF_FaceLandmark)(unsafe.Pointer(asfLandMarkInfo.point))[:num:num] + point := make([]FaceLandMark, num) + for i := int32(0); i < num; i++ { + point[i] = FaceLandMark{ + PosX: float32(asfPoint[i].x), + PosY: float32(asfPoint[i].y), + } + } + return LandMarkInfo{ + Point: point, + Num: num, + }, nil +} + +// UpdateFaceData 更新人脸数据 +func (engine *FaceEngine) UpdateFaceData( + width int, // 宽度 + height int, // 高度 + format C.MInt32, // 图像格式 + imgData []byte, // 图片数据 + faceInfo MultiFaceInfo, // 多人脸信息 +) (err error) { + r := C.ASFUpdateFaceData(engine.handle, C.MInt32(width), C.MInt32(height), format, (*C.MUInt8)(unsafe.Pointer(&imgData[0])), faceInfo.native) + if r != C.MOK { + err = newError(int(r), "更新人脸数据失败") + } + return +} + +// ImageQualityDetect 单人脸图片质量检测 +func (engine *FaceEngine) ImageQualityDetect( + width int, // 宽度 + height int, // 高度 + format C.MInt32, // 图像格式 + imgData []byte, // 图片数据 + faceInfo SingleFaceInfo, // 单人脸信息 + isMask int, // 是否带口罩 +) (confidenceLevel float32, err error) { + asfFaceInfo := &C.ASF_SingleFaceInfo{ + C.MRECT{ + C.MInt32(faceInfo.FaceRect.Left), + C.MInt32(faceInfo.FaceRect.Top), + C.MInt32(faceInfo.FaceRect.Right), + C.MInt32(faceInfo.FaceRect.Bottom)}, + C.MInt32(faceInfo.FaceOrient), + faceInfo.DataInfo} + r := C.ASFImageQualityDetect( + engine.handle, + C.MInt32(width), + C.MInt32(height), + format, + (*C.MUInt8)(unsafe.Pointer(&imgData[0])), + asfFaceInfo, + C.MInt32(isMask), + (*C.MFloat)(unsafe.Pointer(&confidenceLevel)), + C.ASF_DETECT_MODEL_RGB, + ) + if r != C.MOK { + err = newError(int(r), "单人脸图片质量检测失败") + } + return confidenceLevel, err +} + +// SetFaceShelterParam 设置遮挡算法检测的阈值 +func (engine *FaceEngine) SetFaceShelterParam(shelterThreshhold float32) (err error) { + r := C.ASFSetFaceShelterParam(engine.handle, C.MFloat(shelterThreshhold)) + if r != C.MOK { + err = newError(int(r), "设置遮挡算法检测阈值失败") + } + return +} + +// Destroy 销毁引擎 +func (engine *FaceEngine) Destroy() (err error) { + r := C.ASFUninitEngine(engine.handle) + if r != C.MOK { + err = newError(int(r), "销毁引擎失败") + } + return +} + +// GetSingleFaceInfo 从多人脸结构体中提取单人脸信息 +func GetSingleFaceInfo(multiFaceInfo MultiFaceInfo) (faceInfo []SingleFaceInfo) { + faceInfo = make([]SingleFaceInfo, multiFaceInfo.FaceNum) + for i := 0; i < len(faceInfo); i++ { + faceInfo[i].FaceRect = Rect{ + Left: multiFaceInfo.FaceRect[i].Left, + Top: multiFaceInfo.FaceRect[i].Top, + Right: multiFaceInfo.FaceRect[i].Right, + Bottom: multiFaceInfo.FaceRect[i].Bottom, + } + faceInfo[i].FaceOrient = multiFaceInfo.FaceOrient[i] + faceInfo[i].DataInfo = multiFaceInfo.FaceDataInfoList[i] + } + return +} + +// ReadFaceFeatureFromBytes 将字节数据转为人脸特征数据 +func ReadFaceFeatureFromBytes(bytes []byte) (feature FaceFeature) { + asfFaceFeature := &C.ASF_FaceFeature{} + arr := (*C.MByte)(C.malloc(C.size_t(int32(len(bytes))))) + featurePtr := (*C.uchar)(unsafe.Pointer(C.CString(string(bytes)))) + asfFaceFeature.feature = featurePtr + asfFaceFeature.featureSize = C.int(len(bytes)) + return FaceFeature{ + Feature: bytes, + FeatureSize: int32(len(bytes)), + featurePtr: arr, + native: asfFaceFeature, + } +} + +// Release 释放内存 +func (feature *FaceFeature) Release() { + if feature.featurePtr != nil { + C.free(unsafe.Pointer(feature.featurePtr)) + } +} + +// 实现Error接口 +func (err EngineError) Error() string { + return err.Text +} + +func newError(code int, text string) EngineError { + return EngineError{ + Code: code, + Text: text, + } +} + +func imageDataToASVLOFFSCREEN(imageData ImageData) C.LPASVLOFFSCREEN { + var pi32Pitch [4](C.MInt32) + for i := 0; i < 4; i++ { + pi32Pitch[i] = C.MInt32(imageData.WidthStep[0]) + } + var ppu8Plane [4](*C.MUInt8) + for i := 0; i < 4; i++ { + if len(imageData.ImageData[i]) > 0 { + ppu8Plane[i] = (*C.MUInt8)(unsafe.Pointer(&imageData.ImageData[i][0])) + } + } + return &C.ASVLOFFSCREEN{ + imageData.PixelArrayFormat, + C.MInt32(imageData.Width), + C.MInt32(imageData.Height), + ppu8Plane, + pi32Pitch} +} diff --git a/examples/example1.go b/examples/example1.go new file mode 100644 index 0000000..e1fa9a4 --- /dev/null +++ b/examples/example1.go @@ -0,0 +1,69 @@ +package main + +import ( + "fmt" + + . "github.com/windosx/face-engine/v4" + "github.com/windosx/face-engine/v4/util" +) + +var imageInfo = util.GetResizedImageInfo("./mask.jpg") + +func main() { + // 激活SDK + if err := OnlineActivation("YourAppID", "YourSDKKey", "YourActiveCode"); err != nil { + fmt.Printf("%#v\n", err) + return + } + // 初始化引擎 + engine, err := NewFaceEngine(DetectModeImage, + OrientPriority0, + 10, // 4.0最大支持10个人脸 + EnableFaceDetect|EnableFaceRecognition|EnableFace3DAngle|EnableLiveness|EnableIRLiveness|EnableAge|EnableGender|EnableMaskDetect|EnableFaceLandMark) + if err != nil { + fmt.Printf("%#v\n", err) + return + } + deviceInfo, err := GetActiveDeviceInfo() + if err != nil { + fmt.Printf("%#v\n", err) + } + fmt.Printf("设备信息:%s\n", deviceInfo) + // 检测人脸 + info, err := engine.DetectFaces(imageInfo.Width, imageInfo.Height, ColorFormatBGR24, imageInfo.DataUInt8) + if err != nil { + fmt.Printf("%#v\n", err) + return + } + // 处理人脸数据 + if err = engine.Process(imageInfo.Width, imageInfo.Height, ColorFormatBGR24, imageInfo.DataUInt8, info, EnableAge|EnableGender|EnableFace3DAngle|EnableLiveness|EnableMaskDetect|EnableFaceLandMark); err != nil { + fmt.Printf("%#v\n", err) + return + } + // 获取年龄 + ageInfo, err := engine.GetAge() + if err != nil { + fmt.Printf("%#v\n", err) + return + } + fmt.Printf("ageInfo: %v\n", ageInfo) + // 获取口罩信息 + maskInfo, err := engine.GetMask() + if err != nil { + fmt.Printf("%#v\n", err) + return + } + fmt.Printf("口罩信息:%#v\n", maskInfo) + // 获取额头点位 + landMark, err := engine.GetFaceLandMarkInfo() + if err != nil { + fmt.Printf("%#v\n", err) + return + } + fmt.Printf("额头点位:%#v\n", landMark) + // 销毁引擎 + if err = engine.Destroy(); err != nil { + fmt.Printf("%#v\n", err) + return + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..6ae8720 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/windosx/face-engine/v4 + +go 1.15 diff --git a/include/amcomdef.h b/include/amcomdef.h new file mode 100644 index 0000000..50cd565 --- /dev/null +++ b/include/amcomdef.h @@ -0,0 +1,98 @@ +#ifndef __AMCOMDEF_H__ +#define __AMCOMDEF_H__ + + +#if defined(WINCE) || defined(WIN32) + +#ifndef _WCHAR_T_DEFINED +typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif//#ifndef _WCHAR_T_DEFINED + +#elif (defined(EKA2) && defined(__GCCE__)) +#ifndef _STDDEF_H_ +#ifndef __cplusplus +typedef unsigned short wchar_t; +#define __wchar_t_defined +#endif +#endif + + +#elif defined(__GCCE__) || defined(__GCC32__) +#ifndef _STDDEF_H_ +typedef unsigned short wchar_t; +#endif + +#endif//#if defined(WINCE) + + +#if defined(__GCC32__) || defined(__GCCE__) || defined(WINCE) || defined(WIN32) +typedef wchar_t MWChar; +#else +typedef unsigned short MWChar; +#endif + + +typedef long MLong; +typedef float MFloat; +typedef double MDouble; +typedef unsigned char MByte; +typedef unsigned short MWord; +typedef unsigned int MDWord; +typedef void* MHandle; +typedef char MChar; +typedef long MBool; +typedef void MVoid; +typedef void* MPVoid; +typedef char* MPChar; +typedef short MShort; +typedef const char* MPCChar; +typedef MLong MRESULT; +typedef MDWord MCOLORREF; +typedef signed char MInt8; +typedef unsigned char MUInt8; +typedef signed short MInt16; +typedef unsigned short MUInt16; +typedef signed int MInt32; +typedef unsigned int MUInt32; + +#if !defined(M_UNSUPPORT64) +#if defined(_MSC_VER) +typedef signed __int64 MInt64; +typedef unsigned __int64 MUInt64; +#else +typedef signed long long MInt64; +typedef unsigned long long MUInt64; +#endif +#endif + +typedef struct __tag_rect +{ + MInt32 left; + MInt32 top; + MInt32 right; + MInt32 bottom; +} MRECT, *PMRECT; + +typedef struct __tag_point +{ + MInt32 x; + MInt32 y; +} MPOINT, *PMPOINT; + + +#define MNull 0 +#define MFalse 0 +#define MTrue 1 + +//#ifndef MAX_PATH +//#define MAX_PATH 256 +//#endif + +#ifdef M_WIDE_CHAR +#define MTChar MWChar +#else +#define MTChar MChar +#endif + +#endif diff --git a/include/arcsoft_face_sdk.h b/include/arcsoft_face_sdk.h new file mode 100644 index 0000000..d3df33f --- /dev/null +++ b/include/arcsoft_face_sdk.h @@ -0,0 +1,508 @@ +/******************************************************************************* +* Copyright(c) ArcSoft, All right reserved. +* +* This file is ArcSoft's property. It contains ArcSoft's trade secret, proprietary +* and confidential information. +* +* DO NOT DISTRIBUTE, DO NOT DUPLICATE OR TRANSMIT IN ANY FORM WITHOUT PROPER +* AUTHORIZATION. +* +* If you are not an intended recipient of this file, you must not copy, +* distribute, modify, or take any action in reliance on it. +* +* If you have received this file in error, please immediately notify ArcSoft and +* permanently delete the original and any copy of any file and any printout +* thereof. +*********************************************************************************/ + +#ifndef _ARCSOFT_SDK_ASF_H_ +#define _ARCSOFT_SDK_ASF_H_ + +#include "amcomdef.h" +#include "asvloffscreen.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ASF_NONE 0x00000000 //������ +#define ASF_FACE_DETECT 0x00000001 //�˴�detect������tracking����detection��������֮һ�������ѡ����detect mode ȷ�� +#define ASF_FACERECOGNITION 0x00000004 //�������� +#define ASF_AGE 0x00000008 //���� +#define ASF_GENDER 0x00000010 //�Ա� +#define ASF_FACE3DANGLE 0x00000020 //3D�Ƕ� +#define ASF_FACELANDMARK 0x00000040 //��ͷ������ +#define ASF_LIVENESS 0x00000080 //RGB���� +#define ASF_IMAGEQUALITY 0x00000200 //ͼ��������� +#define ASF_IR_LIVENESS 0x00000400 //IR���� +#define ASF_FACESHELTER 0x00000800 //�����ڵ� +#define ASF_MASKDETECT 0x00001000 //���ּ�� +#define ASF_UPDATE_FACEDATA 0x00002000 //������Ϣ + + +#define ASF_MAX_DETECTFACENUM 10 //�ð汾���֧��ͬʱ���10������ + + //���ģʽ + typedef enum __tag_ASF_DetectMode{ + ASF_DETECT_MODE_VIDEO = 0x00000000, //Videoģʽ��һ�����ڶ�֡������� + ASF_DETECT_MODE_IMAGE = 0xFFFFFFFF //Imageģʽ��һ�����ھ�̬ͼ�ĵ��μ�� + } ASF_DetectMode; + + //���ʱ�������Ƕȵ����ȼ������ĵ��г�ʼ���ӿ�����ͼʾ˵������ο� + typedef enum __tag_ASF_OrientPriority { + ASF_OP_0_ONLY = 0x1, // ����Ԥ���������� + ASF_OP_90_ONLY = 0x2, // ����0����ʱ����ת90��ķ��� + ASF_OP_270_ONLY = 0x3, // ����0����ʱ����ת270��ķ��� + ASF_OP_180_ONLY = 0x4, // ����0����ת180��ķ�����ʱ�롢˳ʱ��Ч��һ���� + ASF_OP_ALL_OUT = 0x5 // ȫ�Ƕ� + } ASF_OrientPriority; + + //orientation �Ƕȣ���ʱ�뷽�� + typedef enum __tag_ASF_OrientCode { + ASF_OC_0 = 0x1, // 0 degree + ASF_OC_90 = 0x2, // 90 degree + ASF_OC_270 = 0x3, // 270 degree + ASF_OC_180 = 0x4, // 180 degree + ASF_OC_30 = 0x5, // 30 degree + ASF_OC_60 = 0x6, // 60 degree + ASF_OC_120 = 0x7, // 120 degree + ASF_OC_150 = 0x8, // 150 degree + ASF_OC_210 = 0x9, // 210 degree + ASF_OC_240 = 0xa, // 240 degree + ASF_OC_300 = 0xb, // 300 degree + ASF_OC_330 = 0xc // 330 degree + } ASF_OrientCode; + + //���ģ�� + typedef enum __tag_ASF_DetectModel { + ASF_DETECT_MODEL_RGB = 0x1 //RGBͼ����ģ�� + //Ԥ����չ�������ģ�� + } ASF_DetectModel; + + //�����ȶԿ�ѡ��ģ�� + typedef enum __tag_ASF_CompareModel{ + ASF_LIFE_PHOTO = 0x1, //����������֮��������ȶԣ��Ƽ���ֵ0.80 + ASF_ID_PHOTO = 0x2 //����֤���ջ���������֤����֮��������ȶԣ��Ƽ���ֵ0.82 + } ASF_CompareModel; + + typedef enum __tag_ASF_RegisterOrNot{ + ASF_RECOGNITION = 0x0, //����ʶ��������������ȡ + ASF_REGISTER = 0x1 //����ע��������������ȡ + } ASF_RegisterOrNot; + + //�汾��Ϣ + typedef struct { + MPChar Version; // �汾�� + MPChar BuildDate; // �������� + MPChar CopyRight; // Copyright + }ASF_VERSION, *LPASF_VERSION; + + //ͼ������ + typedef LPASVLOFFSCREEN LPASF_ImageData; + + //������Ϣ + typedef struct{ + MPVoid data; // ������Ϣ + MInt32 dataSize; // ������Ϣ���� + } ASF_FaceDataInfo, *LPASF_FaceDataInfo; + + //��������Ϣ + typedef struct SingleFaceInfo { + MRECT faceRect; // ��������Ϣ + MInt32 faceOrient; // ����ͼ��ĽǶȣ����Բο� ArcFaceCompare_OrientCode + ASF_FaceDataInfo faceDataInfo; // ����������Ϣ + } ASF_SingleFaceInfo, *LPASF_SingleFaceInfo; + + //��������Ϣ + typedef struct MultiFaceInfo { + MRECT* faceRect; // ��������Ϣ + MInt32* faceOrient; // ����ͼ��ĽǶȣ����Բο� ArcFaceCompare_OrientCode . + MInt32 faceNum; // ��⵽���������� + MInt32* faceID; // face ID��IMAGEģʽ�²�����FaceID + MFloat* wearGlasses; // ���۾����Ŷ�[0-1],�Ƽ���ֵ0.5 + MInt32* leftEyeClosed; // ����״̬ 0 δ���ۣ�1 ���� + MInt32* rightEyeClosed; // ����״̬ 0 δ���ۣ�1 ���� + MInt32* faceShelter; // "1" ��ʾ �ڵ�, "0" ��ʾ δ�ڵ�, "-1" ��ʾ��ȷ�� + LPASF_FaceDataInfo faceDataInfoList; // ����������Ϣ + }ASF_MultiFaceInfo, *LPASF_MultiFaceInfo; + + // �����ļ���Ϣ + typedef struct ActiveFileInfo { + MPChar startTime; //��ʼʱ�� + MPChar endTime; //��ֹʱ�� + MPChar activeKey; //������ + MPChar platform; //ƽ̨ + MPChar sdkType; //sdk���� + MPChar appId; //APPID + MPChar sdkKey; //SDKKEY + MPChar sdkVersion; //SDK�汾�� + MPChar fileVersion; //�����ļ��汾�� + }ASF_ActiveFileInfo, *LPASF_ActiveFileInfo; + + /******************************************************************************************* + * ��ȡ�����ļ���Ϣ�ӿ� + *******************************************************************************************/ + MRESULT ASFGetActiveFileInfo( + LPASF_ActiveFileInfo activeFileInfo // [out] �����ļ���Ϣ + ); + + /******************************************************************************************* + * ���߼���ӿ� + *******************************************************************************************/ + MRESULT ASFOnlineActivation( + MPChar AppId, // [in] APPID �������� + MPChar SDKKey, // [in] SDKKEY �������� + MPChar ActiveKey // [in] ActiveKey �������� + ); + + /******************************************************************************************* + * ��ȡ�豸��Ϣ�ӿ� + *******************************************************************************************/ + MRESULT ASFGetActiveDeviceInfo( + MPChar* deviceInfo // [out] �ɼ����豸��Ϣ�����ڵ����������������߼������������Ȩ�ļ� + ); + + /******************************************************************************************* + * ���߼���ӿ� + *******************************************************************************************/ + MRESULT ASFOfflineActivation( + MPChar filePath // [in] �����ļ�·��(������Ȩ�ļ�)����Ҫ��дȨ�� + ); + + /************************************************************************ + * ��ʼ������ + ************************************************************************/ + MRESULT ASFInitEngine( + ASF_DetectMode detectMode, // [in] AF_DETECT_MODE_VIDEO ��Ƶģʽ������������ͷԤ������Ƶ�ļ�ʶ�� + // AF_DETECT_MODE_IMAGE ͼƬģʽ�������ھ�̬ͼƬ��ʶ�� + ASF_OrientPriority detectFaceOrientPriority, // [in] ��������ĽǶ�����ֵ���ο� ArcFaceCompare_OrientPriority + MInt32 detectFaceMaxNum, // [in] �����Ҫ������������ + MInt32 combinedMask, // [in] �û�ѡ����Ҫ���Ĺ�����ϣ��ɵ������� + MHandle* hEngine // [out] ��ʼ�����ص�����handle + ); + + /************************************************************************ + * ȡֵ��Χ[0-1]�� Ĭ����ֵ:0.8�� �û����Ը���ʵ�����������ڵ���Χ + ************************************************************************/ + MRESULT ASFSetFaceShelterParam( + MHandle hEngine, // [in] ����handle + MFloat ShelterThreshhold // [in] �ڵ���ֵ + ); + + /****************************************************** + * VIDEOģʽ:����׷�� IMAGEģʽ:������� + ******************************************************/ + MRESULT ASFDetectFaces( + MHandle hEngine, // [in] ����handle + MInt32 width, // [in] ͼƬ���� + MInt32 height, // [in] ͼƬ�߶� + MInt32 format, // [in] ��ɫ�ռ��ʽ + MUInt8* imgData, // [in] ͼƬ���� + LPASF_MultiFaceInfo detectedFaces, // [out]��⵽��������Ϣ + ASF_DetectModel detectModel // [in] Ԥ���ֶΣ���ǰ�汾ʹ��Ĭ�ϲ������� + ); + + /****************************************************** + * VIDEOģʽ:����׷�� IMAGEģʽ:������� + * ͼ�������Խṹ����ʽ���룬�Բ��ø����ֽڶ��뷽ʽ��ͼ������Ը��� + ******************************************************/ + MRESULT ASFDetectFacesEx( + MHandle hEngine, // [in] ����handle + LPASF_ImageData imgData, // [in] ͼƬ���� + LPASF_MultiFaceInfo detectedFaces, // [out] ��⵽��������Ϣ + ASF_DetectModel detectModel // [in] Ԥ���ֶΣ���ǰ�汾ʹ��Ĭ�ϲ������� + ); + + /****************************************************** + * �����޸ĺ�������򣬸���������Ϣ��������˫Ŀ������������� + * ע�⣺LPASF_MultiFaceInfo�ڸýӿ��м������Ҳ�dz��� + ******************************************************/ + MRESULT ASFUpdateFaceData( + MHandle hEngine, // [in] ����handle + MInt32 width, // [in] ͼƬ���� + MInt32 height, // [in] ͼƬ�߶� + MInt32 format, // [in] ��ɫ�ռ��ʽ + MUInt8 * imgData, // [in] ͼƬ���� + LPASF_MultiFaceInfo detectedFaces // [in/out]��⵽��������Ϣ + ); + + /****************************************************** + * �����޸ĺ�������򣬸���������Ϣ��������˫Ŀ������������� + * ע�⣺LPASF_MultiFaceInfo�ڸýӿ��м������Ҳ�dz��� + * ͼ�������Խṹ����ʽ���룬�Բ��ø����ֽڶ��뷽ʽ��ͼ������Ը��� + ******************************************************/ + MRESULT ASFUpdateFaceDataEx( + MHandle hEngine, // [in] ����handle + LPASF_ImageData imgData, // [in] ͼ������ + LPASF_MultiFaceInfo detectedFaces // [in/out] ��⵽��������Ϣ + ); + + /****************************************************** + * ͼ��������⣬��RGBģʽ�� ʶ����ֵ��0.49 ע����ֵ��0.63 ����ģʽ��ʶ����ֵ��0.29�� + ******************************************************/ + MRESULT ASFImageQualityDetect( + MHandle hEngine, // [in] ����handle + MInt32 width, // [in] ͼƬ���� + MInt32 height, // [in] ͼƬ�߶� + MInt32 format, // [in] ��ɫ�ռ��ʽ + MUInt8 * imgData, // [in] ͼƬ���� + LPASF_SingleFaceInfo faceInfo, // [in] ����λ����Ϣ + MInt32 isMask, // [in] ��֧�ִ���1��0��-1�������� 1��������Ϊδ������ + MFloat* confidenceLevel, // [out] ͼ����������� + ASF_DetectModel detectModel // [in] Ԥ���ֶΣ���ǰ�汾ʹ��Ĭ�ϲ������� + ); + + /****************************************************** + * ͼ��������⣬��RGBģʽ�� ʶ����ֵ��0.49 ע����ֵ��0.63 ����ģʽ��ʶ����ֵ��0.29�� + * ͼ�������Խṹ����ʽ���룬�Բ��ø����ֽڶ��뷽ʽ��ͼ������Ը��� + ******************************************************/ + MRESULT ASFImageQualityDetectEx( + MHandle hEngine, // [in] ����handle + LPASF_ImageData imgData, // [in] ͼƬ���� + LPASF_SingleFaceInfo faceInfo, // [in] ����λ����Ϣ + MInt32 isMask, // [in] ��֧�ִ���1��0��-1�������� 1��������Ϊδ������ + MFloat* confidenceLevel, // [out] ͼ����������� + ASF_DetectModel detectModel // [in] Ԥ���ֶΣ���ǰ�汾ʹ��Ĭ�ϲ������� + ); + + /************************************************************************ + * ����/�Ա�/����3D�Ƕ�/����/�ڵ�/��ͷ���򣨸ýӿڽ�֧��RGBͼ�񣩣����֧��4��������Ϣ��⣬�������ַ���δ֪ + * RGB�����֧�ֵ�������⣬�ýӿڲ�֧�ּ��IR���� + ************************************************************************/ + MRESULT ASFProcess( + MHandle hEngine, // [in] ����handle + MInt32 width, // [in] ͼƬ���� + MInt32 height, // [in] ͼƬ�߶� + MInt32 format, // [in] ��ɫ�ռ��ʽ + MUInt8* imgData, // [in] ͼƬ���� + LPASF_MultiFaceInfo detectedFaces, // [in] ������Ϣ���û����ݴ����Ĺ���ѡ����Ҫʹ�õ������� + MInt32 combinedMask // [in] ֻ֧�ֳ�ʼ��ʱ��ָ����Ҫ���Ĺ��ܣ���processʱ��һ��������Ѿ�ָ���Ĺ��ܼ��м���ɸѡ + // �����ʼ����ʱ��ָ�����������Ա���process��ʱ�����ֻ������䣬���Dz��ܼ���������Ա�֮��Ĺ��� + ); + + /************************************************************************ + * ����/�Ա�/����3D�Ƕ�/����/�ڵ�/��ͷ���򣨸ýӿڽ�֧��RGBͼ�񣩣����֧��4��������Ϣ��⣬�������ַ���δ֪ + * RGB�����֧�ֵ�������⣬�ýӿڲ�֧�ּ��IR���� + * ͼ�������Խṹ����ʽ���룬�Բ��ø����ֽڶ��뷽ʽ��ͼ������Ը��� + ************************************************************************/ + MRESULT ASFProcessEx( + MHandle hEngine, // [in] ����handle + LPASF_ImageData imgData, // [in] ͼƬ���� + LPASF_MultiFaceInfo detectedFaces, // [in] ������Ϣ���û����ݴ����Ĺ���ѡ����Ҫʹ�õ������� + MInt32 combinedMask // [in] ֻ֧�ֳ�ʼ��ʱ��ָ����Ҫ���Ĺ��ܣ���processʱ��һ��������Ѿ�ָ���Ĺ��ܼ��м���ɸѡ + // �����ʼ����ʱ��ָ�����������Ա���process��ʱ�����ֻ������䣬���Dz��ܼ���������Ա�֮��Ĺ��� + ); + + /************************************************************************ + * �ýӿ�Ŀǰ��֧�ֵ�����IR�����⣬Ĭ��ȡ��һ������ + ************************************************************************/ + MRESULT ASFProcess_IR( + MHandle hEngine, // [in] ����handle + MInt32 width, // [in] ͼƬ���� + MInt32 height, // [in] ͼƬ�߶� + MInt32 format, // [in] ��ɫ�ռ��ʽ + MUInt8* imgData, // [in] ͼƬ���� + LPASF_MultiFaceInfo detectedFaces, // [in] ������Ϣ���û����ݴ����Ĺ���ѡ����Ҫʹ�õ������� + MInt32 combinedMask // [in] Ŀǰֻ֧�ִ���ASF_IR_LIVENESS���ԵĴ��룬�ҳ�ʼ���ӿ���Ҫ���� + ); + + /************************************************************************ + * �ýӿ�Ŀǰ��֧�ֵ�����IR�����⣬Ĭ��ȡ��һ������ + * ͼ�������Խṹ����ʽ���룬�Բ��ø����ֽڶ��뷽ʽ��ͼ������Ը��� + ************************************************************************/ + MRESULT ASFProcessEx_IR( + MHandle hEngine, // [in] ����handle + LPASF_ImageData imgData, // [in] ͼƬ���� + LPASF_MultiFaceInfo detectedFaces, // [in] ������Ϣ���û����ݴ����Ĺ���ѡ����Ҫʹ�õ������� + MInt32 combinedMask // [in] Ŀǰֻ֧�ִ���ASF_IR_LIVENESS���ԵĴ��룬�ҳ�ʼ���ӿ���Ҫ���� + ); + + //******************************** ����ʶ����� ********************************************* + typedef struct FaceFeature { + MByte* feature; // ����������Ϣ + MInt32 featureSize; // ����������Ϣ���� + }ASF_FaceFeature, *LPASF_FaceFeature; + + /************************************************************************ + * ������������ȡ + ************************************************************************/ + MRESULT ASFFaceFeatureExtract( + MHandle hEngine, // [in] ����handle + MInt32 width, // [in] ͼƬ���� + MInt32 height, // [in] ͼƬ�߶� + MInt32 format, // [in] ��ɫ�ռ��ʽ + MUInt8* imgData, // [in] ͼƬ���� + LPASF_SingleFaceInfo faceInfo, // [in] ��������λ�úͽǶ���Ϣ + ASF_RegisterOrNot registerOrNot, // [in] ע�� 1 ʶ��Ϊ 0 + MInt32 mask, // [in] ������ 1������0 + LPASF_FaceFeature feature // [out] �������� + ); + + /************************************************************************ + * ������������ȡ + * ͼ�������Խṹ����ʽ���룬�Բ��ø����ֽڶ��뷽ʽ��ͼ������Ը��� + ************************************************************************/ + MRESULT ASFFaceFeatureExtractEx( + MHandle hEngine, // [in] ����handle + LPASF_ImageData imgData, // [in] ͼ������ + LPASF_SingleFaceInfo faceInfo, // [in] ��������λ�úͽǶ���Ϣ + ASF_RegisterOrNot registerOrNot, // [in] ע�� 1 ʶ��Ϊ 0 + MInt32 mask, // [in] ������ 1������0 + LPASF_FaceFeature feature // [out] �������� + ); + + /************************************************************************ + * ���������ȶԣ��Ƽ���ֵ ASF_LIFE_PHOTO��0.80 ASF_ID_PHOTO��0.82 + ************************************************************************/ + MRESULT ASFFaceFeatureCompare( + MHandle hEngine, // [in] ����handle + LPASF_FaceFeature feature1, // [in] ���Ƚ���������1 + LPASF_FaceFeature feature2, // [in] ���Ƚ���������2 + MFloat* confidenceLevel, // [out] �ȽϽ�������Ŷ���ֵ + ASF_CompareModel compareModel // [in] ASF_LIFE_PHOTO������������֮��������ȶ� + // ASF_ID_PHOTO������֤���ջ�֤���պ�������֮��������ȶ� + ); + + //******************************** ������� ********************************************** + typedef struct AgeInfo { + MInt32* ageArray; // "0" ������ȷ��������0����ֵ������������������ + MInt32 num; // ������������ + }ASF_AgeInfo, *LPASF_AgeInfo; + + /************************************************************************ + * ��ȡ������Ϣ + ************************************************************************/ + MRESULT ASFGetAge( + MHandle hEngine, // [in] ����handle + LPASF_AgeInfo ageInfo // [out] ��⵽��������Ϣ + ); + + //******************************** �Ա���� ********************************************** + typedef struct GenderInfo { + MInt32* genderArray; // "0" ��ʾ ����, "1" ��ʾ Ů��, "-1" ��ʾ��ȷ�� + MInt32 num; // ������������ + }ASF_GenderInfo, *LPASF_GenderInfo; + + /************************************************************************ + * ��ȡ�Ա���Ϣ + ************************************************************************/ + MRESULT ASFGetGender( + MHandle hEngine, // [in] ����handle + LPASF_GenderInfo genderInfo // [out] ��⵽���Ա���Ϣ + ); + + //******************************** ����3D �Ƕ���Ϣ *********************************** + typedef struct Face3DAngle { + MFloat* roll; + MFloat* yaw; + MFloat* pitch; + MInt32* status; + MInt32 num; + }ASF_Face3DAngle, *LPASF_Face3DAngle; + + /************************************************************************ + * ��ȡ3D�Ƕ���Ϣ + ************************************************************************/ + MRESULT ASFGetFace3DAngle( + MHandle hEngine, // [in] ����handle + LPASF_Face3DAngle p3DAngleInfo // [out] ��⵽����3D �Ƕ���Ϣ + ); + + //******************************** ������Ϣ *********************************** + typedef struct LivenessThreshold { + MFloat thresholdmodel_BGR; + MFloat thresholdmodel_IR; + }ASF_LivenessThreshold, *LPASF_LivenessThreshold; + + /************************************************************************ + * ȡֵ��Χ[0-1]��Ĭ��ֵ BGR:0.5 IR:0.7�� �û����Ը���ʵ���������ò�ͬ����ֵ + ************************************************************************/ + MRESULT ASFSetLivenessParam( + MHandle hEngine, // [in] ����handle + LPASF_LivenessThreshold threshold // [in] �������Ŷ� + ); + + typedef struct LivenessInfo { + MInt32* isLive; // [out] �ж��Ƿ����ˣ� 0�������ˣ� + // 1�����ˣ� + // -1����ȷ���� + // -2:����������>1�� + // -3: ������С + // -4: �Ƕȹ��� + // -5: ���������߽� + // -6: ���ͼ���� + // -7: ����ͼ̫���� + MInt32 num; + }ASF_LivenessInfo, *LPASF_LivenessInfo; + + /************************************************************************ + * ��ȡRGB������ + ************************************************************************/ + MRESULT ASFGetLivenessScore( + MHandle hEngine, // [in] ����handle + LPASF_LivenessInfo livenessInfo // [out] ���RGB������ + ); + + /************************************************************************ + * ��ȡIR������ + ************************************************************************/ + MRESULT ASFGetLivenessScore_IR( + MHandle hEngine, // [in] ����handle + LPASF_LivenessInfo irLivenessInfo // [out] ��⵽IR������ + ); + + //******************************** ���ּ����� ********************************************** + typedef struct MaskInfo + { + MInt32* maskArray; // "0" ����û�д����֣�"1"���������� ,"-1"����ȷ�� + MInt32 num; // ������������ + }ASF_MaskInfo, *LPASF_MaskInfo; + + /************************************************************************ + * ��ȡ���ּ��Ľ�� + ************************************************************************/ + MRESULT ASFGetMask( + MHandle hEngine, // [in] ����handle + LPASF_MaskInfo maskInfo // [out] ��⵽�Ŀ��ּ����� + ); + + //******************************** ��ͷ��������� ********************************************** + + #define LANDMARKS_NUM 4 //��������� + + typedef struct + { + MFloat x; + MFloat y; + }ASF_FaceLandmark, *LPASF_FaceLandmark; + + typedef struct LandMarkInfo + { + ASF_FaceLandmark *point; //��ͷ��λ + MInt32 num; //�������� + }ASF_LandMarkInfo, *LPASF_LandMarkInfo; + + /************************************************************************ + * ��ȡ��ͷ������������ǰֻ֧��0, 90, 180, 270�ȽǼ�⣩ + ************************************************************************/ + MRESULT ASFGetFaceLandMark( + MHandle engine, // [in] ����handle + LPASF_LandMarkInfo LandMarkInfo // [out]������ͷ�����飬ÿ��������ͷ����ͨ���ĸ����ʾ + ); + + /************************************************************************ + * �������� + ************************************************************************/ + MRESULT ASFUninitEngine( + MHandle hEngine + ); + + /************************************************************************ + * ��ȡ�汾��Ϣ + ************************************************************************/ + const ASF_VERSION ASFGetVersion(); + +#ifdef __cplusplus +} +#endif +#endif \ No newline at end of file diff --git a/include/asvloffscreen.h b/include/asvloffscreen.h new file mode 100644 index 0000000..309a1af --- /dev/null +++ b/include/asvloffscreen.h @@ -0,0 +1,183 @@ +#ifndef __ASVL_OFFSCREEN_H__ +#define __ASVL_OFFSCREEN_H__ + +#include "amcomdef.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/*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 */ + + +/* R R R R R G G G G G G B B B B B */ +#define ASVL_PAF_RGB16_B5G6R5 0x101 +/* X R R R R R G G G G G B B B B B */ +#define ASVL_PAF_RGB16_B5G5R5 0x102 +/* X X X X R R R R G G G G B B B B */ +#define ASVL_PAF_RGB16_B4G4R4 0x103 +/* T R R R R R G G G G G B B B B B */ +#define ASVL_PAF_RGB16_B5G5R5T 0x104 +/* B B B B B G G G G G G R R R R R */ +#define ASVL_PAF_RGB16_R5G6B5 0x105 +/* X B B B B B G G G G G R R R R R */ +#define ASVL_PAF_RGB16_R5G5B5 0x106 +/* X X X X B B B B G G G G R R R R */ +#define ASVL_PAF_RGB16_R4G4B4 0x107 + + +/* R R R R R R R R G G G G G G G G B B B B B B B B */ +#define ASVL_PAF_RGB24_B8G8R8 0x201 +/* X X X X X X R R R R R R G G G G G G B B B B B B */ +#define ASVL_PAF_RGB24_B6G6R6 0x202 +/* X X X X X T R R R R R R G G G G G G B B B B B B */ +#define ASVL_PAF_RGB24_B6G6R6T 0x203 +/* B B B B B B B B G G G G G G G G R R R R R R R R */ +#define ASVL_PAF_RGB24_R8G8B8 0x204 +/* X X X X X X B B B B B B G G G G G G R R R R R R */ +#define ASVL_PAF_RGB24_R6G6B6 0x205 + +/* 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 */ +#define ASVL_PAF_RGB32_B8G8R8 0x301 +/* 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 */ +#define ASVL_PAF_RGB32_B8G8R8A8 0x302 +/* 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 */ +#define ASVL_PAF_RGB32_R8G8B8 0x303 +/* 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 */ +#define ASVL_PAF_RGB32_A8R8G8B8 0x304 +/* 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 */ +#define ASVL_PAF_RGB32_R8G8B8A8 0x305 + +/*Y0, U0, V0*/ +#define ASVL_PAF_YUV 0x401 +/*Y0, V0, U0*/ +#define ASVL_PAF_YVU 0x402 +/*U0, V0, Y0*/ +#define ASVL_PAF_UVY 0x403 +/*V0, U0, Y0*/ +#define ASVL_PAF_VUY 0x404 + +/*Y0, U0, Y1, V0*/ +#define ASVL_PAF_YUYV 0x501 +/*Y0, V0, Y1, U0*/ +#define ASVL_PAF_YVYU 0x502 +/*U0, Y0, V0, Y1*/ +#define ASVL_PAF_UYVY 0x503 +/*V0, Y0, U0, Y1*/ +#define ASVL_PAF_VYUY 0x504 +/*Y1, U0, Y0, V0*/ +#define ASVL_PAF_YUYV2 0x505 +/*Y1, V0, Y0, U0*/ +#define ASVL_PAF_YVYU2 0x506 +/*U0, Y1, V0, Y0*/ +#define ASVL_PAF_UYVY2 0x507 +/*V0, Y1, U0, Y0*/ +#define ASVL_PAF_VYUY2 0x508 +/*Y0, Y1, U0, V0*/ +#define ASVL_PAF_YYUV 0x509 + +/*8 bit Y plane followed by 8 bit 2x2 subsampled U and V planes*/ +#define ASVL_PAF_I420 0x601 +/*8 bit Y plane followed by 8 bit 1x2 subsampled U and V planes*/ +#define ASVL_PAF_I422V 0x602 +/*8 bit Y plane followed by 8 bit 2x1 subsampled U and V planes*/ +#define ASVL_PAF_I422H 0x603 +/*8 bit Y plane followed by 8 bit U and V planes*/ +#define ASVL_PAF_I444 0x604 +/*8 bit Y plane followed by 8 bit 2x2 subsampled V and U planes*/ +#define ASVL_PAF_YV12 0x605 +/*8 bit Y plane followed by 8 bit 1x2 subsampled V and U planes*/ +#define ASVL_PAF_YV16V 0x606 +/*8 bit Y plane followed by 8 bit 2x1 subsampled V and U planes*/ +#define ASVL_PAF_YV16H 0x607 +/*8 bit Y plane followed by 8 bit V and U planes*/ +#define ASVL_PAF_YV24 0x608 +/*8 bit Y plane only*/ +#define ASVL_PAF_GRAY 0x701 + + +/*8 bit Y plane followed by 8 bit 2x2 subsampled UV planes*/ +#define ASVL_PAF_NV12 0x801 +/*8 bit Y plane followed by 8 bit 2x2 subsampled VU planes*/ +#define ASVL_PAF_NV21 0x802 +/*8 bit Y plane followed by 8 bit 2x1 subsampled UV planes*/ +#define ASVL_PAF_LPI422H 0x803 +/*8 bit Y plane followed by 8 bit 2x1 subsampled VU planes*/ +#define ASVL_PAF_LPI422H2 0x804 + +/*8 bit Y plane followed by 8 bit 4x4 subsampled VU planes*/ +#define ASVL_PAF_NV41 0x805 + +/*Negative UYVY, U0, Y0, V0, Y1*/ +#define ASVL_PAF_NEG_UYVY 0x901 +/*Negative I420, 8 bit Y plane followed by 8 bit 2x2 subsampled U and V planes*/ +#define ASVL_PAF_NEG_I420 0x902 + + +/*Mono UYVY, UV values are fixed, gray image in U0, Y0, V0, Y1*/ +#define ASVL_PAF_MONO_UYVY 0xa01 +/*Mono I420, UV values are fixed, 8 bit Y plane followed by 8 bit 2x2 subsampled U and V planes*/ +#define ASVL_PAF_MONO_I420 0xa02 + +/*P8_YUYV, 8 pixels a group, Y0Y1Y2Y3Y4Y5Y6Y7U0U1U2U3V0V1V2V3*/ +#define ASVL_PAF_P8_YUYV 0xb03 + +/*P16_YUYV, 16*16 pixels a group, Y0Y1Y2Y3...U0U1...V0V1...*/ +#define ASVL_PAF_SP16UNIT 0xc01 + +#define ASVL_PAF_DEPTH_U16 0xc02 + +/*10 bits RGGB CFA raw data, each data has 2 bytes*/ + + +#define ASVL_PAF_RAW10_RGGB_10B 0xd01 +#define ASVL_PAF_RAW10_GRBG_10B 0xd02 +#define ASVL_PAF_RAW10_GBRG_10B 0xd03 +#define ASVL_PAF_RAW10_BGGR_10B 0xd04 + +#define ASVL_PAF_RAW12_RGGB_12B 0xd05 +#define ASVL_PAF_RAW12_GRBG_12B 0xd06 +#define ASVL_PAF_RAW12_GBRG_12B 0xd07 +#define ASVL_PAF_RAW12_BGGR_12B 0xd08 + +#define ASVL_PAF_RAW10_RGGB_16B 0xd09 +#define ASVL_PAF_RAW10_GRBG_16B 0xd0A +#define ASVL_PAF_RAW10_GBRG_16B 0xd0B +#define ASVL_PAF_RAW10_BGGR_16B 0xd0C + +/*10 bits gray raw data*/ +#define ASVL_PAF_RAW10_GRAY_10B 0xe01 + +/*10 bits gray raw data, each data has 2 bytes*/ +#define ASVL_PAF_RAW10_GRAY_16B 0xe81 + + +/*Define the image format space*/ +typedef struct __tag_ASVL_OFFSCREEN +{ + MUInt32 u32PixelArrayFormat; + MInt32 i32Width; + MInt32 i32Height; + MUInt8* ppu8Plane[4]; + MInt32 pi32Pitch[4]; +}ASVLOFFSCREEN, *LPASVLOFFSCREEN; + +/*Define the SDK Version infos. This is the template!!!*/ +typedef struct __tag_ASVL_VERSION +{ + MLong lCodebase; // Codebase version number + MLong lMajor; // major version number + MLong lMinor; // minor version number + MLong lBuild; // Build version number, increasable only + const MChar *Version; // version in string form + const MChar *BuildDate; // latest build Date + const MChar *CopyRight; // copyright +}ASVL_VERSION; +const ASVL_VERSION *ASVL_GetVersion(); + +#ifdef __cplusplus +} +#endif + +#endif /*__ASVL_OFFSCREEN_H__*/ diff --git a/include/merror.h b/include/merror.h new file mode 100644 index 0000000..0bea508 --- /dev/null +++ b/include/merror.h @@ -0,0 +1,154 @@ +/*---------------------------------------------------------------------------------------------- +* +* This file is ArcSoft's property. It contains ArcSoft's trade secret, proprietary and +* confidential information. +* +* The information and code contained in this file is only for authorized ArcSoft employees +* to design, create, modify, or review. +* +* DO NOT DISTRIBUTE, DO NOT DUPLICATE OR TRANSMIT IN ANY FORM WITHOUT PROPER AUTHORIZATION. +* +* If you are not an intended recipient of this file, you must not copy, distribute, modify, +* or take any action in reliance on it. +* +* If you have received this file in error, please immediately notify ArcSoft and +* permanently delete the original and any copy of any file and any printout thereof. +* +*-------------------------------------------------------------------------------------------------*/ + + +#ifndef __MERROR_H__ +#define __MERROR_H__ + + +#define MERR_NONE (0) +#define MOK (0) + +#define MERR_BASIC_BASE 0X0001 //通用错误类型 +#define MERR_UNKNOWN MERR_BASIC_BASE //错误原因不明 +#define MERR_INVALID_PARAM (MERR_BASIC_BASE+1) //无效的参数 +#define MERR_UNSUPPORTED (MERR_BASIC_BASE+2) //引擎不支持 +#define MERR_NO_MEMORY (MERR_BASIC_BASE+3) //内存不足 +#define MERR_BAD_STATE (MERR_BASIC_BASE+4) //状态错误 +#define MERR_USER_CANCEL (MERR_BASIC_BASE+5) //用户取消相关操作 +#define MERR_EXPIRED (MERR_BASIC_BASE+6) //操作时间过期 +#define MERR_USER_PAUSE (MERR_BASIC_BASE+7) //用户暂停操作 +#define MERR_BUFFER_OVERFLOW (MERR_BASIC_BASE+8) //缓冲上溢 +#define MERR_BUFFER_UNDERFLOW (MERR_BASIC_BASE+9) //缓冲下溢 +#define MERR_NO_DISKSPACE (MERR_BASIC_BASE+10) //存贮空间不足 +#define MERR_COMPONENT_NOT_EXIST (MERR_BASIC_BASE+11) //组件不存在 +#define MERR_GLOBAL_DATA_NOT_EXIST (MERR_BASIC_BASE+12) //全局数据不存在 + +#define MERR_FSDK_BASE 0X7000 //Free SDK通用错误类型 +#define MERR_FSDK_INVALID_APP_ID (MERR_FSDK_BASE+1) //无效的App Id +#define MERR_FSDK_INVALID_SDK_ID (MERR_FSDK_BASE+2) //无效的SDK key +#define MERR_FSDK_INVALID_ID_PAIR (MERR_FSDK_BASE+3) //AppId和SDKKey不匹配 +#define MERR_FSDK_MISMATCH_ID_AND_SDK (MERR_FSDK_BASE+4) //SDKKey 和使用的SDK 不匹配 +#define MERR_FSDK_SYSTEM_VERSION_UNSUPPORTED (MERR_FSDK_BASE+5) //系统版本不被当前SDK所支持 +#define MERR_FSDK_LICENCE_EXPIRED (MERR_FSDK_BASE+6) //SDK有效期过期,需要重新下载更新 + +#define MERR_FSDK_APS_ERROR_BASE 0x11000 //PhotoStyling 错误类型 +#define MERR_FSDK_APS_ENGINE_HANDLE (MERR_FSDK_APS_ERROR_BASE+1) //引擎句柄非法 +#define MERR_FSDK_APS_MEMMGR_HANDLE (MERR_FSDK_APS_ERROR_BASE+2) //内存句柄非法 +#define MERR_FSDK_APS_DEVICEID_INVALID (MERR_FSDK_APS_ERROR_BASE+3) //Device ID 非法 +#define MERR_FSDK_APS_DEVICEID_UNSUPPORTED (MERR_FSDK_APS_ERROR_BASE+4) //Device ID 不支持 +#define MERR_FSDK_APS_MODEL_HANDLE (MERR_FSDK_APS_ERROR_BASE+5) //模板数据指针非法 +#define MERR_FSDK_APS_MODEL_SIZE (MERR_FSDK_APS_ERROR_BASE+6) //模板数据长度非法 +#define MERR_FSDK_APS_IMAGE_HANDLE (MERR_FSDK_APS_ERROR_BASE+7) //图像结构体指针非法 +#define MERR_FSDK_APS_IMAGE_FORMAT_UNSUPPORTED (MERR_FSDK_APS_ERROR_BASE+8) //图像格式不支持 +#define MERR_FSDK_APS_IMAGE_PARAM (MERR_FSDK_APS_ERROR_BASE+9) //图像参数非法 +#define MERR_FSDK_APS_IMAGE_SIZE (MERR_FSDK_APS_ERROR_BASE+10) //图像尺寸大小超过支持范围 +#define MERR_FSDK_APS_DEVICE_AVX2_UNSUPPORTED (MERR_FSDK_APS_ERROR_BASE+11) //处理器不支持AVX2指令 + +#define MERR_FSDK_FR_ERROR_BASE 0x12000 //Face Recognition错误类型 +#define MERR_FSDK_FR_INVALID_MEMORY_INFO (MERR_FSDK_FR_ERROR_BASE+1) //无效的输入内存 +#define MERR_FSDK_FR_INVALID_IMAGE_INFO (MERR_FSDK_FR_ERROR_BASE+2) //无效的输入图像参数 +#define MERR_FSDK_FR_INVALID_FACE_INFO (MERR_FSDK_FR_ERROR_BASE+3) //无效的脸部信息 +#define MERR_FSDK_FR_NO_GPU_AVAILABLE (MERR_FSDK_FR_ERROR_BASE+4) //当前设备无GPU可用 +#define MERR_FSDK_FR_MISMATCHED_FEATURE_LEVEL (MERR_FSDK_FR_ERROR_BASE+5) //待比较的两个人脸特征的版本不一致 + +#define MERR_FSDK_FACEFEATURE_ERROR_BASE 0x14000 //人脸特征检测错误类型 +#define MERR_FSDK_FACEFEATURE_UNKNOWN (MERR_FSDK_FACEFEATURE_ERROR_BASE+1) //人脸特征检测错误未知 +#define MERR_FSDK_FACEFEATURE_MEMORY (MERR_FSDK_FACEFEATURE_ERROR_BASE+2) //人脸特征检测内存错误 +#define MERR_FSDK_FACEFEATURE_INVALID_FORMAT (MERR_FSDK_FACEFEATURE_ERROR_BASE+3) //人脸特征检测格式错误 +#define MERR_FSDK_FACEFEATURE_INVALID_PARAM (MERR_FSDK_FACEFEATURE_ERROR_BASE+4) //人脸特征检测参数错误 +#define MERR_FSDK_FACEFEATURE_LOW_CONFIDENCE_LEVEL (MERR_FSDK_FACEFEATURE_ERROR_BASE+5) //人脸特征检测结果置信度低 +#define MERR_FSDK_FACEFEATURE_EXPIRED (MERR_FSDK_FACEFEATURE_ERROR_BASE+6) //人脸特征检测结果操作过期 +#define MERR_FSDK_FACEFEATURE_MISSFACE (MERR_FSDK_FACEFEATURE_ERROR_BASE+7) //人脸特征检测人脸丢失 +#define MERR_FSDK_FACEFEATURE_NO_FACE (MERR_FSDK_FACEFEATURE_ERROR_BASE+8) //人脸特征检测没有人脸 +#define MERR_FSDK_FACEFEATURE_FACEDATE (MERR_FSDK_FACEFEATURE_ERROR_BASE+9) //人脸特征检测人脸信息错误 + +#define MERR_ASF_EX_BASE 0x15000 //ASF错误类型 +#define MERR_ASF_EX_FEATURE_UNSUPPORTED_ON_INIT (MERR_ASF_EX_BASE+1) //Engine不支持的检测属性 +#define MERR_ASF_EX_FEATURE_UNINITED (MERR_ASF_EX_BASE+2) //需要检测的属性未初始化 +#define MERR_ASF_EX_FEATURE_UNPROCESSED (MERR_ASF_EX_BASE+3) //待获取的属性未在process中处理过 +#define MERR_ASF_EX_FEATURE_UNSUPPORTED_ON_PROCESS (MERR_ASF_EX_BASE+4) //PROCESS不支持的检测属性组合,例如FR,有自己独立的处理函数 +#define MERR_ASF_EX_INVALID_IMAGE_INFO (MERR_ASF_EX_BASE+5) //无效的输入图像 +#define MERR_ASF_EX_INVALID_FACE_INFO (MERR_ASF_EX_BASE+6) //无效的脸部信息 + + +#define MERR_ASF_BASE 0x16000 //人脸比对基础错误类型 +#define MERR_ASF_ACTIVATION_FAIL (MERR_ASF_BASE+1) //SDK激活失败,请打开读写权限 +#define MERR_ASF_ALREADY_ACTIVATED (MERR_ASF_BASE+2) //SDK已激活 +#define MERR_ASF_NOT_ACTIVATED (MERR_ASF_BASE+3) //SDK未激活 +#define MERR_ASF_SCALE_NOT_SUPPORT (MERR_ASF_BASE+4) //detectFaceScaleVal 不支持 +#define MERR_ASF_ACTIVEFILE_SDKTYPE_MISMATCH (MERR_ASF_BASE+5) //激活文件与SDK类型不匹配,请确认使用的sdk +#define MERR_ASF_DEVICE_MISMATCH (MERR_ASF_BASE+6) //设备不匹配 +#define MERR_ASF_UNIQUE_IDENTIFIER_ILLEGAL (MERR_ASF_BASE+7) //唯一标识不合法 +#define MERR_ASF_PARAM_NULL (MERR_ASF_BASE+8) //参数为空 +#define MERR_ASF_LIVENESS_EXPIRED (MERR_ASF_BASE+9) //活体已过期 +#define MERR_ASF_VERSION_NOT_SUPPORT (MERR_ASF_BASE+10) //版本不支持 +#define MERR_ASF_SIGN_ERROR (MERR_ASF_BASE+11) //签名错误 +#define MERR_ASF_DATABASE_ERROR (MERR_ASF_BASE+12) //激活信息保存异常 +#define MERR_ASF_UNIQUE_CHECKOUT_FAIL (MERR_ASF_BASE+13) //唯一标识符校验失败 +#define MERR_ASF_COLOR_SPACE_NOT_SUPPORT (MERR_ASF_BASE+14) //颜色空间不支持 +#define MERR_ASF_IMAGE_WIDTH_HEIGHT_NOT_SUPPORT (MERR_ASF_BASE+15) //图片宽高不支持,宽度需四字节对齐 + +#define MERR_ASF_BASE_EXTEND 0x16010 //人脸比对基础错误类型 +#define MERR_ASF_READ_PHONE_STATE_DENIED (MERR_ASF_BASE_EXTEND) //android.permission.READ_PHONE_STATE权限被拒绝 +#define MERR_ASF_ACTIVATION_DATA_DESTROYED (MERR_ASF_BASE_EXTEND+1) //激活数据被破坏,请删除激活文件,重新进行激活 +#define MERR_ASF_SERVER_UNKNOWN_ERROR (MERR_ASF_BASE_EXTEND+2) //服务端未知错误 +#define MERR_ASF_INTERNET_DENIED (MERR_ASF_BASE_EXTEND+3) //INTERNET权限被拒绝 +#define MERR_ASF_ACTIVEFILE_SDK_MISMATCH (MERR_ASF_BASE_EXTEND+4) //激活文件与SDK版本不匹配,请重新激活 +#define MERR_ASF_DEVICEINFO_LESS (MERR_ASF_BASE_EXTEND+5) //设备信息太少,不足以生成设备指纹 +#define MERR_ASF_LOCAL_TIME_NOT_CALIBRATED (MERR_ASF_BASE_EXTEND+6) //客户端时间与服务器时间(即北京时间)前后相差在30分钟以上 +#define MERR_ASF_APPID_DATA_DECRYPT (MERR_ASF_BASE_EXTEND+7) //数据校验异常 +#define MERR_ASF_APPID_APPKEY_SDK_MISMATCH (MERR_ASF_BASE_EXTEND+8) //传入的AppId和AppKey与使用的SDK版本不一致 +#define MERR_ASF_NO_REQUEST (MERR_ASF_BASE_EXTEND+9) //短时间大量请求会被禁止请求,30分钟之后解封 +#define MERR_ASF_ACTIVE_FILE_NO_EXIST (MERR_ASF_BASE_EXTEND+10) //激活文件不存在 +#define MERR_ASF_DETECT_MODEL_UNSUPPORTED (MERR_ASF_BASE_EXTEND+11) //检测模型不支持,请查看对应接口说明,使用当前支持的检测模型 +#define MERR_ASF_CURRENT_DEVICE_TIME_INCORRECT (MERR_ASF_BASE_EXTEND+12) //当前设备时间不正确,请调整设备时间 +#define MERR_ASF_ACTIVATION_QUANTITY_OUT_OF_LIMIT (MERR_ASF_BASE_EXTEND+13) //年度激活数量超出限制,次年清零 + +#define MERR_ASF_NETWORK_BASE 0x17000 //网络错误类型 +#define MERR_ASF_NETWORK_COULDNT_RESOLVE_HOST (MERR_ASF_NETWORK_BASE+1) //无法解析主机地址 +#define MERR_ASF_NETWORK_COULDNT_CONNECT_SERVER (MERR_ASF_NETWORK_BASE+2) //无法连接服务器 +#define MERR_ASF_NETWORK_CONNECT_TIMEOUT (MERR_ASF_NETWORK_BASE+3) //网络连接超时 +#define MERR_ASF_NETWORK_UNKNOWN_ERROR (MERR_ASF_NETWORK_BASE+4) //网络未知错误 + +#define MERR_ASF_ACTIVEKEY_BASE 0x18000 //激活码错误类型 +#define MERR_ASF_ACTIVEKEY_COULDNT_CONNECT_SERVER (MERR_ASF_ACTIVEKEY_BASE+1) //无法连接激活服务器 +#define MERR_ASF_ACTIVEKEY_SERVER_SYSTEM_ERROR (MERR_ASF_ACTIVEKEY_BASE+2) //服务器系统错误 +#define MERR_ASF_ACTIVEKEY_POST_PARM_ERROR (MERR_ASF_ACTIVEKEY_BASE+3) //请求参数错误 +#define MERR_ASF_ACTIVEKEY_PARM_MISMATCH (MERR_ASF_ACTIVEKEY_BASE+4) //ACTIVEKEY与APPID、SDKKEY不匹配 +#define MERR_ASF_ACTIVEKEY_ACTIVEKEY_ACTIVATED (MERR_ASF_ACTIVEKEY_BASE+5) //ACTIVEKEY已经被使用 +#define MERR_ASF_ACTIVEKEY_ACTIVEKEY_FORMAT_ERROR (MERR_ASF_ACTIVEKEY_BASE+6) //ACTIVEKEY信息异常 +#define MERR_ASF_ACTIVEKEY_APPID_PARM_MISMATCH (MERR_ASF_ACTIVEKEY_BASE+7) //ACTIVEKEY与APPID不匹配 +#define MERR_ASF_ACTIVEKEY_SDK_FILE_MISMATCH (MERR_ASF_ACTIVEKEY_BASE+8) //SDK与激活文件版本不匹配 +#define MERR_ASF_ACTIVEKEY_EXPIRED (MERR_ASF_ACTIVEKEY_BASE+9) //ACTIVEKEY已过期 +#define MERR_ASF_ACTIVEKEY_DEVICE_OUT_OF_LIMIT (MERR_ASF_ACTIVEKEY_BASE+10) //批量授权激活码设备数超过限制 + + +#define MERR_ASF_OFFLINE_BASE 0x19000 //离线激活错误码类型 +#define MERR_ASF_LICENSE_FILE_NOT_EXIST (MERR_ASF_OFFLINE_BASE+1) //离线授权文件不存在或无读写权限 +#define MERR_ASF_LICENSE_FILE_DATA_DESTROYED (MERR_ASF_OFFLINE_BASE+2) //离线授权文件已损坏 +#define MERR_ASF_LICENSE_FILE_SDK_MISMATCH (MERR_ASF_OFFLINE_BASE+3) //离线授权文件与SDK版本不匹配 +#define MERR_ASF_LICENSE_FILEINFO_SDKINFO_MISMATCH (MERR_ASF_OFFLINE_BASE+4) //离线授权文件与SDK信息不匹配 +#define MERR_ASF_LICENSE_FILE_FINGERPRINT_MISMATCH (MERR_ASF_OFFLINE_BASE+5) //离线授权文件与设备指纹不匹配 +#define MERR_ASF_LICENSE_FILE_EXPIRED (MERR_ASF_OFFLINE_BASE+6) //离线授权文件已过期 +#define MERR_ASF_LOCAL_EXIST_USEFUL_ACTIVE_FILE (MERR_ASF_OFFLINE_BASE+7) //离线授权文件不可用,本地原有激活文件可继续使用 +#define MERR_ASF_LICENSE_FILE_VERSION_TOO_LOW (MERR_ASF_OFFLINE_BASE+8) //离线授权文件版本过低,请使用新版本激活助手重新进行离线激活 + + +#endif + diff --git a/mask.jpg b/mask.jpg new file mode 100644 index 0000000..53e0b3b Binary files /dev/null and b/mask.jpg differ diff --git a/util/image_util.go b/util/image_util.go new file mode 100644 index 0000000..4c975cc --- /dev/null +++ b/util/image_util.go @@ -0,0 +1,634 @@ +package util + +import ( + "fmt" + "math" + "os" + "runtime" + + _ "image/jpeg" + _ "image/png" + + "image" + "image/color" +) + +type resamplingFilter struct { + Support float64 + Kernel func(float64) float64 +} + +// GetImageHeight 获取图片高度 +func GetImageHeight(img image.Image) int { + return img.Bounds().Max.Y +} + +// GetImageWidth 获取图片宽度 +func GetImageWidth(img image.Image) int { + return img.Bounds().Max.X +} + +// DecodeImage decode a image and retrun golang image interface +func DecodeImage(filePath string) (img image.Image, err error) { + reader, err := os.Open(filePath) + if err != nil { + return nil, err + } + defer reader.Close() + + img, _, err = image.Decode(reader) + + return +} + +// NewRGBAMatrix create a new rgba matrix +func NewRGBAMatrix(height int, width int) (rgbaMatrix [][][]uint8) { + rgbaMatrix = New3DSlice(height, width, 4) + return +} + +// ImageInfo 包含图片数据和宽高信息的结构体 +type ImageInfo struct { + DataUInt8 []uint8 + Width int + Height int +} + +// GetResizedImageInfo 获取适配SDK大小的图片,并转为BGR格式的数据 +func GetResizedImageInfo(filename string) (imageInfo ImageInfo) { + img, err := DecodeImage(filename) + if err != nil { + fmt.Printf("%v\n", err) + } + height := GetImageHeight(img) + width := GetImageWidth(img) + newWidth := width - width%4 + imgMatrix, err := ResizeForMatrix(filename, newWidth, height) + if err != nil { + panic(err) + } + var bgrData []uint8 + for starty := 0; starty < height; starty++ { + for startx := 0; startx < newWidth; startx++ { + R := imgMatrix[starty][startx][0] + G := imgMatrix[starty][startx][1] + B := imgMatrix[starty][startx][2] + bgrData = append(bgrData, B, G, R) + } + } + return ImageInfo{bgrData, width, height} +} + +// GetImageWidthAndHeight 获取图片宽高 +func GetImageWidthAndHeight(filename string) (width, height int) { + img, err := DecodeImage(filename) + if err != nil { + return 0, 0 + } + return GetImageWidth(img), GetImageHeight(img) +} + +// ResizeForMatrix 缩放图片 +func ResizeForMatrix(filepath string, width int, height int) (imgMatrix [][][]uint8, err error) { + img, err1 := DecodeImage(filepath) + + if err1 != nil { + err = err1 + return + } + + nrgba := convertToNRGBA(img) + src := Resize(nrgba, width, height) + + imgMatrix = NewRGBAMatrix(height, width) + + for i := 0; i < height; i++ { + for j := 0; j < width; j++ { + c := src.At(j, i) + r, g, b, a := c.RGBA() + imgMatrix[i][j][0] = uint8(r) + imgMatrix[i][j][1] = uint8(g) + imgMatrix[i][j][2] = uint8(b) + imgMatrix[i][j][3] = uint8(a) + + } + } + + return +} + +// Resize 缩放图片 +func Resize(src *image.NRGBA, width int, height int) *image.NRGBA { + dstW, dstH := width, height + + if dstW < 0 || dstH < 0 { + return src + } + if dstW == 0 && dstH == 0 { + return src + } + + srcW := src.Rect.Max.X + srcH := src.Rect.Max.Y + + if srcW <= 0 || srcH <= 0 { + return src + } + + // if new width or height is 0 then preserve aspect ratio, minimum 1px + if dstW == 0 { + tmpW := float64(dstH) * float64(srcW) / float64(srcH) + dstW = int(math.Max(1.0, math.Floor(tmpW+0.5))) + } + if dstH == 0 { + tmpH := float64(dstW) * float64(srcH) / float64(srcW) + dstH = int(math.Max(1.0, math.Floor(tmpH+0.5))) + } + + var dst *image.NRGBA + + var sinc = func(x float64) float64 { + if x == 0 { + return 1 + } + return math.Sin(math.Pi*x) / (math.Pi * x) + } + + var filter resamplingFilter = resamplingFilter{ + Support: 3.0, + Kernel: func(x float64) float64 { + x = math.Abs(x) + if x < 3.0 { + return sinc(x) * sinc(x/3.0) + } + return 0 + }, + } + + if filter.Support <= 0.0 { + // nearest-neighbor special case + dst = resizeNearest(src, dstW, dstH) + + } else { + // two-pass resize + if srcW != dstW { + dst = resizeHorizontal(src, dstW, filter) + } else { + dst = src + } + + if srcH != dstH { + dst = resizeVertical(dst, dstH, filter) + } + } + + return dst +} + +//convert image to NRGBA +func convertToNRGBA(src image.Image) *image.NRGBA { + srcBounds := src.Bounds() + dstBounds := srcBounds.Sub(srcBounds.Min) + + dst := image.NewNRGBA(dstBounds) + + dstMinX := dstBounds.Min.X + dstMinY := dstBounds.Min.Y + + srcMinX := srcBounds.Min.X + srcMinY := srcBounds.Min.Y + srcMaxX := srcBounds.Max.X + srcMaxY := srcBounds.Max.Y + + switch src0 := src.(type) { + + case *image.NRGBA: + rowSize := srcBounds.Dx() * 4 + numRows := srcBounds.Dy() + + i0 := dst.PixOffset(dstMinX, dstMinY) + j0 := src0.PixOffset(srcMinX, srcMinY) + + di := dst.Stride + dj := src0.Stride + + for row := 0; row < numRows; row++ { + copy(dst.Pix[i0:i0+rowSize], src0.Pix[j0:j0+rowSize]) + i0 += di + j0 += dj + } + + case *image.NRGBA64: + i0 := dst.PixOffset(dstMinX, dstMinY) + for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride { + for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 { + + j := src0.PixOffset(x, y) + + dst.Pix[i+0] = src0.Pix[j+0] + dst.Pix[i+1] = src0.Pix[j+2] + dst.Pix[i+2] = src0.Pix[j+4] + dst.Pix[i+3] = src0.Pix[j+6] + + } + } + + case *image.RGBA: + i0 := dst.PixOffset(dstMinX, dstMinY) + for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride { + for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 { + + j := src0.PixOffset(x, y) + a := src0.Pix[j+3] + dst.Pix[i+3] = a + + switch a { + case 0: + dst.Pix[i+0] = 0 + dst.Pix[i+1] = 0 + dst.Pix[i+2] = 0 + case 0xff: + dst.Pix[i+0] = src0.Pix[j+0] + dst.Pix[i+1] = src0.Pix[j+1] + dst.Pix[i+2] = src0.Pix[j+2] + default: + dst.Pix[i+0] = uint8(uint16(src0.Pix[j+0]) * 0xff / uint16(a)) + dst.Pix[i+1] = uint8(uint16(src0.Pix[j+1]) * 0xff / uint16(a)) + dst.Pix[i+2] = uint8(uint16(src0.Pix[j+2]) * 0xff / uint16(a)) + } + } + } + + case *image.RGBA64: + i0 := dst.PixOffset(dstMinX, dstMinY) + for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride { + for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 { + + j := src0.PixOffset(x, y) + a := src0.Pix[j+6] + dst.Pix[i+3] = a + + switch a { + case 0: + dst.Pix[i+0] = 0 + dst.Pix[i+1] = 0 + dst.Pix[i+2] = 0 + case 0xff: + dst.Pix[i+0] = src0.Pix[j+0] + dst.Pix[i+1] = src0.Pix[j+2] + dst.Pix[i+2] = src0.Pix[j+4] + default: + dst.Pix[i+0] = uint8(uint16(src0.Pix[j+0]) * 0xff / uint16(a)) + dst.Pix[i+1] = uint8(uint16(src0.Pix[j+2]) * 0xff / uint16(a)) + dst.Pix[i+2] = uint8(uint16(src0.Pix[j+4]) * 0xff / uint16(a)) + } + } + } + + case *image.Gray: + i0 := dst.PixOffset(dstMinX, dstMinY) + for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride { + for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 { + + j := src0.PixOffset(x, y) + c := src0.Pix[j] + dst.Pix[i+0] = c + dst.Pix[i+1] = c + dst.Pix[i+2] = c + dst.Pix[i+3] = 0xff + + } + } + + case *image.Gray16: + i0 := dst.PixOffset(dstMinX, dstMinY) + for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride { + for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 { + + j := src0.PixOffset(x, y) + c := src0.Pix[j] + dst.Pix[i+0] = c + dst.Pix[i+1] = c + dst.Pix[i+2] = c + dst.Pix[i+3] = 0xff + + } + } + + case *image.YCbCr: + i0 := dst.PixOffset(dstMinX, dstMinY) + for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride { + for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 { + + yj := src0.YOffset(x, y) + cj := src0.COffset(x, y) + r, g, b := color.YCbCrToRGB(src0.Y[yj], src0.Cb[cj], src0.Cr[cj]) + + dst.Pix[i+0] = r + dst.Pix[i+1] = g + dst.Pix[i+2] = b + dst.Pix[i+3] = 0xff + + } + } + + default: + i0 := dst.PixOffset(dstMinX, dstMinY) + for y := srcMinY; y < srcMaxY; y, i0 = y+1, i0+dst.Stride { + for x, i := srcMinX, i0; x < srcMaxX; x, i = x+1, i+4 { + + c := color.NRGBAModel.Convert(src.At(x, y)).(color.NRGBA) + + dst.Pix[i+0] = c.R + dst.Pix[i+1] = c.G + dst.Pix[i+2] = c.B + dst.Pix[i+3] = c.A + + } + } + } + + return dst +} + +func resizeHorizontal(src *image.NRGBA, width int, filter resamplingFilter) *image.NRGBA { + srcBounds := src.Bounds() + srcW := srcBounds.Dx() + srcH := srcBounds.Dy() + srcMinX := srcBounds.Min.X + srcMinY := srcBounds.Min.Y + srcMaxX := srcBounds.Max.X + + dstW := width + dstH := srcH + + dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) + + dX := float64(srcW) / float64(dstW) + scaleX := math.Max(dX, 1.0) + rX := math.Ceil(scaleX * filter.Support) + + // divide image to parts for parallel processing + numGoroutines := runtime.NumCPU() + goMaxProcs := runtime.GOMAXPROCS(0) + if numGoroutines > goMaxProcs { + numGoroutines = goMaxProcs + } + if numGoroutines > dstW { + numGoroutines = dstW + } + partSize := dstW / numGoroutines + + doneChan := make(chan bool, numGoroutines) + + for part := 0; part < numGoroutines; part++ { + partStart := part * partSize + partEnd := (part + 1) * partSize + if part == numGoroutines-1 { + partEnd = dstW + } + + go func(partStart, partEnd int) { + + for dstX := partStart; dstX < partEnd; dstX++ { + fX := float64(srcMinX) + (float64(dstX)+0.5)*dX - 0.5 + + startX := int(math.Ceil(fX - rX)) + if startX < srcMinX { + startX = srcMinX + } + endX := int(math.Floor(fX + rX)) + if endX > srcMaxX-1 { + endX = srcMaxX - 1 + } + + // cache weights + weightSum := 0.0 + weights := make([]float64, int(rX+2)*2) + for x := startX; x <= endX; x++ { + w := filter.Kernel((float64(x) - fX) / scaleX) + weightSum += w + weights[x-startX] = w + } + + for dstY := 0; dstY < dstH; dstY++ { + srcY := srcMinY + dstY + + r, g, b, a := 0.0, 0.0, 0.0, 0.0 + for x := startX; x <= endX; x++ { + weight := weights[x-startX] + i := src.PixOffset(x, srcY) + r += float64(src.Pix[i+0]) * weight + g += float64(src.Pix[i+1]) * weight + b += float64(src.Pix[i+2]) * weight + a += float64(src.Pix[i+3]) * weight + } + + r = math.Min(math.Max(r/weightSum, 0.0), 255.0) + g = math.Min(math.Max(g/weightSum, 0.0), 255.0) + b = math.Min(math.Max(b/weightSum, 0.0), 255.0) + a = math.Min(math.Max(a/weightSum, 0.0), 255.0) + + j := dst.PixOffset(dstX, dstY) + dst.Pix[j+0] = uint8(r + 0.5) + dst.Pix[j+1] = uint8(g + 0.5) + dst.Pix[j+2] = uint8(b + 0.5) + dst.Pix[j+3] = uint8(a + 0.5) + } + } + + doneChan <- true + }(partStart, partEnd) + + } + + // wait for goroutines to finish + for part := 0; part < numGoroutines; part++ { + <-doneChan + } + + return dst +} + +func resizeVertical(src *image.NRGBA, height int, filter resamplingFilter) *image.NRGBA { + srcBounds := src.Bounds() + srcW := srcBounds.Dx() + srcH := srcBounds.Dy() + srcMinX := srcBounds.Min.X + srcMinY := srcBounds.Min.Y + srcMaxY := srcBounds.Max.Y + + dstW := srcW + dstH := height + + dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) + + dY := float64(srcH) / float64(dstH) + scaleY := math.Max(dY, 1.0) + rY := math.Ceil(scaleY * filter.Support) + + // divide image to parts for parallel processing + numGoroutines := runtime.NumCPU() + goMaxProcs := runtime.GOMAXPROCS(0) + if numGoroutines > goMaxProcs { + numGoroutines = goMaxProcs + } + if numGoroutines > dstH { + numGoroutines = dstH + } + partSize := dstH / numGoroutines + + doneChan := make(chan bool, numGoroutines) + + for part := 0; part < numGoroutines; part++ { + partStart := part * partSize + partEnd := (part + 1) * partSize + if part == numGoroutines-1 { + partEnd = dstH + } + + go func(partStart, partEnd int) { + + for dstY := partStart; dstY < partEnd; dstY++ { + fY := float64(srcMinY) + (float64(dstY)+0.5)*dY - 0.5 + + startY := int(math.Ceil(fY - rY)) + if startY < srcMinY { + startY = srcMinY + } + endY := int(math.Floor(fY + rY)) + if endY > srcMaxY-1 { + endY = srcMaxY - 1 + } + + // cache weights + weightSum := 0.0 + weights := make([]float64, int(rY+2)*2) + for y := startY; y <= endY; y++ { + w := filter.Kernel((float64(y) - fY) / scaleY) + weightSum += w + weights[y-startY] = w + } + + for dstX := 0; dstX < dstW; dstX++ { + srcX := srcMinX + dstX + + r, g, b, a := 0.0, 0.0, 0.0, 0.0 + for y := startY; y <= endY; y++ { + weight := weights[y-startY] + i := src.PixOffset(srcX, y) + r += float64(src.Pix[i+0]) * weight + g += float64(src.Pix[i+1]) * weight + b += float64(src.Pix[i+2]) * weight + a += float64(src.Pix[i+3]) * weight + } + + r = math.Min(math.Max(r/weightSum, 0.0), 255.0) + g = math.Min(math.Max(g/weightSum, 0.0), 255.0) + b = math.Min(math.Max(b/weightSum, 0.0), 255.0) + a = math.Min(math.Max(a/weightSum, 0.0), 255.0) + + j := dst.PixOffset(dstX, dstY) + dst.Pix[j+0] = uint8(r + 0.5) + dst.Pix[j+1] = uint8(g + 0.5) + dst.Pix[j+2] = uint8(b + 0.5) + dst.Pix[j+3] = uint8(a + 0.5) + } + } + + doneChan <- true + }(partStart, partEnd) + + } + + // wait for goroutines to finish + for part := 0; part < numGoroutines; part++ { + <-doneChan + } + + return dst +} + +// fast nearest-neighbor resize, no filtering +func resizeNearest(src *image.NRGBA, width, height int) *image.NRGBA { + dstW, dstH := width, height + + srcBounds := src.Bounds() + srcW := srcBounds.Dx() + srcH := srcBounds.Dy() + srcMinX := srcBounds.Min.X + srcMinY := srcBounds.Min.Y + srcMaxX := srcBounds.Max.X + srcMaxY := srcBounds.Max.Y + + dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) + + dx := float64(srcW) / float64(dstW) + dy := float64(srcH) / float64(dstH) + + // divide image to parts for parallel processing + numGoroutines := runtime.NumCPU() + goMaxProcs := runtime.GOMAXPROCS(0) + if numGoroutines > goMaxProcs { + numGoroutines = goMaxProcs + } + if numGoroutines > dstH { + numGoroutines = dstH + } + partSize := dstH / numGoroutines + + doneChan := make(chan bool, numGoroutines) + + for part := 0; part < numGoroutines; part++ { + partStart := part * partSize + partEnd := (part + 1) * partSize + if part == numGoroutines-1 { + partEnd = dstH + } + + go func(partStart, partEnd int) { + + for dstY := partStart; dstY < partEnd; dstY++ { + fy := float64(srcMinY) + (float64(dstY)+0.5)*dy - 0.5 + + for dstX := 0; dstX < dstW; dstX++ { + fx := float64(srcMinX) + (float64(dstX)+0.5)*dx - 0.5 + + srcX := int(math.Min(math.Max(math.Floor(fx+0.5), float64(srcMinX)), float64(srcMaxX))) + srcY := int(math.Min(math.Max(math.Floor(fy+0.5), float64(srcMinY)), float64(srcMaxY))) + + srcOffset := src.PixOffset(srcX, srcY) + dstOffset := dst.PixOffset(dstX, dstY) + + dst.Pix[dstOffset+0] = src.Pix[srcOffset+0] + dst.Pix[dstOffset+1] = src.Pix[srcOffset+1] + dst.Pix[dstOffset+2] = src.Pix[srcOffset+2] + dst.Pix[dstOffset+3] = src.Pix[srcOffset+3] + } + } + + doneChan <- true + }(partStart, partEnd) + } + + // wait for goroutines to finish + for part := 0; part < numGoroutines; part++ { + <-doneChan + } + + return dst +} + +// New3DSlice 创建矩阵 +func New3DSlice(x int, y int, z int) (theSlice [][][]uint8) { + theSlice = make([][][]uint8, x, x) + for i := 0; i < x; i++ { + s2 := make([][]uint8, y, y) + for j := 0; j < y; j++ { + s3 := make([]uint8, z, z) + s2[j] = s3 + } + theSlice[i] = s2 + } + return +}