赞
踩
开放API接口协议和SDK二次开放的人脸识别摄像头
摄像头在中国是非常成熟的产品,整个行业趋于垄断和封闭的状态,要找到一款能方便整合到自己系统的摄像头是非常不容易的事情.
OPCOL是一款AI智能的开放API接口和SDK二次开发的人脸识别摄像头。可以非常轻松的接入的已有的业务系统中。
它有如下特点:
不支持判断是否活体检测
API详细说明链接
https://gitee.com/imlsq/pubdoc/blob/master/opcolv300.md
实物图
API介绍
设备提供如下3种途径集成到第三应用
TTP方式提供基本的,最简单的对接方式
通过http访问设备的请求需要加上签名安全认证码,以确定合法来源.url格式如下
http://${ip}:${port}/xxx?sign=${xxx}&token=请求令牌,创建一个随机UUID
* | 类型 | 说明 |
---|---|---|
ip | string | 设备IP地址(参考内网搜索设备获取ip) |
sign | string | 签名串,token+key组合md5算法之后16进制字符串(32位) key请参考下面如何签名KEY的说明 |
token | string | 请求令牌,客户端每次请求创建一个新的uuid,token不能重复使用 |
用户名和密码登录验证之后会返回md5签名key。
/api/login
method:post
Content-Type: application/json
Request body:
{"username":"admin","password":"xxxx"}
* | 类型 | 说明 |
---|---|---|
username | string | 用户名固定admin |
password | string | 密码 |
这个url请求无需签名,主机验证用户名和密码之后会返回签名md5 key,后续url请求用这个md5 key进行签名访问
返回结构
- {
- "code": 20000,
- "data": {
- "accessKey": "xxxxx"
- }
- }
* | 类型 | 说明 |
---|---|---|
code | string | 20000,设备有处理请求 |
accessKey | string | 签名KEY,后续请求用这个md5 key签名访问 可以把这个key缓存在应用端,设备重置操作KEY会变化 |
/api/set_password?old_password=x&new_password=x
method:get
请求参数:
* | 类型 | 说明 |
---|---|---|
old_password | string | 密码 |
new_password | string | 新密码 |
/api/set_wifi
method:post
Content-Type: application/json
Request body:
{"ssid":"x","password":"x"}
* | 类型 | 说明 |
---|---|---|
ssid | string | wifi ssid |
password | string | wifi password |
Response body:
- {
- "code": 20000,
- "bizCode": 200
- }
当设备端有移动侦测或识别到人脸时会通过此接口设置的URL上报。
/api/set_3rd_url?url=http://your_url&key=xxx
method:get
* | 类型 | 说明 |
---|---|---|
url | string | 设备数据通过http的 POST提交到此URL,数据格式参考 "人脸识别数据结构说明" |
key | string | 预留 |
人脸识别数据结构说明
- {
- "event_type": 4,
- "time": "1603934998092",
- "mac": "76:be:d8:75:29:f0",
- "sign": "x",
- "track_id": "6",
- "score": 86.57,
- "person_id": "10010001",
- "person_name": "Mr.luo",
- "face_base64": "xxxxx",
- "origin_base64": "xxxx",
- "blur":0.1,
- "goodness":0.9
- }
* | 类型 | 说明 |
---|---|---|
event_type | int | 4 人脸识别事件 |
time | string | 事件发生时间 |
mac | string | 设备mac地址 |
sign | string | 签名串,用于验证是否合法请求源,md5(time+key+mac) 32位16进制字符串 |
track_id | string | 人脸跟踪ID |
score | string | 相似度,分值越高,相似度越高,满分100,通常大于70分判断为相同的人 |
person_id | string | 搜索到的相似度最高的人脸库的人脸ID |
person_name | string | 搜索到的相似度最高的人脸库的人名字 |
face_base64 | string | 抓拍的人脸图像数据(base64编码) |
origin_base64 | string | 抓拍的整个图像数据(base64编码) |
blur | float | 人脸模糊程度属性(0〜1,0代表最清晰,1代表最模糊) |
goodness | float | 人脸品质,根据pose/blur,得到的人脸分数(0〜1,1是最高分,表示人脸好 |
/api/face_upload
method:post
Request body:
- 人脸照片的base64编码16进制字符串
- /9j/4AAQSkZJRgABAQ....
整个请求Body全部为照片的base64编码字符串,不能有其他数据
Response body:
- {
- "code": 20000,
- "bizCode": 200,
- "data": {
- "id": 896
- }
- }
* | 类型 | 说明 |
---|---|---|
code | int | 20000为上传成功 |
id | int | 人脸保存的唯一ID |
/api/face_list?page=1&limit=16
method:get
Request body:
* | 类型 | 说明 |
---|---|---|
page | int | 分页查询 |
limit | int | 每页记录数量 |
Response body:
{ "code": 20000, "data": { "total": 2, "list": [{ "id": 896, "file": "/face/896.jpg", "state": "1" }, { "id": 801, "file": "/face/801.jpg", "state": "2", "biz_id": "10010001", "name": "Mr.luo" }] } }
* | 类型 | 说明 |
---|---|---|
id | int | 人脸保存的唯一ID |
file | string | 人脸图片路径 |
state | int | 状态:1未入库,2已入库 |
biz_id | string | 身份ID这个字段值会作为上报接口中对应的person_id字段值 |
name | string | 名字这个字段值会作为上报接口中对应的person_name字段值 |
根据人脸保存的唯一ID设置照片身份ID和名字
/api/face_edit
method:post
Content-Type: application/json
Request body:
{"id":801,"biz_id":"xx","name":"xxx"}
* | 类型 | 说明 |
---|---|---|
biz_id | string | 身份ID这个字段值会作为上报接口中对应的person_id字段值 |
name | string | 名字这个字段值会作为上报接口中对应的person_name字段值 |
分页查询人脸识别历史记录
/api/recognition_list?page=1&limit=16
method:get
* | 类型 | 说明 |
---|---|---|
page | int | 页码 |
limit | int | 每页记录数 |
response body
{ "code": 20000, "data": { "total": 9, "list": [ { "id": 10, "face": "./track_out/10.jpg", "time": "1606189079985", "person_id": "", "person_face": "", "name": "", "origin_file": "./track_out/origin_10.jpg", "video_file": "", "blur": "0.1", "goodness": "1", "score": "0" }, { "id": 9, "face": "./track_out/9.jpg", "time": "1606188705928", "person_id": "", "person_face": "", "name": "", "blur": "0.1", "goodness": "0.9", "score": "0" } ] } }
* | 类型 | 说明 |
---|---|---|
id | int | id |
face | string | 抓拍的人脸保存路径 |
time | string | 识别时间(毫秒) |
person_id | string | 识别到的人脸编号 |
person_face | string | 识别到的人脸路径 |
name | string | 识别到的人名字 |
origin_file | string | 抓拍的整画面图 |
video_file | string | 抓拍的视频文件 |
blur | float | 人脸模糊程度属性(0〜1,0代表最清晰,1代表最模糊) |
goodness | float | 人脸品质,根据pose/blur,得到的人脸分数(0〜1,1是最高分,表示人脸好 |
score | string | 相似度 |
只有进行了入库操作的人脸才会参与识别
/api/face_extract_feature?id=x
method:get
* | 类型 | 说明 |
---|---|---|
id | int | 人脸保存的唯一ID |
response body
- {
- "code": 20000,
- "bizCode": 200
- }
* | 类型 | 说明 |
---|---|---|
bizCode | int | 200为成功 |
通过udp协议给5634端口广播“hi”,同一局域网内的设备会回复自身主机信息。
JAVA搜索例子
DatagramSocket dgSocket = new DatagramSocket(); dgSocket.setSoTimeout(1000); byte b[] = "hi\n".getBytes(); DatagramPacket dgPacket = new DatagramPacket(b, b.length, InetAddress.getByName("255.255.255.255"), 5634); dgSocket.send(dgPacket); byte[] receiveBuf = new byte[256]; DatagramPacket dp = new DatagramPacket(receiveBuf, 0, receiveBuf.length);//定义一个接收的包 try { while (true) { dgSocket.receive(dp); if (dp.getLength() > 0) { String rs = new String(dp.getData(), 0, dp.getLength()); //id:xxxxxx,v:xxxx,m:xxxxx String rs_slipt[] = rs.split(","); if ((cMap.get(rs) == null) && (rs_slipt.length > 1)) { String id = rs_slipt[0].replaceAll("id:", ""); System.out.println("id:"+id); System.out.println("ip:"+dp.getAddress().getHostAddress()); } } }
iOS/C
int socketfd; socklen_t addr_len; char hi[]="Hi"; struct sockaddr_in server_addr; if((socketfd = socket(PF_INET,SOCK_DGRAM,0)) < 0) { perror("socket"); return -1; } int i=1; socklen_t len = sizeof(i); setsockopt(socketfd,SOL_SOCKET,SO_BROADCAST,&i,len); struct timeval tv_out; tv_out.tv_sec = 1;//等待5秒 tv_out.tv_usec = 0; setsockopt(socketfd,SOL_SOCKET,SO_RCVTIMEO,&tv_out, sizeof(tv_out)); memset(&server_addr,0,sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = inet_addr("255.255.255.255"); server_addr.sin_port = htons(atoi("5634")); addr_len=sizeof(server_addr); sendto(socketfd,hi,strlen(hi),0,(struct sockaddr*)&server_addr,addr_len); printf("Broadcast message to port 5634\n"); char buff[256]; memset(&buff, 0, 256); struct sockaddr_in sddr; int n; len = sizeof(sddr); n = recvfrom(socketfd, buff, 256, 0, (struct sockaddr*)&sddr,&len); if (n>0){ printf("%s,server ip=%s\n",buff,inet_ntoa(sddr.sin_addr)); } close(socketfd);
待完善
支持TCP长连接对接第三方服务器,在TCP通道可以发送指令控制设备
待完善
待完善
待完善
待完善
可以二次开发扩展程序(c/c++),FTP上传到设备或NFS挂载调试。
设备应用框架采用linux so动态链接库方式扩展功能
需要具备的知识:
需要熟练掌握C/C++编程
熟悉Linux操作系统基本知识
安装Linux 32位操作系统
建议虚拟机,Ubuntu18.04版本,如果是64位,需要安装32位扩展.
安装HISI Arm处理器编译器
arm-himix200-linux
下载地址 百度网盘
链接:https://pan.baidu.com/s/1IHAlX3NwITqPzXP55N4BZQ
提取码:ibn1
- tar -xzvf arm-himix200-linux.tgz
- cd arm-himix200-linux
- chmod +x ./arm-himix200-linux.install
- ./arm-himix200-linux.install
执行下面命令确认编译器是否安装成功
arm-himix200-linux-gcc -v
- Using built-in specs.
- COLLECT_GCC=arm-himix200-linux-gcc
- COLLECT_LTO_WRAPPER=/opt/hisi-linux/x86-arm/arm-himix200-linux/host_bin/../libexec/gcc/arm-linux-gnueabi/6.3.0/lto-wrapper
- Target: arm-linux-gnueabi
编译第一个程序Hello
解压OPCOL SDK之后,看到如下目录结构
- .OPCOLV300
- │--3rd
- │--admin
- │--doc
- │--hisi
- │--plugin
- │ │--hello
- │ │--|--Makefile
- │--sdkinclude
- │--cfg.mak
- │--Makefile.param
在hello的目录下执行
Make
编译成功之后生成了 libhello.so
把libhello.so拷贝到设备上的/app/plugin目录下
用telnet客户端连接到设备
执行启动主程序
- cd /app
- ./run.sh
hello.c程序解析
- #include "opcol.h" //SDK头文件
- #include <stdlib.h>
-
- int OPCOL_plugin_init(OPCOL_PLUGIN_CONTEXT_S *context)
- {
- //扩展SO,初始化入口
- printf("Hi,i am opcol\n");
- return 0;
- }
- int OPCOL_plugin_free()
- {
- //扩展SO,释放函数
- return 0;
- }
有2个函数
OPCOL_plugin_init为so的入口函数,主程序主动调用用户二次开发的so
OPCOL_plugin_free 为主程序退出时调用的函数
设备里有2路视频流:1路1080P 30帧/s;1路360P 20帧/s
- #include "opcol.h" //SDK头文件
- #include <stdlib.h>
- int SNB_event_handle(OPCOL_EVENT_TYPE_E eventType, void *pstData);
- int OPCOL_plugin_init(OPCOL_PLUGIN_CONTEXT_S *context)
- {
- //扩展SO,初始化入口
- //注册事件回调函数,当有视频数据时,回调my_event_handle函数
- context->eventListener = &my_event_handle;
- return 0;
- }
- int OPCOL_plugin_free()
- {
- //扩展SO,释放函数
- return 0;
- }
-
- //视频数据回调函数
- int SNB_event_handle(OPCOL_EVENT_TYPE_E eventType, void *pstData)
- {
- if (eventType != OPCOL_EVENT_VENC_STREAM)
- {
- return 0;
- }
- OPCOL_VENC_STREAM_S *param = (OPCOL_VENC_STREAM_S *)pstData;
- //视频流数据处理,例如保存到文件,提交到云服务器等
- //....do something
- if (param->chn == 1)
- {
- //第1通道视频数据,拷贝到内存
- char *cache=(char *)malloc(1024*1024);
- int len=0;
- for (i = 0; i < param->pstStream->u32PackCount; i++)
- {
- memcpy(cache + len, pstStream->pstPack[i].pu8Addr + pstStream->pstPack[i].u32Offset, pstStream->pstPack[i].u32Len - pstStream->pstPack[i].u32Offset);
- len = len + pstStream->pstPack[i].u32Len - pstStream->pstPack[i].u32Offset;
- }
- free(cache);
- }
- return 0;
- }
- #include "opcol.h" //SDK头文件
- #include <stdlib.h>
- #include "sqlite3.h"
- sqlite3 *db_handler;
- int SNB_event_handle(OPCOL_EVENT_TYPE_E eventType, void *pstData);
- int OPCOL_plugin_init(OPCOL_PLUGIN_CONTEXT_S *context)
- {
- //扩展SO,初始化入口
- db_handler = context->db_handler; //指向数据库指针
- //do something about sqlite3 db
- //.....
- return 0;
- }
- int OPCOL_plugin_free()
- {
- //扩展SO,释放函数
- return 0;
- }
//设置视频通道的帧率 int OPCOL_set_h264_frame_rate(int chn, int rate); //设置视频通道的码流 int OPCOL_set_h264_bit_rate(int chn, int rate); //编码一帧图像RAW(yuv420)数据到JPG int OPCOL_encode_jpeg(VIDEO_FRAME_INFO_S *frame, unsigned char *out_buffer, int *out_len); //在视频画面画框 int OPCOL_draw_rect(int x, int y, int w, int h); //清除视频画面画框 int OPCOL_clear_rect(); //侦听系统事件 void OPCOL_plugin_dispath_event(OPCOL_EVENT_TYPE_E eType, void *data); //设置系统密码 int OPCOL_set_password(const char *old_password, const char *new_password); //获取签名KEY OPCOL_ACCESS_INFO *OPCOL_get_access_info(); //设置音视频参数,如视频镜像翻转,快门曝光时间 int OPCOL_set_video_audio_attr(OPCOL_VIDEO_AUDIO_ATTR *video_audio_attr); //获取音视频参数 OPCOL_VIDEO_AUDIO_ATTR *OPCOL_get_video_audio_attr(); //获取网络配置参数,如WIFI,IP地址,mac等 OPCOL_NET_INFO *OPCOL_get_net_info(); //设置网络参数,如WFI,ip int OPCOL_set_net_info(OPCOL_NET_INFO *net_info);
系统事件,系统事件发生时,会广播每个so插件,每个插件在入口函数里注册事件侦听函数
如下注册my_event_handle为事件处理函数,具体看SO里获取视频流例子代码
context->eventListener = &my_event_handle;
- typedef enum _opcolEVENT_TYPE_E
- {
- OPCOL_EVENT_VENC_STREAM = 0, //有新的视频流帧数据
- OPCOL_EVENT_YUV_FRAME, //新的yuv420 raw数据帧
- OPCOL_EVENT_HTTP_REQ, //当收到HTTP请求事件
- OPCOL_EVENT_DISK_SPACE_COUNTED, //磁盘统计信息事件
- OPCOL_EVENT_FACE_RECOGNITION, //侦测到人脸时事件
- } OPCOL_EVENT_TYPE_E;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。