由于本地有一大批数据需要处理,虽然百度开放了在线人脸识别接口,但实际测试,10个QPS+50M上行带宽,仅仅三十多万张图就花了40小时左右, 后面还有大量的视频,抽帧检测更是难搞,因此申请离线识别SDK走起。。。。
狗血的是,百度的人脸识别SDK分为两种,离线采集(仅支持移动端)和离线识别,还有单设备90天和5台设备的限制,(吐槽归吐槽,后面还是得掏钱买的,还TM一百个授权码起购。。。)
到下载页面一看,傻眼了,没有python版本的,只有Java和C++.
我的java就是入了门,直接搞kotlin+Android(当然也是非常烂); C++就更不用说了,就会写个hello world
于是我萌生了一个大胆的想法——python调用Java!!!
正文
一、环境配置
python3.7
依赖库:pyjnius
jdk18
亲测此版本可用
不要问我为什么用这么新的jdk,因为我找不到当时的安装路径了,懒得找了,直接现场下。
python 仅仅需要 pip install pyjnius
即可食用。
二、jnius使用
理论上,应该下载C++版本的,直接编译成dll与python供python调用是最完美的方案,无奈我看不懂。
因此调用流程就是:python 调用 java , java在调用dll,然后再通过java传递给python。
jnius用法很简单,但有点小坑,因此我直接简单封装了个jvm
包,方便以后使用。
如果要修改jvm的封装,请注意: 导入顺序千万不能错,先配置环境变量,再调用jnius_config
, 最后再导入autoclass
,因为autoclass导入后,虚拟机已经启动了,再配置jnius_config
就不生效了(当然也有解决方案,但不做赘述,能跑就行)
# jvm.__init__.py
import os
import jnius_config
env = []
jar2classPaths = []
def run():
os.environ['path'] = ';'.join(env)
jnius_config.add_classpath(*jar2classPaths)
# jvm.com.py
# 可以在这个文件中定义一些常用的Java类的映射与类型标注,方便IDE进行代码提示。
from jnius import autoclass
class __System:
@staticmethod
def getProperty(key: str) -> str: ...
@staticmethod
def loadLibrary(name: str) -> str: ...
@staticmethod
def load(path: str) -> str: ...
class out:
def println(self, *args): ...
System: __System = autoclass("java.lang.System")
# main.py
# 运行测试
import jvm
# --- jvm初始化 ---
jvm.env.extend([
r"C:\Program Files\Java\jdk-18\bin\server", # jvm地址
# 各种dll路径,我将相关的dll全部复制到这个目录了,也可以直接填百度SDK的主目录
r"E:\projects\Python\tempitem\mada_emotion\lib"])
jvm.jar2classPaths.extend([
r"E:\projects\kotlin\BaiduFaceSDK\bin", # java编译后的目录
# jar包, 如果有其他依赖,继续往这儿加,本质上都是.class文件
r"E:\projects\Python\tempitem\mada_emotion\lib\opencv-320"])
jvm.run()
# --- jvm初始化完成 ---
# 尝试初始化百度SDK的Face类
api = autoclass("com.jni.face.Face")()
print(api.sdkInit("xxxxx")) # 初始化成功返回0
至此,就可以勉强使用了
三、BaiduFaceSDK 封装
可是,作为有强迫症的我,没有代码提示简直没法下手敲,因此,肝了一小时,拿去用吧各位,不用谢。共三个文件,封装成了baiduFaceSDK,后面打包整理传github再更新。
# baiduFaceSDK.__init__.py
from jnius import autoclass
from result import *
class Api:
def __new__(cls, **kwargs):
return autoclass("com.jni.face.Face")()
def __init__(self): ...
def readImage(self, f: Union[bytes, bytearray]) -> Mat: ...
def sdkInit(self, modelPath) -> int: ...
def sdkDestroy(self): ...
def isAuth(self) -> bool: ...
def getDeviceId(self) -> str: ...
def sdkVersion(self) -> str: ...
def detect(self, addr: int, _type: int) -> detectResult: ...
def track(self, addr: int, _type: int) -> trackResult: ...
def clearTrackHistory(self) -> int:
def faceAttr(self, addr: int) -> faceAttrResult: ...
def faceEyeClose(self, addr: int) -> faceEyeCloseResult: ...
def faceGaze(self, addr: int) -> faceGazeResult: ...
def faceHeadPose(self, addr: int) -> faceHeadPoseResult: ...
def faceIllumination(self, addr: int) -> List[int]: ...
def faceBlur(self, addr: int) -> List[float]: ...
def faceMouthClose(self, addr: int) -> List[float]: ...
def faceMouthMask(self, addr: int) -> List[float]: ...
def faceOcclusion(self, addr: int) -> faceOcclusionResult: ...
def darkEnhance(self, in_addr: int, out_addr: int) -> int: ...
def faceCrop(self, in_addr: int, out_addr: int) -> int: ...
def faceBest(self, addr: int) -> List[float]: ...
def faceLandmark(self, addr: int) -> faceLandmarkResult: ...
def faceActionLive(self, addr: int, actionType: int, actionResult: List[int]) -> faceActionLiveResult: ...
def clearActionLiveHistory(self) -> int: ...
def faceFeature(self, addr: int, _type: int) -> faceFeatureResult: ...
def livenessFeature(self, addr: int, _type: int) -> livenessFeatureResult: ...
def match(self, addr1: int, addr2: int, _type: int) -> int: ...
def compareFeature(self, f1: Feature, f2: Feature, _type: int) -> float: ...
def rgbLiveness(self, addr: int) -> rgbLivenessResult: ...
def userAddByMat(self, addr: int, userId: str, groupId: str, userInfo: str) -> str: ...
def userAdd(self, fea: Feature, userId: str, groupId: str, userInfo: str) -> str: ...
def userUpdate(self, addr: int, userId: str, groupId: str, userInfo: str) -> str: ...
def userDelete(self, userId: str, groupId: str) -> str: ...
def groupAdd(self, groupId: str) -> str: ...
def groupDelete(self, groupId: str) -> str: ...
def getUserInfo(self, userId: str, groupId: str) -> str: ...
def getUserImage(self, out_addr: int, userId: str, groupId: str) -> int: ...
def getUserList(self, groupId: str, start: int, length: int) -> str: ...
def getGroupList(self, start: int, length: int) -> str: ...
def dbFaceCount(self, groupId: str) -> int: ...
def identifyByMat(self, addr: int, groupIdList: str, userId: str, _type: int)-> str: ...
def identify(self, fea: Feature, groupIdList: str, userId: str, _type: int) -> str: ...
def identifyWithAllByMat(self, addr: int, _type: int) -> str: ...
def identifyWithAll(self, fea: Feature, _type: int) -> str: ...
def loadDbFace(self) -> bool: ...
# baiduFaceSDK.result.py
# 定义接口的返回值,并做类型标注,即使是列表遍历之后Pycharm也会提示关键字,舒服!!!
from structs import *
class Mat:
def release(self): ...
def getNativeObjAddr(self) -> float: ...
class detectResult(list):
def __getitem__(self, i) -> FaceBox: ...
def __iter__(self) -> List[FaceBox]: ...
class trackResult(list):
def __getitem__(self, i) -> TrackFaceInfo: ...
def __iter__(self) -> List[TrackFaceInfo]: ...
class faceAttrResult(list):
def __getitem__(self, i) -> Attribute: ...
def __iter__(self) -> List[Attribute]: ...
class faceEyeCloseResult(list):
def __getitem__(self, i) -> EyeClose: ...
def __iter__(self) -> List[EyeClose]: ...
class faceGazeResult(list):
def __getitem__(self, item) -> GazeInfo: ...
def __iter__(self) -> List[GazeInfo]: ...
class faceHeadPoseResult(list):
def __getitem__(self, item) -> HeadPose: ...
def __iter__(self) -> List[HeadPose]: ...
class faceOcclusionResult(list):
def __getitem__(self, item) -> Occlusion: ...
def __iter__(self) -> List[Occlusion]: ...
class faceLandmarkResult(list):
def __getitem__(self, item) -> Landmarks: ...
def __iter__(self) -> List[Landmarks]: ...
class faceActionLiveResult(list):
def __getitem__(self, item) -> FaceBox: ...
def __iter__(self) -> List[FaceBox]: ...
class faceFeatureResult(list):
def __getitem__(self, item) -> FeatureInfo: ...
def __iter__(self) -> List[FeatureInfo]: ...
class livenessFeatureResult(list):
def __getitem__(self, item) -> LiveFeatureInfo: ...
def __iter__(self) -> List[LiveFeatureInfo]: ...
class rgbLivenessResult(list):
def __getitem__(self, item) -> LivenessInfo: ...
def __iter__(self) -> List[LivenessInfo]: ...
# baiduFaceSDK.structs.py
# 定义的结构体
from typing import List
class Attribute:
age: int
race: int # 0:黄种人 1:白种人 2:黑种人 3:印第安人
emotion: int # 0:皱眉 1:笑 2:平静
glasses: int # 0:无眼镜 1:有眼镜 2:墨镜
gender: int # 0:女性 1:男性
class CropFaceConf:
isFlat: int # 是否镜像
cropSize: int # 抠图大小
enlargeRatio: int # 抠图倍数
class EyeClose: # 双眼闭合置信度
leftEyeCloseConf: float
rightEyeCloseConf: float
class FaceBox:
index: int
centerx: float
centery: float
width: float
height: float
angle: float
score: float
class Feature:
size: int
data: bytes
class FeatureInfo:
feature: Feature
face: FaceBox
class GazeInfo: # 注意力信息
leftEyeDirection: int # 左眼凝视方向 0:向上看 1:向下看 2:向右看 3:向左看 4:向前看 5:闭眼
leftEyeConf: float # 置信度
rightEyeDirection: int # 右眼凝视方向 0:向上看 1:向下看 2:向右看 3:向左看 4:向前看 5:闭眼
rightEyeConf: float # 置信度
class HeadPose:
yaw: float # 水平转动
roll: float # 左右倾斜
pitch: float # 抬头低头
class Landmarks:
index: int # 关键点索引
size: int
data: List[float] # 关键点数据,144个点,72个x,y坐标
score: float # 关键点分值
class LiveFeatureInfo:
feature: Feature # 特征值
box: FaceBox # 人脸框
score: float # 活体分值
class TrackFaceInfo:
faceId: int
box: FaceBox
land: Landmarks
class LivenessInfo:
trackinfo: TrackFaceInfo
livescore: float
class Occlusion:
leftEye: float
rightEye: float
nose: float
mouth: float
leftCheek: float
rightCheek: float
chin: float
class RgbDepthInfo:
trackinfo: TrackFaceInfo
rgbscore: float
depthscore: float