开源软件名称:sdk-presenter
开源软件地址:https://gitee.com/Atlas200DK/sdk-presenter
开源软件介绍:
中文|英文 Presenter部署在Mind Studio所在的Linux服务器上,主要作用是推理结果的展示。 Presenter包括Presenter Server与Presenter Agent。 - Presenter Agent提供一系列API,用户通过调用API向Presenter Server推送媒体消息。
- Presenter Server接收Presenter Agent发过来的人脸数据,通过浏览器进行结果展示。
Presenter ServerDescription Presenter Server是展示人脸检测推理结果的软件包,该软件基于python3.5实现,并用到了第三方web框架tornado,以及底层通信框架protobuf。 Presenter Server支持图片模式和视频模式。图片模式展示单张人脸图片,视频模式以图片流的方式展示连续图片。Presenter server通过channel来标记不同的数据源,在浏览器里通过Create按钮添加channel,Delete进行删除,默认支持两路channel,分别是image和video。 Sample Code presenter server的根目录在common/presenter/server,face_detection是人脸识别app的目录,config是配置文件目录,修改config.conf进行可服务端ip和port的定制,logging.conf是logging模块的配置;src是源码目录,其中,presenter_message_pb2.py 定义protobuf格式,presenter_socket_server.py 负责并行接收人脸数据,webapp.py 负责把数据推送到Chrome,进行前台展示;ui是web界面素材所在目录。 与Presenter Agent的消息通信: Presenter Server 与Presenter Agent和Chrome的消息通信如下图所示,Chrome上发起创建channel的操作,Presenter Server发送人脸数据到指定channel,Chrome打开此channel,观察人脸检测推理结果。 Presenter Server与Presenter Agent之间消息结构如下,依次是4个字节的消息总长度,1个字节的消息名长度,若干字节的消息消息名,若干字节的protobuf内容。 --------------------------------------------------------------|total message len | int | 4 bytes ||--------------------------------------------------------------|message name len | byte | 1 byte ||--------------------------------------------------------------|message name | string | xx bytes ||--------------------------------------------------------------|message body | protobuf | xx bytes |--------------------------------------------------------------- 主要的消息有两个,一个是打开channel的请求消息OpenChannelRequest ,另一个是发送人脸数据的消息PresentImageRequest ,其在ptorobuf中的定义如下: message OpenChannelRequest {string channel_name = 1; //channel 名称ChannelContentType content_type = 2; //数据模式,用来识别image和video}message PresentImageRequest {ImageFormat format = 1; // 图片格式,当前仅支持Jpeguint32 width = 2; //图片宽度uint32 height =3; //图片高度bytes data = 4; //图片数据} 通过epoll实现多路channel并行工作,实现伪码如下: def _server_listen_thread(self):"""socket server thread, epoll listening all the socket events"""epoll = select.epoll()epoll.register(self._sock_server.fileno(), select.EPOLLIN | select.EPOLLHUP)try:conns = {}msgs = {}while True:events = epoll.poll(EPOLL_TIMEOUT)# timeout, but no event come, continue waitingif not events:continuefor sock_fileno, event in events:# new connection request from presenter agentif self._sock_server.fileno() == sock_fileno:self._accept_new_socket(epoll, conns)# remote connection closed# it means presenter agent exit withot close socket.elif event & select.EPOLLHUP:self._clean_connect(sock_fileno, epoll, conns, msgs)# new data coming in a socket connectionelif event & select.EPOLLIN:self._process_epollin(sock_fileno, epoll, conns, msgs)# receive event not recognizeelse:self._clean_connect(sock_fileno, epoll, conns, msgs)finally:epoll.unregister(self._sock_server.fileno())epoll.close()self._sock_server.close() 消息解析过程,实现伪码如下,首先是解析消息,包括消息长度,消息名,最后读取protobuf并进行处理。 def _read_sock_and_process_msg(self, sock_fileno, conns, msgs):# Step1: read msg headmsg_total_len, msg_name_len = self._read_msg_head(sock_fileno, conns)if msg_total_len is None:return PRESENTER_ERR# Step2: read msg namemsg_name = self._read_msg_name(conns[sock_fileno], msg_name_len)if msg_name == SOCKET_RECEIVE_NULL:return PRESENTER_ERRtry:msg_name = msg_name.decode("utf-8")except UnicodeDecodeError:return PRESENTER_ERR# Step3: read msg bodymsg_body_len = msg_total_len - MSG_HEAD_LENGTH - msg_name_lenret = self._read_msg_body(sock_fileno, conns, msgs, msg_name, msg_body_len)if ret == PRESENTER_ERR:return ret# Step4: process msgret = self._process_msg(conns[sock_fileno], msg_name, msgs[sock_fileno])return ret 解析protobuf,来自Presenter Agent的消息请求共有三个,分别是打开channel、发送人脸数据、发送心跳。 def _process_msg(self, conn, msg_name, msg_data):# process open channel requestif msg_name == OPEN_CHANNEL_REQUEST_FULL_NAME:ret = self._process_open_channel(conn, msg_data)# process image request, receive an image data from presenter agentelif msg_name == PRESENT_IMAGE_REQUEST_FULL_NAME:ret = self._process_image_request(conn, msg_data)# process heartbeat request, it used to keepalive a channel pathelif msg_name == HEART_BEAT_MESSAGE_FULL_NAME:ret = self._process_heartbeat(conn)else:ret = PRESENTER_ERRreturn ret
Present AgentPresenter Agent提供一系列API,用户可以调用这些API向Presenter Server推送媒体消息,并在浏览器中查看。当前支持JPEG格式图片的推送。 调用流程如下所示: - App调用OpenChannel函数打开与Presenter Server间的通道。
- App调用SendMessage函数在该通道上推送媒体消息。推送消息时, 支持在推送的图片上画矩形框。使用时需要将框的左上、右下点的坐标、框的标题设置到PresentImageRequest对象中。
- 所有图片发送完成后,App调用CloseChannel函数释放分配的资源。
Sample Code 以发送图片为例: Open channel OpenChannelParam param;param.hostIp = "127.0.0.1"; //IP address of Presenter Serverparam.port = 7006; //port of present serviceparam.channelName = "image";param.contentType = ContentType::kImage; //content type is IMAGEChannel *channel = nullptr;PresenterErrorCode errorCode = OpenChannel(channel, param);if (errorCode != PresenterErrorCode::kNone) { return;} SendMessage ascend::presenter::proto::PresentImageRequest request;request.set_data(string(reinterpret_cast<const char*>(buffer), size)); //image data buffer, image shuold be jpeg formatrequest.set_width(1920);request.set_height(1280);//Set the rectangles info into request.ascend::presenter::proto::Rectangle_Attr *rectangle_attr = nullptr; rectangle_attr = request.add_rectangle_list(); //Add one rectanglerectangle_attr->mutable_left_top()-> set_x(100); rectangle_attr->mutable_left_top()-> set_y(100);rectangle_attr->mutable_right_bottom()->set_x(500);rectangle_attr->mutable_right_bottom()->set_y(500);rectangle_attr->set_label_text("This is a title"); //Set the title for the rectangleascend::presenter::PresenterErrorCode error_code = ascend::presenter::SendMessage(channel, request) Close Channel
如果需要发送一系列图片来展示视频的效果,则将1中的contentType改为ContentType::kVideo,并 不断的调用SendMessage即可。 修改源码 编译源码需要使用protoc编译proto文件,请从https://github.com/protocolbuffers/protobuf/releases/中获取软件包protoc-3.5.1-linux- x86_64.zip,并参照包中的readme进行安装。 主要源码结构如下所示: common/presenter/agent PresenterAgent源码根目录 ├─proto Protobuf消息定义 ├─include/ascendk/presenter/agent API头文件 ├─channel.h 通用channel的接口,提供收发protobuf消息的功能 ├─errors.h 错误码 ├─presenter_channel.h 封装了发送媒体数据到PresenterServer的功能 ├─presenter_types.h 封装了发送媒体数据到PresenterServer的功能 ├─src/asceddk/presenter/agent 源码目录 ├─channel 与PresenterServer交互相关源码 ├─default_channel.cpp Channel类的默认实现,维护与Server间的长连接 ├─default_channel.h Channel类的默认实现的头文件 ├─channel.cpp Channel类的默认实现的头文件 ├─codec ├─connection 提供发送/接收protobuf消息的接口 ├─net 网络连接相关源码, 完成收发字节数组的接口 ├─socket.cpp Socket抽象类 ├─socket_factory.cpp Socket工厂抽象类 ├─raw_socket.cpp 基于linux原生socket,不提供通道加密功能 ├─raw_socket_factory.cpp RawSocket的工厂类 ├─presenter 封装了发送媒体数据到PresenterServer的功能 ├─util 工具类相关源码 ├─Makefile 如果修改了presenter_message.proto,则需要在proto文件夹下执行以下命令编译proto文件: protoc presenter_message.proto --cpp_out=./ |
请发表评论