开放API接口协议和SDK二次开放的人脸识别摄像头

摄像头在中国是非常成熟的产品,整个行业趋于垄断和封闭的状态,要找到一款能方便整合到自己系统的摄像头是非常不容易的事情.

OPCOL是一款AI智能的开放API接口和SDK二次开发的人脸识别摄像头。可以非常轻松的接入的已有的业务系统中。

它有如下特点:

开放API+SDK,API为全HTTP restful风格的极容易集成的接口方式,SDK方式为C/C++插件so动态库扩展方式

完全离线模式,不依赖任何第三方云服务器,数据不会传输到任何第三方服务器,让用户隐私得到保障

设备支持2万张人脸库,人脸识别毫秒级响应,深度学习算法实现人脸检测、跟踪、去重、质量检测。

采用SONY CMOS图像传感器

最大画面尺寸 1080P(1920*1080),最大支持2路视频流和1路JPG图像抓拍通道

不支持判断是否活体检测

API详细说明链接

https://gitee.com/imlsq/pubdoc/blob/master/opcolv300.md

实物图

 

离线ocr java集成 离线ocr识别开发sdk_字段

离线ocr java集成 离线ocr识别开发sdk_字段_02

API介绍

设备提供如下3种途径集成到第三应用

  • HTTP协议接口.
  • TCP/ip长连接协议对接
  • SDK用户自定义研发SO插件集成

TTP方式提供基本的,最简单的对接方式

 

HTTP请求认证


通过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不能重复使用

 

签名KEY


用户名和密码登录验证之后会返回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

新密码

 

设置WIFI


 

/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设置照片身份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/IP协议对接


支持TCP长连接对接第三方服务器,在TCP通道可以发送指令控制设备 待完善

 

获取实时视频流(H264)


待完善

 

P2P对接协议


待完善

 

RTMP协议对接


待完善

 

SDK二次开发说明


可以二次开发扩展程序(c/c++),FTP上传到设备或NFS挂载调试。 设备应用框架采用linux so动态链接库方式扩展功能

需要具备的知识: 需要熟练掌握C/C++编程 熟悉Linux操作系统基本知识

 

开发第一个Hello程序


安装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 为主程序退出时调用的函数

 

SO里获取视频流


设备里有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;
}

 

SQLite3数据库

 

#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;
}

 

SDK函数

 

//设置视频通道的帧率
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;