This commit is contained in:
ascendhuawei
2020-09-16 11:50:53 -07:00
commit a61dda4612
97 changed files with 15410 additions and 0 deletions
+193
View File
@@ -0,0 +1,193 @@
# Body Pose Detection \(Python)
This application runs on Atlas 200 DK, to infer human body poses. The model used is modified from Lightweight OpenPose [Osokin, Daniil. "Real-time 2d multi-person pose estimation on CPU: Lightweight OpenPose." arXiv preprint arXiv:1811.12004 (2018)], an open-source pose detection network. This application can be run on various input formats, namely image input, video input as well as live camera input.
The pose detection network originates from [Cao, Zhe, et al. "OpenPose: realtime multi-person 2D pose estimation using Part Affinity Fields." arXiv preprint arXiv:1812.08008 (2018)], where the network provides two outputs: heatmaps and PAF maps for each frame. In the post-processing of the model, both heatmaps and PAF maps are used to obtain multi-persion pose estimation.
In this repository, the post-processing a simplied version for edge computing, where only the heatmap is used to calculate the predicted locations of the human body joints. A set of 14 detected joints are grouped, connected to form limbs and associated to a person. The diagram below represents connection scheme:
12 12: head, 13: neck
|
|
0-----13-----3
/ / \ \
1 / \ 4
/ / \ \
2 6 9 5
| |
7 10
| |
8 11
The figure below shows the sample output on a single image input. The detected pose is displayed in the form of a skeleton overlay on the image.
**Figure** OpenPose detection result<a name="zh-cn_topic_0228757088_fig64391558352"></a>
![](figures/pose_detected.jpg "pose-detected")
## Software Preparation<a name="zh-cn_topic_0228757083_section17595135641"></a>
Clone or download the project repository:
**mkdir -p $HOME/AscendProjects**
**cd $HOME/AscendProjects**
**git clone ssh://git@rnd-gitlab-ca-g.huawei.com:2222/hispark/openpose-pythonc73.git**
OR
**wget https://rnd-gitlab-ca-g.huawei.com/hispark/openpose-pythonc73.git**
Then, unzip the downloaded file:
**unzip openpose-pythonC73.zip**
## Environment Preparation<a name="zh-cn_topic_0228757083_section17595135641"></a>
Install required libraries for Python3 environment (OpenCV, PresentAgent and Python3env)
Please refer to https://github.com/Huawei-Ascend/samples/tree/master/common
## Environment Deployment<a name="zh-cn_topic_0228757083_section1759513564117"></a>
1. Go to the root directory where the application code is located, such as: $HOME/AscendProjects/openpose-pythonC73/.
**cd $HOME/AscendProjects/openpose-pythonC73/**
2. Modify the configuration file.
Modify **presenter\_server\_ip** and **presenter\_view\_ip** in **script/body\_pose.conf** to the current ubuntu server and atlas200dk development board network port ip, **presenter \_agent\_ip** is the ip of the network port connected to the ubuntu server on the development board.
If you use USB connection, the USB network port ip of the development board is 192.168.1.2, and the network port ip of the virtual network card connected to the ubuntu server and the development board is 192.168.1.223, then the configuration file content is as follows:
**presenter\_server\_ip=192.168.1.223**
**presenter\_view\_ip=192.168.1.223**
**presenter\_agent\_ip=192.168.1.2**
Generally, when connecting via USB, atlas200dk\_board\_ip is the USB network port ip of the development board, and the default is 192.168.1.2. When connecting through a network port, atlas200dk\_board\_ip is the network port ip of the development board, and the default is 192.168.0.2.
3. Copy the application code to the development board.
Navigate to the root directory where the openpose-pythonC73 application code is located, such as: AscendProjects/openpose-pythonC73, execute the following command to copy the application code to the development board. If the copy fails, please check if there is a directory HIAI\_PROJECTS on the development board, and if not, create it.
**scp -r ~/AscendProjects/openpose-pythonC73 HwHiAiUser@192.168.1.2:/home/HwHiAiUser/HIAI\_PROJECTS**
Enter the development board password when prompted for password. The default password of the development board is **Mind@123**, as shown below:
<a name="zh-cn_topic_02287570831_zh-cn_topic_0198304761_fig1660453512014"></a>
![](figures/files_copy.png)
4. Start Presenter Server.
**NOTE**: This step is required when the presenter server needs to be used for video or live display on the browser. Otherwise, skip this step.
Execute the following command to start the Presenter Server in the background.
**bash $HOME/AscendProjects/openpose-pythonC73/script/run_presenter_server.sh &**
Log in to the Presenter Server using the prompted URL. The figure below shows that the Presenter Server has started successfully.
**Figure** Home Page Display<a name="zh-cn_topic_0228757088_fig64391558352"></a>
![](figures/主页显示.png "Home page display")
The communication between Presenter Server, Mind Studio and Atlas 200 DK is shown as below
**Figure** Examples of IP addresses<a name="zh-cn_topic_0228757088_fig1881532172010"></a>
![](figures/IP地址示例.png "Examples of IP addresses")
NOTE:
- The IP address used by the Atlas 200 DK developer board is 192.168.1.2 (USB connection).
- The IP address for the communication between Presenter Server and Atlas 200 DK is the IP address of the UI Host server on the same network segment as Atlas 200 DK, for example: 192.168.1.223.
- This example of the IP address for accessing Presenter Server through a browser is 10.10.0.1. Since Presenter Server and Mind Studio are deployed on the same server, this IP address is also the IP for accessing Mind Studio through a browser.
5. Copy acl.so to the development board. Please skip this step if it is already done in other projects.
**scp ~/Ascend/ascend-toolkit/20.0.RC1/arm64-linux_gcc7.3.0/pyACL/python/site-packages/acl/acl.so HwHiAiUser@192.168.1.2:/home/HwHiAiUser/Ascend/**
**Please replace X.X.X with the actual version number of the Ascend-Toolkit development kit package**
**For example: the package name of the Toolkit package is Ascend-Toolkit-20.0.RC1-x86_64-linux_gcc7.3.0.run, then the version number of this Toolkit is 20.0.RC1.**
6. Log in to the development board and add environment variables. Please skip this step if it is already done in other projects.
**ssh HwHiAiUser@192.168.1.2**
**vim ~/.bashrc**
Add two lines at the end
**export LD_LIBRARY_PATH=/home/HwHiAiUser/Ascend/acllib/lib64**
**export PYTHONPATH=/home/HwHiAiUser/Ascend/:\\${PYTHONPATH}**
![](figures/bashrc.png)
Execute the following command to make the environment variable take effect
**source ~/.bashrc**
## Running the Application
1. Check whether the "CAMERA0" camera is used.
The "CAMERA0" camera is used by default in the code. Please refer to the link below for the viewing method.
https://support.huaweicloud.com/usermanual-A200dk_3000/atlas200dk_02_0051.html
2. Log in to the development board. Navigate to the code directory corresponding to the required input source format (image, video or live camera), and execute one of the following commands to run the application according to the input source format.
**NOTE**: To execute it, you could use the default input (just run **python3 main.py** without parameter), or input parameters as below for input/output paths and model path as indicated in **main.py**. For the video input, you also have the option to save the output as a video or display to presenter server, with the value in parameter 'is_presenter_server' set to False or True, respectively .
*Image input source*:
**cd ~/HIAI_PROJECTS/openpose-pythonC73/code_image**
**python3 main.py --model='model/body_pose.om' --frames_input_src='tennis_player.jpg' --output_dir='outputs'**
*Video input source (output video)*:
**cd ~/HIAI_PROJECTS/openpose-pythonC73/code_video**
**python3 main.py --model='model/body_pose.om' --frames_input_src='yoga.mp4' --output_dir='outputs' --is_presenter_server=False**
Video input source (output streamed to presenter server)*:
**cd ~/HIAI_PROJECTS/openpose-pythonC73/code_video**
**python3 main.py --model='model/body_pose.om' --frames_input_src='yoga.mp4' --output_dir='outputs' --is_presenter_server=True**
*Live camera source*:
**cd ~/HIAI_PROJECTS/openpose-pythonC73/code_live**
**python3 main.py --model='model/body_pose.om'**
3. If you need to view the detection results using presenter server for the live input or video source, log in to the Presenter Server website using the URL that was prompted when the Presenter Server service was started. Otherwise, skip this step.
Wait for the Presenter Agent to transmit data to the server, and click "Refresh" to refresh. When there is data, the status of the corresponding Channel turns green, as shown in the figure below.
**Figure** Presenter Server<a name="zh-cn_topic_0228461904_zh-cn_topic_0203223294_fig113691556202312"></a>
![](figures/presenter.png "Presenter-Server-interface")
Click the corresponding View Name link on the right, such as "video" in the above picture, to view the results.
## Stopping Application<a name="zh-cn_topic_0228757088_section1092612277429"></a>
If the presenter server is being used for display, stop
- **Stop Presenter Server**
The Presenter Server service will always be running after it is started. If you want to stop the Presenter Server service corresponding to the pose detection application, you can perform the following operations.
Execute the following command on the command line on the server where the process of the Presenter Server service is running:
**ps -ef | grep presenter**
```
ascend@ubuntu:~/AscendProjects/openpose-pythonC73/script$ ps -ef | grep presenter
ascend 9560 1342 0 02:19 pts/4 00:00:04 python3/home/ascend/AscendProjects/openpose-pythonC73.bak/script/..//present
erserver/presenter_server.py --app openpose-pythonC73
```
As shown above, _9650_ is the process ID of the Presenter Server service corresponding to the openpose-pythonC73 application.
If you want to stop this service, execute the following command:
**kill -9** _9650_
View File
+215
View File
@@ -0,0 +1,215 @@
import numpy as np
import acl
from atlas_utils.utils import *
from atlas_utils.acl_image import AclImage
class Dvpp():
def __init__(self, acl_resource):
self._stream = acl_resource.stream
self._run_mode = acl_resource.run_mode
self._dvpp_channel_desc = None
ret = self._init_resource()
if ret == FAILED:
raise Exception("Dvpp init failed")
def __del__(self):
if self._resize_config:
acl.media.dvpp_destroy_resize_config(self._resize_config)
if self._dvpp_channel_desc:
acl.media.dvpp_destroy_channel(self._dvpp_channel_desc)
acl.media.dvpp_destroy_channel_desc(self._dvpp_channel_desc)
if self._jpege_config:
acl.media.dvpp_destroy_jpege_config(self._jpege_config)
def _init_resource(self):
# create dvpp channel
self._dvpp_channel_desc = acl.media.dvpp_create_channel_desc()
ret = acl.media.dvpp_create_channel(self._dvpp_channel_desc)
if ret != ACL_ERROR_NONE:
print("Dvpp create channel failed")
return FAILED
# create resize configuration
self._resize_config = acl.media.dvpp_create_resize_config()
#create yuv to jpeg configuration
self._jpege_config = acl.media.dvpp_create_jpege_config()
ret = acl.media.dvpp_set_jpege_config_level (self._jpege_config, 100)
if ret != ACL_ERROR_NONE:
print("Dvpp set jpege config failed")
return FAILED
return SUCCESS
def _gen_input_pic_desc(self, image,
width_align_factor=16, height_align_factor=2):
#create image input desc
stride_width = align_up(image.width, width_align_factor)
stride_height = align_up(image.height, height_align_factor)
pic_desc = acl.media.dvpp_create_pic_desc()
acl.media.dvpp_set_pic_desc_data(pic_desc, image.data())
acl.media.dvpp_set_pic_desc_format(pic_desc,
PIXEL_FORMAT_YUV_SEMIPLANAR_420)
acl.media.dvpp_set_pic_desc_width(pic_desc, image.width)
acl.media.dvpp_set_pic_desc_height(pic_desc, image.height)
acl.media.dvpp_set_pic_desc_width_stride(pic_desc, stride_width)
acl.media.dvpp_set_pic_desc_height_stride(pic_desc, stride_height)
acl.media.dvpp_set_pic_desc_size(pic_desc, image.size)
return pic_desc
def _gen_output_pic_desc(self, width, height,
output_buffer, output_buffer_size,
width_align_factor=16, height_align_factor=2):
# create image output desc
stride_width = align_up(width, width_align_factor)
stride_height = align_up(height, height_align_factor)
pic_desc = acl.media.dvpp_create_pic_desc()
acl.media.dvpp_set_pic_desc_data(pic_desc, output_buffer)
acl.media.dvpp_set_pic_desc_format(pic_desc,
PIXEL_FORMAT_YUV_SEMIPLANAR_420)
acl.media.dvpp_set_pic_desc_width(pic_desc, width)
acl.media.dvpp_set_pic_desc_height(pic_desc, height)
acl.media.dvpp_set_pic_desc_width_stride(pic_desc, stride_width)
acl.media.dvpp_set_pic_desc_height_stride(pic_desc, stride_height)
acl.media.dvpp_set_pic_desc_size(pic_desc, output_buffer_size)
return pic_desc
def _stride_yuv_size(self, width, height,
width_align_factor=16, height_align_factor=2):
stride_width = align_up(width, width_align_factor)
stride_height = align_up(height, height_align_factor)
stride_size = yuv420sp_size(stride_width, stride_height)
return stride_width, stride_height, stride_size
def jpegd(self, image):
# jepg image to yuv image
# create converted image desc
output_desc, out_buffer = self._gen_jpegd_out_pic_desc(image)
ret = acl.media.dvpp_jpeg_decode_async(self._dvpp_channel_desc,
image.data(),
image.size,
output_desc,
self._stream)
if ret != ACL_ERROR_NONE:
print("dvpp_jpeg_decode_async failed ret={}".format(ret))
return None
ret = acl.rt.synchronize_stream(self._stream)
if ret != ACL_ERROR_NONE:
print("dvpp_jpeg_decode_async failed ret={}".format(ret))
return None
width, height, size = self._stride_yuv_size(image.width, image.height)
return AclImage(out_buffer, width, height, size)
def _gen_jpegd_out_pic_desc(self, image):
# predict memory sieze for decoding jpeg to yuy image
out_buffer_size, ret = acl.media.dvpp_jpeg_predict_dec_size( \
image.data(), image.size, PIXEL_FORMAT_YUV_SEMIPLANAR_420)
if ret != ACL_ERROR_NONE:
print("Predict jpeg decode size failed, return ", ret)
return None
# allocate memory for yuv image
out_buffer, ret = acl.media.dvpp_malloc(out_buffer_size)
if ret != ACL_ERROR_NONE:
print("Dvpp malloc failed, error: ", ret)
return None
# create output image desc
pic_desc = self._gen_output_pic_desc(image.width, image.height,
out_buffer, out_buffer_size)
return pic_desc, out_buffer
def resize(self, image, resize_width, resize_height):
# resize yuvsp420 image to specified size
# generate input image desc
input_desc = self._gen_input_pic_desc(image)
# calculate resized image size
stride_width = align_up16(resize_width)
stride_height = align_up2(resize_height)
output_size = yuv420sp_size(stride_width, stride_height)
# allocate memory for resized image
out_buffer, ret = acl.media.dvpp_malloc(output_size)
if ret != ACL_ERROR_NONE:
print("Dvpp malloc failed, error: ", ret)
return None
#create output desc
output_desc = self._gen_output_pic_desc(resize_width, resize_height,
out_buffer, output_size)
if output_desc == None:
print("Gen resize output desc failed")
return None
# call DVPP asynchronous resize interface to resize image
ret = acl.media.dvpp_vpc_resize_async(self._dvpp_channel_desc,
input_desc,
output_desc,
self._resize_config,
self._stream)
if ret != ACL_ERROR_NONE:
print("Vpc resize async failed, error: ", ret)
return None
# wait for resize to complete
ret = acl.rt.synchronize_stream(self._stream)
if ret != ACL_ERROR_NONE:
print("Resize synchronize stream failed, error: ", ret)
return None
# release allocated memory for resize
acl.media.dvpp_destroy_pic_desc(input_desc)
acl.media.dvpp_destroy_pic_desc(output_desc)
return AclImage(out_buffer, stride_width,
stride_height, output_size, MEMORY_DVPP)
def _gen_resize_out_pic_desc(self, resize_width,
resize_height, output_size):
out_buffer, ret = acl.media.dvpp_malloc(output_size)
if ret != ACL_ERROR_NONE:
print("Dvpp malloc failed, error: ", ret)
return None
pic_desc = self._gen_output_pic_desc(resize_width, resize_height,
out_buffer, output_size)
return pic_desc, out_buffer
def jpege(self, image):
# convert yuv420sp image to jpeg image
# create input image desc
input_desc = self._gen_input_pic_desc(image)
# predict memory size for conversion
output_size, ret = acl.media.dvpp_jpeg_predict_enc_size(
input_desc, self._jpege_config)
if (ret != ACL_ERROR_NONE):
print("Predict jpege output size failed")
return None
# allocate memory for conversion
output_buffer, ret = acl.media.dvpp_malloc(output_size)
if (ret != ACL_ERROR_NONE):
print("Malloc jpege output memory failed")
return None
# output size is an parameter for both input and output, which needs to be a pointer
output_size_array = np.array([output_size], dtype=np.int32)
output_size_ptr = acl.util.numpy_to_ptr(output_size_array)
# call jpeg asynchronous interface to convert image异步接口转换图片
ret = acl.media.dvpp_jpeg_encode_async(self._dvpp_channel_desc,
input_desc, output_buffer,
output_size_ptr,
self._jpege_config,
self._stream)
if (ret != ACL_ERROR_NONE):
print("Jpege failed, ret ", ret)
return None
# wait for conversion to complete
ret = acl.rt.synchronize_stream(self._stream)
if (ret != ACL_ERROR_NONE):
print("Jpege synchronize stream, failed, ret ", ret)
return None
# release resource
acl.media.dvpp_destroy_pic_desc(input_desc)
return AclImage(output_buffer, image.width,
image.height, int(output_size_array[0]), MEMORY_DVPP)
+263
View File
@@ -0,0 +1,263 @@
import acl
import numpy as np
import datetime
from atlas_utils.utils import *
from atlas_utils.acl_image import AclImage
class Model(object):
def __init__(self, acl_resource, model_path):
self._run_mode = acl_resource.run_mode
self.model_path = model_path # string
self.model_id = None # pointer
self.input_dataset = None
self.output_dataset = None
self._output_info = []
self.model_desc = None # pointer when using
self._init_resource()
def __del__(self):
if self.input_dataset:
self._release_dataset(self.input_dataset)
if self.output_dataset:
self._release_dataset(self.output_dataset)
if self.model_id:
ret = acl.mdl.unload(self.model_id)
if ret != ACL_ERROR_NONE:
print("acl.mdl.unload error:", ret)
if self.model_desc:
ret = acl.mdl.destroy_desc(self.model_desc)
if ret != ACL_ERROR_NONE:
print("acl.mdl.destroy_desc error:", ret)
print("Model release source success")
def _init_resource(self):
print("Init model resource")
# loading model file
self.model_id, ret = acl.mdl.load_from_file(self.model_path)
check_ret("acl.mdl.load_from_file", ret)
self.model_desc = acl.mdl.create_desc()
ret = acl.mdl.get_desc(self.model_desc, self.model_id)
check_ret("acl.mdl.get_desc", ret)
# obtain model outputs number
output_size = acl.mdl.get_num_outputs(self.model_desc)
# create model output dataset structure
self._gen_output_dataset(output_size)
print("[Model] class Model init resource stage success")
# obtain shape and type of each output of the model
self._get_output_desc(output_size)
# create a table to record memory for input data, which can be reused when allocating memory for the input
self._init_input_buffer()
return SUCCESS
def _get_output_desc(self, output_size):
for i in range(output_size):
# obtain shape and type of each output
dims = acl.mdl.get_output_dims(self.model_desc, i)
shape = tuple(dims[0]["dims"])
datatype = acl.mdl.get_output_data_type(self.model_desc, i)
size = acl.mdl.get_output_size_by_index(self.model_desc, i)
if datatype == ACL_FLOAT:
np_type = np.float32
elif datatype == ACL_INT32:
np_type = np.int32
elif datatype == ACL_UINT32:
np_type = np.uint32
else:
print("Unspport model output datatype ", datatype)
return None
# create a numpy array corresponding to outputs, with the same datatype and shape of outputs
output_tensor = np.zeros(size//4, dtype=np_type).reshape(shape)
if not output_tensor.flags['C_CONTIGUOUS']:
output_tensor = np.ascontiguousarray(output_tensor)
tensor_ptr = acl.util.numpy_to_ptr(output_tensor)
self._output_info.append({"ptr": tensor_ptr,
"tensor": output_tensor})
def _gen_output_dataset(self, size):
print("[Model] create model output dataset:")
dataset = acl.mdl.create_dataset()
for i in range(size):
# allocate device memory for each output
size = acl.mdl.get_output_size_by_index(self.model_desc, i)
buffer, ret = acl.rt.malloc(size, ACL_MEM_MALLOC_NORMAL_ONLY)
check_ret("acl.rt.malloc", ret)
# create output data buffer structure, fill allocated memory into the data buffer
dataset_buffer = acl.create_data_buffer(buffer, size)
#add data buffer to output dataset
_, ret = acl.mdl.add_dataset_buffer(dataset, dataset_buffer)
print("malloc output %d, size %d"%(i, size))
if ret:
# release resource if failed
acl.rt.free(buffer)
acl.destroy_data_buffer(dataset)
check_ret("acl.destroy_data_buffer", ret)
self.output_dataset = dataset
print("[Model] create model output dataset success")
def _init_input_buffer(self):
# create a table recording the input data memory allocated for users
# currently, the numpy data needs to be copied to device for memory allocation only when the input is numpy array
self._input_num = acl.mdl.get_num_inputs(self.model_desc)
self._input_buffer = []
for i in range(self._input_num):
# none of inputs is allocated memory initially
item = {"addr":None, "size":0}
self._input_buffer.append(item)
def _gen_input_dataset(self, input_list):
# organize input dataset structure
ret = SUCCESS
# return if the input number does not match model requirements
if len(input_list) != self._input_num:
print("Current input data num %d unequal to"
" model input num %d"%(len(input_list), self._input_num))
return FAILED
self.input_dataset = acl.mdl.create_dataset()
for i in range(self._input_num):
item = input_list[i]
# parse input, currently supports AclImage type, Acl pointer and numpy array
data, size = self._parse_input_data(item, i)
if (data is None) or (size == 0):
# not parse the remaining data when parsing data fails
ret = FAILED
print("The %d input is invalid"%(i))
break
# create input dataset buffer structure, fill in input data
dataset_buffer = acl.create_data_buffer(data, size)
# add dataset buffer to dataset
_, ret = acl.mdl.add_dataset_buffer(self.input_dataset,
dataset_buffer)
if ret:
print("Add input dataset buffer failed")
acl.destroy_data_buffer(self.input_dataset)
ret = FAILED
break
if ret == FAILED:
# release dataset if fails
self._release_dataset(self.input_dataset)
return ret
def _parse_input_data(self, input, index):
data = None
size = 0
if isinstance(input, AclImage):
# if input data is AclImage, directly return memory pointer and sieze of image
# defautly image memory is data on the device
size = input.size
data = input.data()
elif isinstance(input, np.ndarray):
# if input is numpy data, allocate device memory for data and copy data to device
# allocated memory can be reused, no need to apply for it everytime
ptr = acl.util.numpy_to_ptr(input)
size = input.size * input.itemsize
data = self._copy_input_to_device(ptr, size, index)
if data == None:
size = 0
print("Copy input to device failed")
# if directly input memory pointer, structure should be dict like {"data":, "size":}, and default memory is on the device side
elif (isinstance(input, dict) and
input.has_key('data') and input.has_key('size')):
size = input['size']
data = input['data']
else:
print("Unsupport input")
return data, size
def _copy_input_to_device(self, input_ptr, size, index):
# allocate device memory for input, and copy data to this memory
buffer_item = self._input_buffer[index]
data = None
# according to the index of the data in the model input, check whether the input has already been allocated memory
if buffer_item['addr'] is None:
# if not, allocate memory, copy data and record memory for resue
data = copy_data_device_to_device(input_ptr, size)
if data is None:
print("Malloc memory and copy model %dth "
"input to device failed"%(index))
return None
buffer_item['addr'] = data
buffer_item['size'] = size
elif size == buffer_item['size']:
# if memory has already been allocated for the input, and memory size is consistent with current input data
# copy data to this memory for inference
ret = acl.rt.memcpy(buffer_item['addr'], size,
input_ptr, size,
ACL_MEMCPY_DEVICE_TO_DEVICE)
if ret != ACL_ERROR_NONE:
print("Copy model %dth input to device failed"%(index))
return None
data = buffer_item['addr']
else:
# if memory has already been allocated for the input, but memory size is not consistent with current input data
# it would be considered as exception. because size of each model input is fixed
print("The model %dth input size %d is change,"
" before is %d"%(index, size, buffer_item['size']))
return None
return data
def execute(self, input_list):
# create dataset object instance for offline model inference
ret = self._gen_input_dataset(input_list)
if ret == FAILED:
print("Gen model input dataset failed")
return None
# call execute inference data of offline model
start = datetime.datetime.now()
ret = acl.mdl.execute(self.model_id,
self.input_dataset,
self.output_dataset)
if ret != ACL_ERROR_NONE:
print("Execute model failed for acl.mdl.execute error ", ret)
return None
end = datetime.datetime.now()
print("acl.mdl.execute exhaust ", end - start)
# release input dataset object instance without releasing input data memory
#self._release_dataset(self.input_dataset)
# decode the binary data stream output from inference to numpy array, shape and datatype of the array are consistent with model outputs
return self._output_dataset_to_numpy()
def _output_dataset_to_numpy(self):
dataset = []
num = acl.mdl.get_dataset_num_buffers(self.output_dataset)
# iterative each output
for i in range(num):
# obtain memory address from output buffer
buffer = acl.mdl.get_dataset_buffer(self.output_dataset, i)
data = acl.get_data_buffer_addr(buffer)
size = int(acl.get_data_buffer_size(buffer))
output_ptr = self._output_info[i]["ptr"]
output_tensor = self._output_info[i]["tensor"]
ret = acl.rt.memcpy(output_ptr, output_tensor.size*output_tensor.itemsize,
data, size, ACL_MEMCPY_DEVICE_TO_DEVICE)
if ret != ACL_ERROR_NONE:
print("Memcpy inference output to local failed")
return None
dataset.append(output_tensor)
return dataset
def _release_dataset(self, dataset):
if not dataset:
return
print("destroy dataset")
num = acl.mdl.get_dataset_num_buffers(dataset)
for i in range(num):
data_buf = acl.mdl.get_dataset_buffer(dataset, i)
if data_buf:
ret = acl.destroy_data_buffer(data_buf)
if ret != ACL_ERROR_NONE:
print("Destroy data buffer error ", ret)
ret = acl.mdl.destroy_dataset(dataset)
if ret != ACL_ERROR_NONE:
print("Destroy data buffer error ", ret)
+38
View File
@@ -0,0 +1,38 @@
import acl
from atlas_utils.utils import *
class AclResource(object):
def __init__(self, device_id=0):
self.device_id = device_id
self.context = None
self.stream = None
self.run_mode = None
def init(self):
print("init resource stage:")
ret = acl.init()
check_ret("acl.rt.set_device", ret)
ret = acl.rt.set_device(self.device_id)
check_ret("acl.rt.set_device", ret)
self.context, ret = acl.rt.create_context(self.device_id)
check_ret("acl.rt.create_context", ret)
self.stream, ret = acl.rt.create_stream()
check_ret("acl.rt.create_stream", ret)
self.run_mode, ret = acl.rt.get_run_mode()
check_ret("acl.rt.get_run_mode", ret)
print("Init resource success")
def __del__(self):
if self.stream:
acl.rt.destroy_stream(self.stream)
if self.context:
acl.rt.destroy_context(self.context)
acl.rt.reset_device(self.device_id)
acl.finalize()
print("Release acl resource success")
View File
View File
+115
View File
@@ -0,0 +1,115 @@
import numpy as np
from PIL import Image
import copy
import acl
#from utils import *
from atlas_utils.constants import *
class AclImage():
def __init__(self, image, width=0, height=0,
size=0, memory_type=MEMORY_NORMAL):
self._data = None
self._np_array = None
self._memory_type = memory_type
self.width = 0
self.height = 0
self.channels = 0
self.size = 0
if isinstance(image, str):
self._instance_by_image_file(image)
elif str(type(image))=="<class 'numpy.ndarray'>":
self._instance_by_numpy_array(image,width,height)
elif isinstance(image, int):
self._instance_by_buffer(image, width, height, size)
else:
print("Create instance failed for unknow image data type")
def _instance_by_numpy_array(self, image,width,height):
self._data = image
self._type = IMAGE_DATA_NUMPY
self.size = self._data.itemsize * self._data.size
self.width = width
self.height = height
def _instance_by_image_file(self, image_path):
self._data = np.fromfile(image_path, dtype=np.byte)
self._type = IMAGE_DATA_NUMPY
self.size = self._data.itemsize * self._data.size
image = Image.open(image_path)
self.width, self.height = image.size
def _instance_by_buffer(self, image_buffer, width, height, size):
self.width = width
self.height = height
self.size = size
self._data = image_buffer
self._type = IMAGE_DATA_BUFFER
def tobytes(self):
if self._type == IMAGE_DATA_NUMPY:
return self._data
else:
return acl.util.ptr_to_numpy(self._data, (self.size, ), NPY_BYTE).tobytes()
def data(self):
if self._type == IMAGE_DATA_NUMPY:
return acl.util.numpy_to_ptr(self._data)
else:
return self._data
def copy_to_device(self, run_mode):
device_ptr = None
if run_mode == ACL_HOST:
device_ptr = copy_data_host_to_device(self.data(), self.size)
else:
device_ptr = copy_data_device_to_device(self.data(), self.size)
if device_ptr is None:
print("Copy image to device failed ")
return None
print("image copyt to device ", device_ptr, "%d, %d, %d"%(self.width,
self.height, self.size))
return AclImage(device_ptr, self.width,
self.height, self.size, MEMORY_DEVICE)
def copy_as_nparray(self):
if self._type == IMAGE_DATA_BUFFER:
#np_output = np.zeros(self.size, dtype=np.byte)
#if not np_output.flags['C_CONTIGUOUS']:
# np_output = np.ascontiguousarray(np_output)
np_output_ptr, ret = acl.rt.malloc(self.size, ACL_MEM_MALLOC_NORMAL_ONLY)
print("image ", np_output_ptr)
ret = acl.rt.memcpy(np_output_ptr, self.size, self._data, self.size, 3)
if (ret != ACL_ERROR_NONE):
print("Copy mage to np array failed for memcpy error ", ret)
return None
return copy.deepcopy(acl.util.ptr_to_numpy(np_output_ptr, (self.size, ), NPY_BYTE))
else:
return self._data.copy()
def destroy(self):
if (self._data is None) or (self.size == 0):
print("Release image abnormaly, data is None")
return
if self._memory_type == MEMORY_DEVICE:
acl.rt.free(self._data)
elif self._memory_type == MEMORY_HOST:
acl.rt.free_host(self._data)
elif self._memory_type == MEMORY_DVPP:
acl.media.dvpp_free(self._data)
self._data = None
self.size = 0
def __del__(self):
self.destroy()
+83
View File
@@ -0,0 +1,83 @@
# !/usr/bin/env python
# -*- coding:utf-8 -*-
#
from ctypes import *
import os
import time
import sys
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(BASE_DIR)
from lib.atlasutil_so import libatlas
from constants import *
from acl_image import AclImage
CAMERA_OK = 0
CAMERA_ERROR = 1
CAMERA_CLOSED = 0
CAMERA_OPENED = 1
INVALID_IMAGE_PTR = 0
class CameraOutputC(Structure):
_fields_ = [
('size', c_int),
('data', POINTER(c_ubyte))
]
class Camera():
def __init__(self, id, fps=20, size=(1280, 720)):
self._id = id
self._fps = fps
self._width = size[0]
self._height = size[1]
self._size = int(self._width * self._height * 3 / 2)
self._status = CAMERA_CLOSED
if CAMERA_OK == self._open():
self._status = CAMERA_OPENED
else:
print("Open camera %d failed"%(id))
def _open(self):
ret = libatlas.OpenCameraEx(self._id, self._fps,
self._width, self._height)
print(ret)
if (ret != CAMERA_OK):
print("ERROR:Open camera %d failed ,ret = %d"%(self._id, ret))
return CAMERA_ERROR
self._status = CAMERA_OPENED
return CAMERA_OK
def is_opened(self):
return (self._status == CAMERA_OPENED)
def read(self):
frame_data = CameraOutputC()
ret = libatlas.ReadCameraFrame(self._id, byref(frame_data))
if (ret != CAMERA_OK):
print("ERROR:Read camera %d failed"%(self._id))
return None
return AclImage(addressof(frame_data.data.contents),
self._width, self._height, self._size, MEMORY_DVPP)
def close(self):
print("Close camera ", self._id)
libatlas.CloseCameraEx(self._id)
def __del__(self):
self.close()
if __name__ == "__main__":
cap = Camera(id=0, fps=20, size=(1280, 720))
start = time.time()
for i in range(0,100):
image = cap.read()
print("Read 100 frame exhaust ", time.time() - start)
+188
View File
@@ -0,0 +1,188 @@
"""
Copyright (R) @huawei.com, all rights reserved
-*- coding:utf-8 -*-
CREATED: 2020-6-04 20:12:13
MODIFIED: 2020-6-06 14:04:45
"""
SUCCESS = 0
FAILED = 1
ACL_DEVICE = 0
ACL_HOST = 1
MEMORY_NORMAL = 0
MEMORY_HOST = 1
MEMORY_DEVICE = 2
MEMORY_DVPP = 3
MEMORY_CTYPES = 4
IMAGE_DATA_NUMPY = 0
IMAGE_DATA_BUFFER = 1
# error code
ACL_ERROR_NONE = 0
ACL_ERROR_INVALID_PARAM = 100000
ACL_ERROR_UNINITIALIZE = 100001
ACL_ERROR_REPEAT_INITIALIZE = 100002
ACL_ERROR_INVALID_FILE = 100003
ACL_ERROR_WRITE_FILE = 100004
ACL_ERROR_INVALID_FILE_SIZE = 100005
ACL_ERROR_PARSE_FILE = 100006
ACL_ERROR_FILE_MISSING_ATTR = 100007
ACL_ERROR_FILE_ATTR_INVALID = 100008
ACL_ERROR_INVALID_DUMP_CONFIG = 100009
ACL_ERROR_INVALID_PROFILING_CONFIG = 100010
ACL_ERROR_INVALID_MODEL_ID = 100011
ACL_ERROR_DESERIALIZE_MODEL = 100012
ACL_ERROR_PARSE_MODEL = 100013
ACL_ERROR_READ_MODEL_FAILURE = 100014
ACL_ERROR_MODEL_SIZE_INVALID = 100015
ACL_ERROR_MODEL_MISSING_ATTR = 100016
ACL_ERROR_MODEL_INPUT_NOT_MATCH = 100017
ACL_ERROR_MODEL_OUTPUT_NOT_MATCH = 100018
ACL_ERROR_MODEL_NOT_DYNAMIC = 100019
ACL_ERROR_OP_TYPE_NOT_MATCH = 100020
ACL_ERROR_OP_INPUT_NOT_MATCH = 100021
ACL_ERROR_OP_OUTPUT_NOT_MATCH = 100022
ACL_ERROR_OP_ATTR_NOT_MATCH = 100023
ACL_ERROR_OP_NOT_FOUND = 100024
ACL_ERROR_OP_LOAD_FAILED = 100025
ACL_ERROR_UNSUPPORTED_DATA_TYPE = 100026
ACL_ERROR_FORMAT_NOT_MATCH = 100027
ACL_ERROR_BIN_SELECTOR_NOT_REGISTERED = 100028
ACL_ERROR_KERNEL_NOT_FOUND = 100029
ACL_ERROR_BIN_SELECTOR_ALREADY_REGISTERED = 100030
ACL_ERROR_KERNEL_ALREADY_REGISTERED = 100031
ACL_ERROR_INVALID_QUEUE_ID = 100032
ACL_ERROR_REPEAT_SUBSCRIBE = 100033
ACL_ERROR_STREAM_NOT_SUBSCRIBE = 100034
ACL_ERROR_THREAD_NOT_SUBSCRIBE = 100035
ACL_ERROR_WAIT_CALLBACK_TIMEOUT = 100036
ACL_ERROR_REPEAT_FINALIZE = 100037
ACL_ERROR_BAD_ALLOC = 200000
ACL_ERROR_API_NOT_SUPPORT = 200001
ACL_ERROR_INVALID_DEVICE = 200002
ACL_ERROR_MEMORY_ADDRESS_UNALIGNED = 200003
ACL_ERROR_RESOURCE_NOT_MATCH = 200004
ACL_ERROR_INVALID_RESOURCE_HANDLE = 200005
ACL_ERROR_STORAGE_OVER_LIMIT = 300000
ACL_ERROR_INTERNAL_ERROR = 500000
ACL_ERROR_FAILURE = 500001
ACL_ERROR_GE_FAILURE = 500002
ACL_ERROR_RT_FAILURE = 500003
ACL_ERROR_DRV_FAILURE = 500004
# rule for mem
ACL_MEM_MALLOC_HUGE_FIRST = 0
ACL_MEM_MALLOC_HUGE_ONLY = 1
ACL_MEM_MALLOC_NORMAL_ONLY = 2
# rule for memory copy
ACL_MEMCPY_HOST_TO_HOST = 0
ACL_MEMCPY_HOST_TO_DEVICE = 1
ACL_MEMCPY_DEVICE_TO_HOST = 2
ACL_MEMCPY_DEVICE_TO_DEVICE = 3
# input
LAST_ONE = -1
LAST_TWO = -2
type_dict = {
"bool": 0,
"int8": 1,
"int16": 2,
"int32": 4,
"int64": 8,
"uint8": 1,
"uint16": 2,
"uint32": 4,
"uint64": 8,
"float16": 2,
"float32": 4,
"float64": 8,
"float_": 8
}
NPY_BOOL = 0
NPY_BYTE = 1
NPY_UBYTE = 2
NPY_SHORT = 3
NPY_USHORT = 4
NPY_INT = 5
NPY_UINT = 6
NPY_LONG = 7
NPY_ULONG = 8
NPY_LONGLONG = 9
NPY_ULONGLONG = 10
ACL_DT_UNDEFINED = -1
ACL_FLOAT = 0
ACL_FLOAT16 = 1
ACL_INT8 = 2
ACL_INT32 = 3
ACL_UINT8 = 4
ACL_INT16 = 6
ACL_UINT16 = 7
ACL_UINT32 = 8
ACL_INT64 = 9
ACL_UINT64 = 10
ACL_DOUBLE = 11
ACL_BOOL = 12
# data format
ACL_FORMAT_UNDEFINED = -1
ACL_FORMAT_NCHW = 0
ACL_FORMAT_NHWC = 1
ACL_FORMAT_ND = 2
ACL_FORMAT_NC1HWC0 = 3
ACL_FORMAT_FRACTAL_Z = 4
ACL_DT_UNDEFINED = -1
ACL_FLOAT = 0
ACL_FLOAT16 = 1
ACL_INT8 = 2
ACL_INT32 = 3
ACL_UINT8 = 4
ACL_INT16 = 6
ACL_UINT16 = 7
ACL_UINT32 = 8
ACL_INT64 = 9
ACL_UINT64 = 10
ACL_DOUBLE = 11
ACL_BOOL = 12
acl_dtype = {
"dt_undefined": -1,
"float": 0,
"float16": 1,
"int8": 2,
"int32": 3,
"uint8": 4,
"int16": 6,
"uint16": 7,
"uint32": 8,
"int64": 9,
"double": 11,
"bool": 12
}
ACL_CALLBACK_NO_BLOCK = 0
ACL_CALLBACK_BLOCK = 1
PIXEL_FORMAT_YUV_400 = 0 # 0, YUV400 8bit
PIXEL_FORMAT_YUV_SEMIPLANAR_420 = 1 # 1, YUV420SP NV12 8bit
PIXEL_FORMAT_YVU_SEMIPLANAR_420 = 2 # 2, YUV420SP NV21 8bit
PIXEL_FORMAT_YUV_SEMIPLANAR_422 = 3 # 3, YUV422SP NV12 8bit
PIXEL_FORMAT_YVU_SEMIPLANAR_422 = 4 # 4, YUV422SP NV21 8bit
PIXEL_FORMAT_YUV_SEMIPLANAR_444 = 5 # 5, YUV444SP NV12 8bit
PIXEL_FORMAT_YVU_SEMIPLANAR_444 = 6 # 6, YUV444SP NV21 8bit
PIXEL_FORMAT_YUYV_PACKED_422 = 7 # 7, YUV422P YUYV 8bit
PIXEL_FORMAT_UYVY_PACKED_422 = 8 # 8, YUV422P UYVY 8bit
PIXEL_FORMAT_YVYU_PACKED_422 = 9 # 9, YUV422P YVYU 8bit
PIXEL_FORMAT_VYUY_PACKED_422 = 10 # 10, YUV422P VYUY 8bit
PIXEL_FORMAT_YUV_PACKED_444 = 11 # 11, YUV444P 8bit
PIXEL_FORMAT_RGB_888 = 12 # 12, RGB888
PIXEL_FORMAT_BGR_888 = 13 # 13, BGR888
PIXEL_FORMAT_ARGB_8888 = 14 # 14, ARGB8888
PIXEL_FORMAT_ABGR_8888 = 15 # 15, ABGR8888
PIXEL_FORMAT_RGBA_8888 = 16 # 16, RGBA8888
PIXEL_FORMAT_BGRA_8888 = 17 # 17, BGRA8888
PIXEL_FORMAT_YUV_SEMI_PLANNER_420_10BIT = 18 # 18, YUV420SP 10bit
PIXEL_FORMAT_YVU_SEMI_PLANNER_420_10BIT = 19 # 19, YVU420sp 10bit
PIXEL_FORMAT_YVU_PLANAR_420 = 20 # 20, YUV420P 8bit
# images format
IMG_EXT = ['.jpg', '.JPG', '.png', '.PNG', '.bmp', '.BMP', '.jpeg', '.JPEG']
View File
+20
View File
@@ -0,0 +1,20 @@
import threading
import ctypes
import os
class _AtlasutilLib(object):
_instance_lock = threading.Lock()
lib = ctypes.CDLL(os.path.dirname(os.path.abspath(__file__)) + '/libatlasutil.so')
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
if not hasattr(_AtlasutilLib, "_instance"):
with _AtlasutilLib._instance_lock:
if not hasattr(_AtlasutilLib, "_instance"):
_AtlasutilLib._instance = object.__new__(cls)
return _AtlasutilLib._instance
libatlas = _AtlasutilLib.lib
Binary file not shown.
Binary file not shown.
+59
View File
@@ -0,0 +1,59 @@
TOPDIR := $(patsubst %,%,$(CURDIR))
ifndef DDK_PATH
$(error "Can not find DDK_PATH env, please set it in environment!.")
endif
LOCAL_MODULE_NAME := libatlasutil.so
CC := aarch64-linux-gnu-g++
LOCAL_DIR := .
OUT_DIR = out
OBJ_DIR = $(OUT_DIR)/obj
DEPS_DIR = $(OUT_DIR)/deps
LOCAL_LIBRARY=$(OUT_DIR)/$(LOCAL_MODULE_NAME)
OUT_INC_DIR = $(OUT_DIR)/include
INC_DIR = \
-I$(HOME)/Ascend/driver/ \
-I$(DDK_PATH)/../arm64-linux_gcc7.3.0/acllib/include/
CC_FLAGS := $(INC_DIR) -DENABLE_DVPP_INTERFACE -std=c++11 -fPIC -Wall -O2
LNK_FLAGS := \
-L$(NPU_HOST_LIB) \
-L$(HOME)/Ascend/driver \
-lmedia_mini \
-lascendcl \
-lacl_dvpp \
-shared
SRCS := $(patsubst $(LOCAL_DIR)/%.cpp, %.cpp, $(shell find $(LOCAL_DIR) -name "*.cpp"))
OBJS := $(addprefix $(OBJ_DIR)/, $(patsubst %.cpp, %.o,$(SRCS)))
ALL_OBJS := $(OBJS)
all: do_pre_build do_build
do_pre_build:
$(Q)echo - do [$@]
$(Q)mkdir -p $(OBJ_DIR)
$(Q)mkdir -p $(OUT_INC_DIR)
do_build: $(LOCAL_LIBRARY) | do_pre_build
$(Q)echo - do [$@]
$(LOCAL_LIBRARY): $(ALL_OBJS)
$(Q)echo [LD] $@
$(Q)$(CC) $(CC_FLAGS) -o $@ $^ -Wl,--whole-archive -Wl,--no-whole-archive -Wl,--start-group -Wl,--end-group -Wl,-rpath='/home/HwHiAiUser/HIAI_PROJECTS/ascend_lib' $(LNK_FLAGS)
$(OBJS): $(OBJ_DIR)/%.o : %.cpp | do_pre_build
$(Q)echo [CC] $@
$(Q)mkdir -p $(dir $@)
$(Q)$(CC) $(CC_FLAGS) $(INC_DIR) -c -fstack-protector-all $< -o $@
clean:
rm -rf $(TOPDIR)/out
+209
View File
@@ -0,0 +1,209 @@
/**
* ============================================================================
*
* Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1 Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2 Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3 Neither the names of the copyright holders nor the names of the
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* ============================================================================
*/
#include <memory>
#include <sys/time.h>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include "acl/acl.h"
#include "acl/ops/acl_dvpp.h"
#include "atlas_utils_common.h"
using namespace std;
extern "C" {
#if 0
void* CopyDataHostToDvpp(void* data, int size) {
void* buffer = nullptr;
auto aclRet = acldvppMalloc(&buffer, size);
if (aclRet != ACL_ERROR_NONE) {
ASC_LOG_ERROR("acl malloc dvpp data failed, dataSize=%u, ret=%d",
size, aclRet);
return nullptr;
}
printf("malloc dvpp memory size %d ok", size);
// copy input to device memory
aclRet = aclrtMemcpy(buffer, size, data, size, ACL_MEMCPY_HOST_TO_DEVICE);
if (aclRet != ACL_ERROR_NONE) {
ASC_LOG_ERROR("acl memcpy data to dvpp failed, size %u, error %d", size, aclRet);
acldvppFree(buffer);
return nullptr;
}
printf("copy data to dvpp ok");
return buffer;
}
void* CopyDataHostToDevice(void* data, int size) {
void* buffer = nullptr;
auto aclRet = aclrtMalloc(&buffer, size, ACL_MEM_MALLOC_NORMAL_ONLY);
if (aclRet != ACL_ERROR_NONE) {
ASC_LOG_ERROR("acl malloc device memory failed, dataSize=%u, ret=%d",
size, aclRet);
return nullptr;
}
// copy input to device memory
aclRet = aclrtMemcpy(buffer, size, data, size, ACL_MEMCPY_HOST_TO_DEVICE);
if (aclRet != ACL_ERROR_NONE) {
ASC_LOG_ERROR("acl memcpy data to dev failed, size %u, error %d", size, aclRet);
aclrtFree(buffer);
return nullptr;
}
return buffer;
}
void* CopyDataDeviceToDevice(void* data, int size) {
void* buffer = nullptr;
auto aclRet = aclrtMalloc(&buffer, size, ACL_MEM_MALLOC_NORMAL_ONLY);
if (aclRet != ACL_ERROR_NONE) {
ASC_LOG_ERROR("acl malloc device memory failed, dataSize=%u, ret=%d",
size, aclRet);
return nullptr;
}
// copy input to device memory
aclRet = aclrtMemcpy(buffer, size, data, size, ACL_MEMCPY_DEVICE_TO_DEVICE);
if (aclRet != ACL_ERROR_NONE) {
ASC_LOG_ERROR("acl memcpy data to dev failed, size %u, error %d", size, aclRet);
aclrtFree(buffer);
return nullptr;
}
return buffer;
}
void* CopyDataDeviceToHost(void* deviceData, uint32_t dataLen) {
void *outHostData = nullptr;
aclError ret = aclrtMallocHost(&outHostData, dataLen);
if (ret != ACL_ERROR_NONE) {
ASC_LOG_ERROR("aclrtMallocHost failed, ret[%d]", ret);
return nullptr;
}
ret = aclrtMemcpy(outHostData, dataLen, deviceData,
dataLen, ACL_MEMCPY_DEVICE_TO_HOST);
if (ret != ACL_ERROR_NONE) {
ASC_LOG_ERROR("aclrtMemcpy failed, ret[%d]", ret);
aclrtFreeHost(outHostData);
return nullptr;
}
return outHostData;
}
void* CopyDataDeviceToNewBuf(void* deviceData, uint32_t dataLen) {
uint8_t* outHostData = new uint8_t[dataLen];
/* aclError ret = aclrtMallocHost(&outHostData, dataLen);
if (ret != ACL_ERROR_NONE) {
ASC_LOG_ERROR("aclrtMallocHost failed, ret[%d]", ret);
return nullptr;
}
*/
int ret = aclrtMemcpy(outHostData, dataLen, deviceData,
dataLen, ACL_MEMCPY_DEVICE_TO_HOST);
if (ret != ACL_ERROR_NONE) {
ASC_LOG_ERROR("aclrtMemcpy failed, ret[%d]", ret);
aclrtFreeHost(outHostData);
return nullptr;
}
return (void *)outHostData;
}
void SaveBinFile(const char* filename, void* data, uint32_t size) {
FILE *outFileFp = fopen(filename, "wb+");
if (outFileFp == nullptr) {
ASC_LOG_ERROR("Save file %s failed for open error", filename);
return;
}
fwrite(data, 1, size, outFileFp);
fflush(outFileFp);
fclose(outFileFp);
}
char* ReadBinFile(const std::string& fileName, uint32_t& fileSize)
{
std::ifstream binFile(fileName, std::ifstream::binary);
if (binFile.is_open() == false) {
ASC_LOG_ERROR("open file %s failed", fileName.c_str());
return nullptr;
}
binFile.seekg(0, binFile.end);
uint32_t binFileBufferLen = binFile.tellg();
if (binFileBufferLen == 0) {
ASC_LOG_ERROR("binfile is empty, filename is %s", fileName.c_str());
binFile.close();
return nullptr;
}
binFile.seekg(0, binFile.beg);
char* binFileBufferData = new(std::nothrow) char[binFileBufferLen];
if (binFileBufferData == nullptr) {
ASC_LOG_ERROR("malloc binFileBufferData failed");
binFile.close();
return nullptr;
}
binFile.read(binFileBufferData, binFileBufferLen);
binFile.close();
fileSize = binFileBufferLen;
return binFileBufferData;
}
int ReadImageFile(ImageData* image, const string& filename) {
char* data;
uint32_t size = 0;
data = ReadBinFile(filename, size);
if (data == nullptr) {
ASC_LOG_ERROR("Read image file %s failed", filename.c_str());
return STATUS_ERROR;
}
image->data = SHARED_PRT_U8_BUF(data);
image->size = size;
printf("read image ok, size %d", size);
return STATUS_OK;
}
#endif
}
+130
View File
@@ -0,0 +1,130 @@
/**
* ============================================================================
*
* Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1 Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2 Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3 Neither the names of the copyright holders nor the names of the
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* ============================================================================
*/
#ifndef _ATLAS_UTILS_COMMON_H_
#define _ATLAS_UTILS_COMMON_H_
#include <memory>
#include <mutex>
#include <unistd.h>
#include <vector>
#include "acl/acl_base.h"
using namespace std;
#define STATUS_ERROR -1
#define STATUS_OK 0
#define ALIGN_UP(num, align) (((num) + (align) - 1) & ~((align) - 1))
#define ALIGN_UP2(num) ALIGN_UP(num, 2)
#define ALIGN_UP16(num) ALIGN_UP(num, 16)
#define ALIGN_UP128(num) ALIGN_UP(num, 128)
#define YUV420SP_SIZE(width, height) ((width) * (height) * 3 / 2)
//#define SHARED_PRT_DVPP_BUF(buf) (shared_ptr<uint8_t>((uint8_t *)(buf), [](uint8_t* p) { acldvppFree(p); }))
//#define SHARED_PRT_U8_BUF(buf) (shared_ptr<uint8_t>((uint8_t *)(buf), [](uint8_t* p) { delete[](p); }))
#define ASC_LOG_ERROR(fmt, ...) \
do{aclAppLog(ACL_ERROR, __FUNCTION__, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \
printf(fmt"\n", ##__VA_ARGS__);}while(0)
#define ASC_LOG_INFO(fmt, ...) \
do{aclAppLog(ACL_INFO, __FUNCTION__, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \
printf(fmt"\n", ##__VA_ARGS__);}while(0)
#define ASC_LOG_DEBUG(fmt, ...) \
do{aclAppLog(ACL_DEBUG, __FUNCTION__, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \
printf(fmt"\n", ##__VA_ARGS__);}while(0)
#if 0
struct ImageData {
bool isAligned = false;
uint32_t format = 1; //PIXEL_FORMAT_YUV_SEMIPLANAR_420;
uint32_t width = 0;
uint32_t height = 0;
uint32_t alignWidth = 0;
uint32_t alignHeight = 0;
uint32_t size = 0;
std::shared_ptr<uint8_t> data;
};
struct FrameData {
bool isFinished = false;
uint32_t width = 0;
uint32_t height = 0;
uint32_t frameId = 0;
ImageData image;
};
struct Resolution {
uint32_t width;
uint32_t height;
};
struct BoxArea {
uint32_t ltx;
uint32_t lty;
uint32_t width;
uint32_t height;
};
struct DataBuffer {
uint32_t size;
std::shared_ptr<void> data;
};
struct DetectionData {
ImageData image;
std::vector<DataBuffer> output;
};
struct AtlasMessage {
int dest;
int msgId;
std::shared_ptr<void> data;
};
extern "C" {
void* CopyDataDeviceToHost(void* deviceData, uint32_t dataLen);
void* CopyDataHostToDvpp(void* data, int size);
void* CopyDataHostToDevice(void* data, int size);
void* CopyDataDeviceToDevice(void* data, int size);
void* CopyDataDeviceToNewBuf(void* deviceData, uint32_t dataLen);
void SaveBinFile(const char* filename, void* data, uint32_t size);
int ReadImageFile(ImageData* image, const string& filename);
}
#endif
#endif /* HIAI_APP_IMAGE_POOL_H_ */
+164
View File
@@ -0,0 +1,164 @@
/**
* ============================================================================
*
* Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1 Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2 Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3 Neither the names of the copyright holders nor the names of the
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* ============================================================================
*/
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
#include <memory>
#include <sys/time.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "acl/acl.h"
#include "acl/ops/acl_dvpp.h"
#include "atlas_utils_common.h"
#include "camera.h"
using namespace std;
extern "C" {
#include "peripheral_api.h"
#include "camera.h"
CameraManager g_CameraMgr;
int CameraInit(int id, int fps, int width, int height) {
if (!g_CameraMgr.hwInited) {
MediaLibInit();
g_CameraMgr.hwInited = 1;
}
Camera& cap = CAMERA(id);
cap.frameSize = YUV420SP_SIZE(width, height);
cap.id = id;
cap.fps = fps;
cap.width = width;
cap.height = height;
cap.inited = true;
return STATUS_OK;
}
int ConfigCamera(int id, int fps, int width, int height) {
int ret = SetCameraProperty(id, CAMERA_PROP_FPS, &fps);
if (ret == LIBMEDIA_STATUS_FAILED) {
ASC_LOG_ERROR("Set camera fps failed");
return STATUS_ERROR;
}
CameraResolution resolution;
resolution.width = width;
resolution.height = height;
ret = SetCameraProperty(id, CAMERA_PROP_RESOLUTION, &resolution);
if (ret == LIBMEDIA_STATUS_FAILED) {
ASC_LOG_ERROR("Set camera resolution failed");
return STATUS_ERROR;
}
CameraCapMode mode = CAMERA_CAP_ACTIVE;
ret = SetCameraProperty(id, CAMERA_PROP_CAP_MODE, &mode);
if (ret == LIBMEDIA_STATUS_FAILED) {
ASC_LOG_ERROR("Set camera mode:%d failed", mode);
return STATUS_ERROR;
}
return STATUS_OK;
}
int OpenCameraEx(int id, int fps, int width, int height) {
if ((id < 0) || (id >= CAMERA_NUM)) {
ASC_LOG_ERROR("Open camera failed for invalid id %d", id);
return STATUS_ERROR;
}
if (!CAMERA(id).inited) {
CameraInit(id, fps, width, height);
}
CameraStatus status = QueryCameraStatus(id);
if (status == CAMERA_STATUS_CLOSED){
// Open Camera
if (LIBMEDIA_STATUS_FAILED == OpenCamera(id)) {
ASC_LOG_ERROR("Camera%d closed, and open failed.", id);
return STATUS_ERROR;
}
} else if (status != CAMERA_STATUS_OPEN) {
ASC_LOG_ERROR("Invalid camera%d status %d", id, status);
return STATUS_ERROR;
}
//Set camera property
if (STATUS_OK != ConfigCamera(id, fps, width, height)) {
CloseCamera(id);
ASC_LOG_ERROR("Set camera%d property failed", id);
return STATUS_ERROR;
}
ASC_LOG_INFO("Open camera %d success", id);
return STATUS_OK;
}
int ReadCameraFrame(int id, CameraOutput& frame) {
int size = CAMERA(id).frameSize;
void* data = nullptr;
auto aclRet = acldvppMalloc(&data, size);
if (aclRet != ACL_ERROR_NONE) {
ASC_LOG_ERROR("acl malloc dvpp data failed, dataSize=%u, ret=%d",
size, aclRet);
return STATUS_ERROR;
}
int ret = ReadFrameFromCamera(id, (void*)data, (int *)&size);
if ((ret == LIBMEDIA_STATUS_FAILED) ||
(size != CAMERA(id).frameSize)) {
acldvppFree(data);
ASC_LOG_ERROR("Get image from camera %d failed, size %d", id, size);
return STATUS_ERROR;
}
frame.size = size;
frame.data = (uint8_t*)data;
ASC_LOG_INFO("cpp image ptr 0x%x", data);
return STATUS_OK;
}
int CloseCameraEx(int cameraId) {
if (LIBMEDIA_STATUS_FAILED == CloseCamera(cameraId)) {
ASC_LOG_ERROR("Close camera %d failed", cameraId);
return STATUS_ERROR;
}
return STATUS_OK;
}
}
+63
View File
@@ -0,0 +1,63 @@
/**
* ============================================================================
*
* Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1 Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2 Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3 Neither the names of the copyright holders nor the names of the
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* ============================================================================
*/
#ifndef _CAMERA_H
#define _CAMERA_H
#define CAMERA_NUM (2)
#define CAMERA(i) (g_CameraMgr.cap[i])
struct CameraOutput {
int size;
uint8_t* data;
};
struct Camera {
bool inited = false;
int id = 255;
int fps = 0;
int width = 0;
int height = 0;
int frameSize = 0;
};
struct CameraManager {
bool hwInited = 0;
Camera cap[CAMERA_NUM];
};
#endif
Binary file not shown.
Binary file not shown.
Binary file not shown.
+6
View File
@@ -0,0 +1,6 @@
from .presenter_datatype import *
from .presenter_agent import *
from .presenter_channel import *
#from .presenter_message_pb2 import *
__all__ = ['presenter_datatype.py', 'presenter_agent', 'presenter_channel', 'presenter_message_pb']
@@ -0,0 +1,75 @@
# !/usr/bin/env python
# -*- coding:utf-8 -*-
import time
from threading import Thread
from .socket_client import AgentSocket
from . import presenter_message as pm
from . import presenter_datatype as datatype
class PresenterAgent():
def __init__(self, server_ip, port):
self.socket = AgentSocket(server_ip, port)
self._closed = False
def connect_server(self):
return self.socket.connect()
def start_heard_beat_thread(self):
self.heart_beat_thread = Thread(target=self._keep_alive)
self.heart_beat_thread.start()
def _keep_alive(self):
msg = pm.heartbeat_message()
while True:
if self._closed:
print("ERROR:Heard beat thread exit")
break
self.socket.send_msg(msg)
time.sleep(2)
def exit(self):
self.socket.close()
self._closed = True
def StartPresenterAgent(msg_queue, server_ip, port, open_status, data_respone_counter):
agent = PresenterAgent(server_ip, port)
ret = agent.connect_server()
if ret:
print("ERROR:Connect server failed, ret =", ret)
return
open_status.value = datatype.STATUS_CONNECTED
while True:
data = msg_queue.get()
if open_status.value == datatype.STATUS_EXITING:
open_status.value = datatype.STATUS_EXITTED
agent.exit()
break
if data:
agent.socket.send_msg(data)
msg_name, msg_body = agent.socket.recv_msg()
if (msg_name == None) or (msg_body == None):
print("ERROR:Recv invalid message, message name ", msg_name)
continue
if ((open_status.value == datatype.STATUS_CONNECTED)
and pm.is_open_channel_response(msg_name)):
print("Received open channel respone")
open_status.value = datatype.STATUS_OPENED
agent.start_heard_beat_thread()
print("presenter agent change connect_status to ", open_status.value)
if ((open_status.value == datatype.STATUS_OPENED) and
pm.is_image_frame_response(msg_name)):
data_respone_counter.value += 1
print("send ok ", data_respone_counter.value)
@@ -0,0 +1,159 @@
# !/usr/bin/env python
# -*- coding:utf-8 -*-
import ctypes
from ctypes import *
import time
import configparser
from multiprocessing import Process, Queue, Manager
import queue
import numpy as np
import sys
sys.path.append('..')
import acl
from ..constants import *
from ..lib.atlasutil_so import libatlas
from .presenter_datatype import *
from . import presenter_agent as agent
from . import presenter_message as pm
class DataBufC(Structure):
_fields_ = [
('size', c_int),
('data', POINTER(c_ubyte))
]
class DataBuf():
def __init__(self, data, data_size):
self.data = data
self.size = data_size
self.nparray = None
def copy_to_local(self):
src_data = DataBufC()
src_data.data = cast(self.data, POINTER(c_ubyte))
src_data.size = self.size
dest_data = DataBufC()
ret = libatlas.CopyDataToLocal(byref(dest_data), byref(src_data))
if ret:
print("Copy data to local failed")
return None
return DataBuf(dest_data.data, dest_data.size)
def tobytes(self):
self.nparray = np.frombuffer((ctypes.c_ubyte * self.size).from_address(ctypes.addressof(self.data.contents)), dtype=np.uint8)
return self.nparray.tobytes()
def destroy(self):
data_buf = DataBufC()
data_buf.data = cast(self.data, POINTER(c_ubyte))
data_buf.size = self.size
libatlas.ReleaseDataBuf(byref(data_buf))
self.data = None
self.size = 0
class PresenterChannel():
def __init__(self, server_ip, port, name='video', type=CONTENT_TYPE_VIDEO):
self._server_ip = server_ip
self._port = port
self._type = type
self._name = name
self.agent_msg_queue = Queue()
self.open_status = Manager().Value('i', STATUS_DISCONNECT)
self.data_respone_counter = Manager().Value('i', 0)
self._send_counter = 0
self._send_buffer = queue.Queue(64)
self.send_cnt = 0
self.relase_cnt = 0
def startup(self):
agent_process = Process(target=agent.StartPresenterAgent,
args=(self.agent_msg_queue, self._server_ip,self._port,
self.open_status, self.data_respone_counter))
agent_process.start()
time.sleep(0.5)
self._send_open_channel_request(self._name, self._type)
return self._wait_open_status(STATUS_OPENED)
def _wait_open_status(self, listen_status):
ret = STATUS_ERROR
for i in range(0, 100):
time.sleep(0.1)
if self.open_status.value == listen_status:
print("Open status is %d now"%(listen_status))
ret = STATUS_OK
break
return ret
def send_message(self, data):
self.agent_msg_queue.put(data)
self._send_counter += 1
def _send_open_channel_request(self, channel_name, content_type):
request_msg = pm.open_channel_request(channel_name, content_type)
self.send_message(request_msg)
def _release_send_success_data(self):
release_num = self._send_buffer.qsize() - \
(self._send_counter - self.data_respone_counter.value)
if release_num > 0:
for i in range(0, release_num):
data = self._send_buffer.get_nowait()
data.destroy()
data = None
self.relase_cnt += 1
#print("Released send success images ", self.relase_cnt)
def send_detection_data(self, image_width, image_height,
image_data, detection_result):
if self._send_buffer.full() is True:
print("ERROR:Send detection data failed for buffer is full")
return False
image_buf = DataBuf(image_data.data(), image_data.size).copy_to_local()
request_msg = pm.image_frame_request(image_width, image_height,
image_buf.tobytes(), detection_result)
self.send_message(request_msg)
self._send_buffer.put(image_buf)
self._release_send_success_data()
return True
def _send_heart_beat_message(self):
msg = pm.heartbeat_message()
self.send_message(msg)
def __del__(self):
self.open_status.value = STATUS_EXITING
print("Presenter channel close...")
self._send_heart_beat_message()
if STATUS_OK == self._wait_open_status(STATUS_EXITTED):
print("Presenter channel closed")
else:
print("Presenter channel close failed for presenter agent no response")
def get_presenter_server_addr(config_file):
config = configparser.ConfigParser()
config.read(config_file)
presenter_server_ip = config['baseconf']['presenter_server_ip']
port = int(config['baseconf']['presenter_server_port'])
print("presenter server ip %s, port %d"%(presenter_server_ip, port))
return presenter_server_ip, port
def open_channel(config_file, channel_name='video', channel_type = CONTENT_TYPE_VIDEO):
server_ip, port = get_presenter_server_addr(config_file)
channel = PresenterChannel(server_ip, port, channel_name, channel_type)
ret = channel.startup()
if ret:
print("ERROR:Open channel failed")
return None
return channel
@@ -0,0 +1,38 @@
STATUS_DISCONNECT = 0
STATUS_CONNECTED = 1
STATUS_OPEN_CH_REQUEST = 2
STATUS_OPENED = 3
STATUS_EXITING = 4
STATUS_EXITTED = 5
CONTENT_TYPE_IMAGE = 0
CONTENT_TYPE_VIDEO = 1
STATUS_OK = 0
STATUS_ERROR = 1
class Point():
def __init__(self, x=0, y=0):
self.x = x
self.y = y
class Box():
def __init__(self, lt, rb):
self.lt = Point(lt)
self.rb = Point(rb)
def box_valid(self):
return ((self.lt.x >= 0)
and (self.lt.y >= 0)
and (self.rb.x >= self.lt.x)
and (self.rb.y >= self.lt.y))
class ObjectDetectionResult():
def __init__(self, ltx=0, lty=0, rbx=0, rby=0, text=None):
self.object_class = 0
self.confidence = 0
self.box = Box((ltx, lty), (rbx, rby))
self.result_text = text
@@ -0,0 +1,67 @@
syntax = "proto3";
package ascend.presenter.proto;
enum OpenChannelErrorCode {
kOpenChannelErrorNone = 0;
kOpenChannelErrorNoSuchChannel = 1;
kOpenChannelErrorChannelAlreadyOpened = 2;
kOpenChannelErrorOther = -1;
}
enum ChannelContentType {
kChannelContentTypeImage = 0;
kChannelContentTypeVideo = 1;
}
// By Protocol Buffer Style Guide, need to use underscore_separated_names
// for field names
message OpenChannelRequest {
string channel_name = 1;
ChannelContentType content_type = 2;
}
message OpenChannelResponse {
OpenChannelErrorCode error_code = 1;
string error_message = 2;
}
message HeartbeatMessage {
}
enum ImageFormat {
kImageFormatJpeg = 0;
}
message Coordinate {
uint32 x = 1;
uint32 y = 2;
}
message Rectangle_Attr {
Coordinate left_top = 1;
Coordinate right_bottom = 2;
string label_text = 3;
}
message PresentImageRequest {
ImageFormat format = 1;
uint32 width = 2;
uint32 height = 3;
bytes data = 4;
repeated Rectangle_Attr rectangle_list = 5;
}
enum PresentDataErrorCode {
kPresentDataErrorNone = 0;
kPresentDataErrorUnsupportedType = 1;
kPresentDataErrorUnsupportedFormat = 2;
kPresentDataErrorOther = -1;
}
message PresentImageResponse {
PresentDataErrorCode error_code = 1;
string error_message = 2;
}
@@ -0,0 +1,56 @@
# !/usr/bin/env python
# -*- coding:utf-8 -*-
import struct
import socket
from . import presenter_message_pb2 as pb2
def pack_message(msg_name, msg_data):
buf = msg_data.SerializeToString()
msg_body_len = len(buf)
msg_name_len = len(msg_name)
msg_total_len = msg_name_len + msg_body_len + 5
data = b''
msg_total_len = socket.htonl(msg_total_len)
pack_data = struct.pack('IB', msg_total_len, msg_name_len)
data += pack_data
data += msg_name.encode()
data += buf
return data
def open_channel_request(channel_name, content_type):
request = pb2.OpenChannelRequest()
request.channel_name = channel_name
request.content_type = content_type
return pack_message(pb2._OPENCHANNELREQUEST.full_name, request)
def image_frame_request(image_width, image_height, image_data, detection_result):
request = pb2.PresentImageRequest()
request.format = 0
request.width = image_width
request.height = image_height
request.data = image_data
for i in range(0, len(detection_result)):
myadd = request.rectangle_list.add()
myadd.left_top.x = detection_result[i].box.lt.x
myadd.left_top.y = detection_result[i].box.lt.y
myadd.right_bottom.x = detection_result[i].box.rb.x
myadd.right_bottom.y = detection_result[i].box.rb.y
myadd.label_text = detection_result[i].result_text
return pack_message(pb2._PRESENTIMAGEREQUEST.full_name, request)
def heartbeat_message():
return pack_message(pb2._HEARTBEATMESSAGE.full_name, pb2.HeartbeatMessage())
def is_open_channel_response(msg_name):
return (msg_name == pb2._OPENCHANNELRESPONSE.full_name)
def is_image_frame_response(msg_name):
return (msg_name == pb2._PRESENTIMAGERESPONSE.full_name)
@@ -0,0 +1,493 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: presenter_message.proto
import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf.internal import enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
from google.protobuf import descriptor_pb2
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='presenter_message.proto',
package='ascend.presenter.proto',
syntax='proto3',
serialized_pb=_b('\n\x17presenter_message.proto\x12\x16\x61scend.presenter.proto\"l\n\x12OpenChannelRequest\x12\x14\n\x0c\x63hannel_name\x18\x01 \x01(\t\x12@\n\x0c\x63ontent_type\x18\x02 \x01(\x0e\x32*.ascend.presenter.proto.ChannelContentType\"n\n\x13OpenChannelResponse\x12@\n\nerror_code\x18\x01 \x01(\x0e\x32,.ascend.presenter.proto.OpenChannelErrorCode\x12\x15\n\rerror_message\x18\x02 \x01(\t\"\x12\n\x10HeartbeatMessage\"\"\n\nCoordinate\x12\t\n\x01x\x18\x01 \x01(\r\x12\t\n\x01y\x18\x02 \x01(\r\"\x94\x01\n\x0eRectangle_Attr\x12\x34\n\x08left_top\x18\x01 \x01(\x0b\x32\".ascend.presenter.proto.Coordinate\x12\x38\n\x0cright_bottom\x18\x02 \x01(\x0b\x32\".ascend.presenter.proto.Coordinate\x12\x12\n\nlabel_text\x18\x03 \x01(\t\"\xb7\x01\n\x13PresentImageRequest\x12\x33\n\x06\x66ormat\x18\x01 \x01(\x0e\x32#.ascend.presenter.proto.ImageFormat\x12\r\n\x05width\x18\x02 \x01(\r\x12\x0e\n\x06height\x18\x03 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x12>\n\x0erectangle_list\x18\x05 \x03(\x0b\x32&.ascend.presenter.proto.Rectangle_Attr\"o\n\x14PresentImageResponse\x12@\n\nerror_code\x18\x01 \x01(\x0e\x32,.ascend.presenter.proto.PresentDataErrorCode\x12\x15\n\rerror_message\x18\x02 \x01(\t*\xa5\x01\n\x14OpenChannelErrorCode\x12\x19\n\x15kOpenChannelErrorNone\x10\x00\x12\"\n\x1ekOpenChannelErrorNoSuchChannel\x10\x01\x12)\n%kOpenChannelErrorChannelAlreadyOpened\x10\x02\x12#\n\x16kOpenChannelErrorOther\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01*P\n\x12\x43hannelContentType\x12\x1c\n\x18kChannelContentTypeImage\x10\x00\x12\x1c\n\x18kChannelContentTypeVideo\x10\x01*#\n\x0bImageFormat\x12\x14\n\x10kImageFormatJpeg\x10\x00*\xa4\x01\n\x14PresentDataErrorCode\x12\x19\n\x15kPresentDataErrorNone\x10\x00\x12$\n kPresentDataErrorUnsupportedType\x10\x01\x12&\n\"kPresentDataErrorUnsupportedFormat\x10\x02\x12#\n\x16kPresentDataErrorOther\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x62\x06proto3')
)
_OPENCHANNELERRORCODE = _descriptor.EnumDescriptor(
name='OpenChannelErrorCode',
full_name='ascend.presenter.proto.OpenChannelErrorCode',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='kOpenChannelErrorNone', index=0, number=0,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='kOpenChannelErrorNoSuchChannel', index=1, number=1,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='kOpenChannelErrorChannelAlreadyOpened', index=2, number=2,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='kOpenChannelErrorOther', index=3, number=-1,
options=None,
type=None),
],
containing_type=None,
options=None,
serialized_start=780,
serialized_end=945,
)
_sym_db.RegisterEnumDescriptor(_OPENCHANNELERRORCODE)
OpenChannelErrorCode = enum_type_wrapper.EnumTypeWrapper(_OPENCHANNELERRORCODE)
_CHANNELCONTENTTYPE = _descriptor.EnumDescriptor(
name='ChannelContentType',
full_name='ascend.presenter.proto.ChannelContentType',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='kChannelContentTypeImage', index=0, number=0,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='kChannelContentTypeVideo', index=1, number=1,
options=None,
type=None),
],
containing_type=None,
options=None,
serialized_start=947,
serialized_end=1027,
)
_sym_db.RegisterEnumDescriptor(_CHANNELCONTENTTYPE)
ChannelContentType = enum_type_wrapper.EnumTypeWrapper(_CHANNELCONTENTTYPE)
_IMAGEFORMAT = _descriptor.EnumDescriptor(
name='ImageFormat',
full_name='ascend.presenter.proto.ImageFormat',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='kImageFormatJpeg', index=0, number=0,
options=None,
type=None),
],
containing_type=None,
options=None,
serialized_start=1029,
serialized_end=1064,
)
_sym_db.RegisterEnumDescriptor(_IMAGEFORMAT)
ImageFormat = enum_type_wrapper.EnumTypeWrapper(_IMAGEFORMAT)
_PRESENTDATAERRORCODE = _descriptor.EnumDescriptor(
name='PresentDataErrorCode',
full_name='ascend.presenter.proto.PresentDataErrorCode',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='kPresentDataErrorNone', index=0, number=0,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='kPresentDataErrorUnsupportedType', index=1, number=1,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='kPresentDataErrorUnsupportedFormat', index=2, number=2,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='kPresentDataErrorOther', index=3, number=-1,
options=None,
type=None),
],
containing_type=None,
options=None,
serialized_start=1067,
serialized_end=1231,
)
_sym_db.RegisterEnumDescriptor(_PRESENTDATAERRORCODE)
PresentDataErrorCode = enum_type_wrapper.EnumTypeWrapper(_PRESENTDATAERRORCODE)
kOpenChannelErrorNone = 0
kOpenChannelErrorNoSuchChannel = 1
kOpenChannelErrorChannelAlreadyOpened = 2
kOpenChannelErrorOther = -1
kChannelContentTypeImage = 0
kChannelContentTypeVideo = 1
kImageFormatJpeg = 0
kPresentDataErrorNone = 0
kPresentDataErrorUnsupportedType = 1
kPresentDataErrorUnsupportedFormat = 2
kPresentDataErrorOther = -1
_OPENCHANNELREQUEST = _descriptor.Descriptor(
name='OpenChannelRequest',
full_name='ascend.presenter.proto.OpenChannelRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='channel_name', full_name='ascend.presenter.proto.OpenChannelRequest.channel_name', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='content_type', full_name='ascend.presenter.proto.OpenChannelRequest.content_type', index=1,
number=2, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=51,
serialized_end=159,
)
_OPENCHANNELRESPONSE = _descriptor.Descriptor(
name='OpenChannelResponse',
full_name='ascend.presenter.proto.OpenChannelResponse',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='error_code', full_name='ascend.presenter.proto.OpenChannelResponse.error_code', index=0,
number=1, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='error_message', full_name='ascend.presenter.proto.OpenChannelResponse.error_message', index=1,
number=2, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=161,
serialized_end=271,
)
_HEARTBEATMESSAGE = _descriptor.Descriptor(
name='HeartbeatMessage',
full_name='ascend.presenter.proto.HeartbeatMessage',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=273,
serialized_end=291,
)
_COORDINATE = _descriptor.Descriptor(
name='Coordinate',
full_name='ascend.presenter.proto.Coordinate',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='x', full_name='ascend.presenter.proto.Coordinate.x', index=0,
number=1, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='y', full_name='ascend.presenter.proto.Coordinate.y', index=1,
number=2, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=293,
serialized_end=327,
)
_RECTANGLE_ATTR = _descriptor.Descriptor(
name='Rectangle_Attr',
full_name='ascend.presenter.proto.Rectangle_Attr',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='left_top', full_name='ascend.presenter.proto.Rectangle_Attr.left_top', index=0,
number=1, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='right_bottom', full_name='ascend.presenter.proto.Rectangle_Attr.right_bottom', index=1,
number=2, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='label_text', full_name='ascend.presenter.proto.Rectangle_Attr.label_text', index=2,
number=3, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=330,
serialized_end=478,
)
_PRESENTIMAGEREQUEST = _descriptor.Descriptor(
name='PresentImageRequest',
full_name='ascend.presenter.proto.PresentImageRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='format', full_name='ascend.presenter.proto.PresentImageRequest.format', index=0,
number=1, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='width', full_name='ascend.presenter.proto.PresentImageRequest.width', index=1,
number=2, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='height', full_name='ascend.presenter.proto.PresentImageRequest.height', index=2,
number=3, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='data', full_name='ascend.presenter.proto.PresentImageRequest.data', index=3,
number=4, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='rectangle_list', full_name='ascend.presenter.proto.PresentImageRequest.rectangle_list', index=4,
number=5, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=481,
serialized_end=664,
)
_PRESENTIMAGERESPONSE = _descriptor.Descriptor(
name='PresentImageResponse',
full_name='ascend.presenter.proto.PresentImageResponse',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='error_code', full_name='ascend.presenter.proto.PresentImageResponse.error_code', index=0,
number=1, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='error_message', full_name='ascend.presenter.proto.PresentImageResponse.error_message', index=1,
number=2, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=666,
serialized_end=777,
)
_OPENCHANNELREQUEST.fields_by_name['content_type'].enum_type = _CHANNELCONTENTTYPE
_OPENCHANNELRESPONSE.fields_by_name['error_code'].enum_type = _OPENCHANNELERRORCODE
_RECTANGLE_ATTR.fields_by_name['left_top'].message_type = _COORDINATE
_RECTANGLE_ATTR.fields_by_name['right_bottom'].message_type = _COORDINATE
_PRESENTIMAGEREQUEST.fields_by_name['format'].enum_type = _IMAGEFORMAT
_PRESENTIMAGEREQUEST.fields_by_name['rectangle_list'].message_type = _RECTANGLE_ATTR
_PRESENTIMAGERESPONSE.fields_by_name['error_code'].enum_type = _PRESENTDATAERRORCODE
DESCRIPTOR.message_types_by_name['OpenChannelRequest'] = _OPENCHANNELREQUEST
DESCRIPTOR.message_types_by_name['OpenChannelResponse'] = _OPENCHANNELRESPONSE
DESCRIPTOR.message_types_by_name['HeartbeatMessage'] = _HEARTBEATMESSAGE
DESCRIPTOR.message_types_by_name['Coordinate'] = _COORDINATE
DESCRIPTOR.message_types_by_name['Rectangle_Attr'] = _RECTANGLE_ATTR
DESCRIPTOR.message_types_by_name['PresentImageRequest'] = _PRESENTIMAGEREQUEST
DESCRIPTOR.message_types_by_name['PresentImageResponse'] = _PRESENTIMAGERESPONSE
DESCRIPTOR.enum_types_by_name['OpenChannelErrorCode'] = _OPENCHANNELERRORCODE
DESCRIPTOR.enum_types_by_name['ChannelContentType'] = _CHANNELCONTENTTYPE
DESCRIPTOR.enum_types_by_name['ImageFormat'] = _IMAGEFORMAT
DESCRIPTOR.enum_types_by_name['PresentDataErrorCode'] = _PRESENTDATAERRORCODE
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
OpenChannelRequest = _reflection.GeneratedProtocolMessageType('OpenChannelRequest', (_message.Message,), dict(
DESCRIPTOR = _OPENCHANNELREQUEST,
__module__ = 'presenter_message_pb2'
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.OpenChannelRequest)
))
_sym_db.RegisterMessage(OpenChannelRequest)
OpenChannelResponse = _reflection.GeneratedProtocolMessageType('OpenChannelResponse', (_message.Message,), dict(
DESCRIPTOR = _OPENCHANNELRESPONSE,
__module__ = 'presenter_message_pb2'
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.OpenChannelResponse)
))
_sym_db.RegisterMessage(OpenChannelResponse)
HeartbeatMessage = _reflection.GeneratedProtocolMessageType('HeartbeatMessage', (_message.Message,), dict(
DESCRIPTOR = _HEARTBEATMESSAGE,
__module__ = 'presenter_message_pb2'
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.HeartbeatMessage)
))
_sym_db.RegisterMessage(HeartbeatMessage)
Coordinate = _reflection.GeneratedProtocolMessageType('Coordinate', (_message.Message,), dict(
DESCRIPTOR = _COORDINATE,
__module__ = 'presenter_message_pb2'
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.Coordinate)
))
_sym_db.RegisterMessage(Coordinate)
Rectangle_Attr = _reflection.GeneratedProtocolMessageType('Rectangle_Attr', (_message.Message,), dict(
DESCRIPTOR = _RECTANGLE_ATTR,
__module__ = 'presenter_message_pb2'
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.Rectangle_Attr)
))
_sym_db.RegisterMessage(Rectangle_Attr)
PresentImageRequest = _reflection.GeneratedProtocolMessageType('PresentImageRequest', (_message.Message,), dict(
DESCRIPTOR = _PRESENTIMAGEREQUEST,
__module__ = 'presenter_message_pb2'
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.PresentImageRequest)
))
_sym_db.RegisterMessage(PresentImageRequest)
PresentImageResponse = _reflection.GeneratedProtocolMessageType('PresentImageResponse', (_message.Message,), dict(
DESCRIPTOR = _PRESENTIMAGERESPONSE,
__module__ = 'presenter_message_pb2'
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.PresentImageResponse)
))
_sym_db.RegisterMessage(PresentImageResponse)
# @@protoc_insertion_point(module_scope)
+119
View File
@@ -0,0 +1,119 @@
# !/usr/bin/env python
# -*- coding:utf-8 -*-
import threading
import socket
import time
import struct
import time
from .presenter_datatype import *
class AgentSocket(object):
def __init__(self, server_ip, port):
self._server_address = (server_ip, port)
self._sock_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def connect(self):
ret = 0
for i in range(0,5):
ret = self._sock_client.connect_ex(self._server_address)
if ret == 0:
break
time.sleep(0.2)
return ret
def _read_socket(self, read_len):
has_read_len = 0
read_buf = b''
total_buf = b''
while has_read_len != read_len:
try:
read_buf = self._sock_client.recv(read_len - has_read_len)
except socket.error:
print("ERROR:Read socket failed")
return False, None
if read_buf == b'':
return False, None
total_buf += read_buf
has_read_len = len(total_buf)
return True, total_buf
def _read_msg_head(self, read_len):
ret, msg_head = self._read_socket(read_len)
#print("msg head data is :", msg_head)
if not ret:
print("ERROR:socket receive msg head null")
return None, None
# in Struct(), 'I' is unsigned int, 'B' is unsigned char
msg_head_data = struct.Struct('IB')
(msg_total_len, msg_name_len) = msg_head_data.unpack(msg_head)
msg_total_len = socket.ntohl(msg_total_len)
#print("msg total length is :", msg_total_len)
#print("msg name is :", msg_name_len)
return msg_total_len, msg_name_len
def _read_msg_name(self, msg_name_len):
ret, msg_name = self._read_socket(msg_name_len)
#print("direct msg name is :", msg_name)
if not ret:
print("ERROR:socket receive msg name null")
return False, None
try:
msg_name = msg_name.decode("utf-8")
#print("decode msg name is :", msg_name)
except Exception as e:
print("ERROR:msg name decode to utf-8 error")
return False, None
return True, msg_name
def _read_msg_body(self, msg_body_len):
#print("msg body length is :", msg_body_len)
ret, msg_body = self._read_socket(msg_body_len)
if not ret:
print("ERROR:socket receive msg body null")
return False, None
return True, msg_body
def recv_msg(self):
# Step1: read msg head
msg_total_len, msg_name_len = self._read_msg_head(5)
if msg_total_len is None:
print("ERROR:msg total len is None.")
return None
# Step2: read msg name
ret, msg_name = self._read_msg_name(msg_name_len)
if not ret:
return None
# Step3: read msg body
msg_body_len = msg_total_len - 5 - msg_name_len
if msg_body_len < 0:
print("ERROR:msg total len is 0")
return None
ret, msg_body = self._read_msg_body(msg_body_len)
if not ret:
return None
return msg_name, msg_body
def send_msg(self, data):
try:
self._sock_client.sendall(data)
except Exception as e:
print("ERROR:Send msg failed")
return 1
return 0
def close(self):
self._sock_client.shutdown(socket.SHUT_RDWR)
self._sock_client.close()
+71
View File
@@ -0,0 +1,71 @@
import acl
from atlas_utils.constants import *
from atlas_utils.lib.atlasutil_so import libatlas
def check_ret(message, ret):
if ret != ACL_ERROR_NONE:
raise Exception("{} failed ret={}"
.format(message, ret))
def copy_data_device_to_host(device_data, data_size):
host_buffer, ret = acl.rt.malloc_host(data_size)
if ret != ACL_ERROR_NONE:
print("Malloc host memory failed, error: ", ret)
return None
ret = acl.rt.memcpy(host_buffer, data_size,
device_data, data_size,
ACL_MEMCPY_DEVICE_TO_HOST)
if ret != ACL_ERROR_NONE:
print("Copy device data to host memory failed, error: ", ret)
acl.rt.free_host(host_buffer)
return None
return host_buffer
def copy_data_device_to_device(device_data, data_size):
device_buffer, ret = acl.rt.malloc(data_size, ACL_MEM_MALLOC_NORMAL_ONLY)
if ret != ACL_ERROR_NONE:
print("Malloc device memory failed, error: ", ret)
return None
ret = acl.rt.memcpy(device_buffer, data_size,
device_data, data_size,
ACL_MEMCPY_DEVICE_TO_DEVICE)
if ret != ACL_ERROR_NONE:
print("Copy device data to device memory failed, error: ", ret)
acl.rt.free(device_buffer)
return None
return device_buffer
def copy_data_host_to_device(host_data, data_size):
device_buffer, ret = acl.rt.malloc(data_size, ACL_MEM_MALLOC_NORMAL_ONLY)
if ret != ACL_ERROR_NONE:
print("Malloc device memory failed, error: ", ret)
return None
ret = acl.rt.memcpy(device_buffer, data_size,
host_data, data_size,
ACL_MEMCPY_HOST_TO_DEVICE)
if ret != ACL_ERROR_NONE:
print("Copy device data to device memory failed, error: ", ret)
acl.rt.free(device_buffer)
return None
return device_buffer
def align_up(value, align):
return int(int((value + align - 1) / align) * align)
def align_up16(value):
return align_up(value, 16)
def align_up2(value):
return align_up(value, 2)
def yuv420sp_size(width, height):
return width * height * 3 // 2
def unpack_bytes(dest, dest_size, src, src_size):
libatlas.UnpackFloatByteArray(dest, dest_size, src, src_size)
+20
View File
@@ -0,0 +1,20 @@
[baseconf]
# A socket server address to communicate with presenter agent
presenter_server_ip=192.168.1.223
# The port of presenter agent and server communicate with
presenter_server_port=7006
#the ip in presenter server view web url
presenter_view_ip=192.168.1.223
#the ip of atlas200dk board connect with presenter server
#presenter_agent_ip=192.168.1.2
atlas200dk_board_ip=192.168.1.2
#view entry label in presenter server view web
channel_name=video
#the data type that send to presenter server from agent, 0:image, 1:video
content_type=1
+22
View File
@@ -0,0 +1,22 @@
2020-09-08 22:16:36,023-INFO-body_pose_server.py:222 presenter server is starting...
2020-09-08 22:16:36,024-INFO-presenter_server.py:79 presenter server starting, type: body_pose
2020-09-08 22:17:25,532-INFO-presenter_socket_server.py:255 create new connection:client-ip:192.168.1.2, client-port:53428, fd:17
2020-09-08 22:17:26,028-ERROR-presenter_socket_server.py:354 channel name video is not exist.
2020-09-08 22:17:26,030-INFO-channel_manager.py:216 register channel: video
2020-09-08 22:17:26,032-INFO-channel_handler.py:215 create videothread-video...
2020-09-08 22:17:26,032-INFO-channel_manager.py:127 create channel resource, channel_name:video, channel_fd:17, media_type:video
2020-09-08 22:17:34,188-ERROR-presenter_socket_server.py:142 socket 17 receive msg head null
2020-09-08 22:17:34,188-ERROR-presenter_socket_server.py:204 msg_total_len is None.
2020-09-08 22:17:34,189-INFO-body_pose_server.py:60 clean fd:17, conns:{17: <socket.socket fd=17, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.1.223', 7006), raddr=('192.168.1.2', 53428)>}
2020-09-08 22:17:34,191-INFO-channel_handler.py:124 videothread-video set _close_thread_switch True
2020-09-08 22:17:34,191-INFO-channel_manager.py:139 clean channel: video's resource
2020-09-08 22:17:34,192-INFO-channel_handler.py:226 Stop thread:videothread-video.
2020-09-08 22:18:03,748-INFO-presenter_socket_server.py:255 create new connection:client-ip:192.168.1.2, client-port:53438, fd:17
2020-09-08 22:18:04,245-INFO-channel_handler.py:215 create videothread-video...
2020-09-08 22:18:04,245-INFO-channel_manager.py:127 create channel resource, channel_name:video, channel_fd:17, media_type:video
2020-09-08 22:18:53,726-ERROR-presenter_socket_server.py:142 socket 17 receive msg head null
2020-09-08 22:18:53,727-ERROR-presenter_socket_server.py:204 msg_total_len is None.
2020-09-08 22:18:53,727-INFO-body_pose_server.py:60 clean fd:17, conns:{17: <socket.socket fd=17, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.1.223', 7006), raddr=('192.168.1.2', 53438)>}
2020-09-08 22:18:53,727-INFO-channel_handler.py:124 videothread-video set _close_thread_switch True
2020-09-08 22:18:53,727-INFO-channel_manager.py:139 clean channel: video's resource
2020-09-08 22:18:53,727-INFO-channel_handler.py:226 Stop thread:videothread-video.
+57
View File
@@ -0,0 +1,57 @@
import os
import cv2
import numpy as np
import argparse
import sys
sys.path.append('..')
from model_processor import ModelProcessor
import acl
from acl_resource import AclResource
MODEL_PATH = "../model/body_pose.om"
DATA_PATH = './tennis_player.jpg'
def execute(model_path, frames_input_src, output_dir):
## Initialization ##
#initialize acl runtime
acl_resource = AclResource()
acl_resource.init()
## Prepare Model ##
# parameters for model path and model inputs
model_parameters = {
'model_dir': model_path,
'width': 368, # model input width
'height': 368, # model input height
}
# perpare model instance: init (loading model from file to memory)
# model_processor: preprocessing + model inference + postprocessing
model_processor = ModelProcessor(acl_resource, model_parameters)
## Get Input ##
# Read the image input using OpenCV
img_original = cv2.imread(args.frames_input_src)
## Model Prediction ##
# model_processor.predict: processing + model inference + postprocessing
# canvas: the picture overlayed with human body joints and limbs
canvas = model_processor.predict(img_original)
# Save the detected results
cv2.imwrite(os.path.join(args.output_dir, 'Result_Pose.jpg'), canvas)
if __name__ == '__main__':
description = 'Load a model for human pose estimation'
parser = argparse.ArgumentParser(description=description)
parser.add_argument('--model', type=str, default=MODEL_PATH)
parser.add_argument('--frames_input_src', type=str,default=DATA_PATH, help="Directory path for image")
parser.add_argument('--output_dir', type=str, default='./outputs', help="Output Path")
args = parser.parse_args()
if not os.path.exists(args.output_dir):
os.makedirs(args.output_dir)
execute(args.model, args.frames_input_src, args.output_dir)
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

+107
View File
@@ -0,0 +1,107 @@
import random
import os
import cv2
import numpy as np
import argparse
import sys
sys.path.append('..')
from model_processor import ModelProcessor
from atlas_utils.camera import Camera
from atlas_utils import presenteragent
from atlas_utils.acl_image import AclImage
import acl
from acl_resource import AclResource
MODEL_PATH = "../model/body_pose.om"
BODYPOSE_CONF="../body_pose.conf"
CAMERA_FRAME_WIDTH = 1280
CAMERA_FRAME_HEIGHT = 720
def execute(model_path):
## Initialization ##
#initialize acl runtime
acl_resource = AclResource()
acl_resource.init()
## Prepare Model ##
# parameters for model path and model inputs
model_parameters = {
'model_dir': model_path,
'width': 368, # model input width
'height': 368, # model input height
}
# perpare model instance: init (loading model from file to memory)
# model_processor: preprocessing + model inference + postprocessing
model_processor = ModelProcessor(acl_resource, model_parameters)
## Get Input ##
# Initialize Camera
cap = Camera(id = 0, fps = 10)
## Set Output ##
# open the presenter channel
chan = presenteragent.presenter_channel.open_channel(BODYPOSE_CONF)
if chan == None:
print("Open presenter channel failed")
return
while True:
## Read one frame from Camera ##
img_original = cap.read()
if not img_original:
print('Error: Camera read failed')
break
# Camera Input (YUV) to RGB Image
image_byte = img_original.tobytes()
image_array = np.frombuffer(image_byte, dtype=np.uint8)
img_original = YUVtoRGB(image_array)
img_original = cv2.flip(img_original,1)
## Model Prediction ##
# model_processor.predict: processing + model inference + postprocessing
# canvas: the picture overlayed with human body joints and limbs
canvas = model_processor.predict(img_original)
## Present Result ##
# convert to jpeg image for presenter server display
_,jpeg_image = cv2.imencode('.jpg',canvas)
# construct AclImage object for presenter server
jpeg_image = AclImage(jpeg_image, img_original.shape[0], img_original.shape[1], jpeg_image.size)
# send to presenter server
chan.send_detection_data(img_original.shape[0], img_original.shape[1], jpeg_image, [])
# release the resources
cap.release()
def YUVtoRGB(byteArray):
e = 1280*720
Y = byteArray[0:e]
Y = np.reshape(Y, (720,1280))
s = e
V = byteArray[s::2]
V = np.repeat(V, 2, 0)
V = np.reshape(V, (360,1280))
V = np.repeat(V, 2, 0)
U = byteArray[s+1::2]
U = np.repeat(U, 2, 0)
U = np.reshape(U, (360,1280))
U = np.repeat(U, 2, 0)
RGBMatrix = (np.dstack([Y,U,V])).astype(np.uint8)
RGBMatrix = cv2.cvtColor(RGBMatrix, cv2.COLOR_YUV2RGB, 3)
return RGBMatrix
if __name__ == '__main__':
description = 'Load a model for human pose estimation'
parser = argparse.ArgumentParser(description=description)
parser.add_argument('--model', type=str, default=MODEL_PATH)
args = parser.parse_args()
execute(args.model)
+106
View File
@@ -0,0 +1,106 @@
import random
import os
import cv2
import numpy as np
import argparse
import sys
sys.path.append('..')
from model_processor import ModelProcessor
from atlas_utils.camera import Camera
from atlas_utils import presenteragent
from atlas_utils.acl_image import AclImage
import acl
from acl_resource import AclResource
MODEL_PATH = "../model/body_pose.om"
BODYPOSE_CONF="../body_pose.conf"
CAMERA_FRAME_WIDTH = 1280
CAMERA_FRAME_HEIGHT = 720
DATA_PATH = './yoga.mp4'
def execute(model_path, frames_input_src, output_dir, is_presenter_server):
## Initialization ##
#initialize acl runtime
acl_resource = AclResource()
acl_resource.init()
## Prepare Model ##
# parameters for model path and model inputs
model_parameters = {
'model_dir': model_path,
'width': 368, # model input width
'height': 368, # model input height
}
# perpare model instance: init (loading model from file to memory)
# model_processor: preprocessing + model inference + postprocessing
model_processor = ModelProcessor(acl_resource, model_parameters)
## Get Input ##
# Read the video input using OpenCV
cap = cv2.VideoCapture(frames_input_src)
## Set Output ##
if is_presenter_server:
# if using presenter server, then open the presenter channel
chan = presenteragent.presenter_channel.open_channel(BODYPOSE_CONF)
if chan == None:
print("Open presenter channel failed")
return
else:
# if saving result as video file (mp4), then set the output video writer using opencv
video_output_path = '{}/demo-{}-{}.mp4'.format(output_dir, os.path.basename(frames_input_src), str(random.randint(1, 100001)))
video_writer = cv2.VideoWriter(video_output_path, 0x7634706d, 25,
(1280, 720))
if video_writer == None:
print('Error: cannot get video writer from openCV')
while(cap.isOpened()):
## Read one frame of the input video ##
ret, img_original = cap.read()
if not ret:
print('Cannot read more, Reach the end of video')
break
## Model Prediction ##
# model_processor.predict: processing + model inference + postprocessing
# canvas: the picture overlayed with human body joints and limbs
canvas = model_processor.predict(img_original)
## Present Result ##
if is_presenter_server:
# convert to jpeg image for presenter server display
_,jpeg_image = cv2.imencode('.jpg',canvas)
# construct AclImage object for presenter server
jpeg_image = AclImage(jpeg_image, img_original.shape[0], img_original.shape[1], jpeg_image.size)
# send to presenter server
chan.send_detection_data(img_original.shape[0], img_original.shape[1], jpeg_image, [])
else:
# save to video
video_writer.write(canvas)
# release the resources
cap.release()
if not is_presenter_server:
video_writer.release()
if __name__ == '__main__':
description = 'Load a model for human pose estimation'
parser = argparse.ArgumentParser(description=description)
parser.add_argument('--model', type=str, default=MODEL_PATH)
parser.add_argument('--frames_input_src', type=str,default=DATA_PATH, help="Directory path for video.")
parser.add_argument('--output_dir', type=str, default='./outputs', help="Output Path")
parser.add_argument('--is_presenter_server', type=bool, default=False, help="Display on presenter server or save to a video mp4 file (T/F)")
args = parser.parse_args()
if not os.path.exists(args.output_dir):
os.makedirs(args.output_dir)
execute(args.model, args.frames_input_src, args.output_dir, args.is_presenter_server)
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File
Binary file not shown.
+59
View File
@@ -0,0 +1,59 @@
import os
import cv2
import numpy as np
import argparse
import sys
sys.path.append('../')
from src.pose_decode import decode_pose
from acl_model import Model
heatmap_width = 92
heatmap_height = 92
class ModelProcessor:
def __init__(self, acl_resource, params):
self._acl_resource = acl_resource
self.params = params
self._model_width = params['width']
self._model_height = params['height']
assert 'model_dir' in params and params['model_dir'] is not None, 'Review your param: model_dir'
assert os.path.exists(params['model_dir']), "Model directory doesn't exist {}".format(params['model_dir'])
# load model from path, and get model ready for inference
self.model = Model(acl_resource, params['model_dir'])
def predict(self, img_original):
#preprocess image to get 'model_input'
model_input = self.preprocess(img_original)
# execute model inference
result = self.model.execute([model_input])
# postprocessing: use the heatmaps (the second output of model) to get the joins and limbs for human body
# Note: the model has multiple outputs, here we used a simplified method, which only uses heatmap for body joints
# and the heatmap has shape of [1,14], each value correspond to the position of one of the 14 joints.
# The value is the index in the 92*92 heatmap (flatten to one dimension)
heatmaps = result[1]
# calculate the scale of original image over heatmap, Note: image_original.shape[0] is height
scale = np.array([img_original.shape[1] / heatmap_width, img_original.shape[0]/ heatmap_height])
canvas = decode_pose(heatmaps[0], scale, img_original)
return canvas
def preprocess(self,img_original):
'''
preprocessing: resize image to model required size, and normalize value between [0,1]
'''
scaled_img_data = cv2.resize(img_original, (self._model_width, self._model_height))
preprocessed_img = np.asarray(scaled_img_data, dtype=np.float32) / 255.
return preprocessed_img
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.5 (fastrcnn)" project-jdk-type="Python SDK" />
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/presenterserver.iml" filepath="$PROJECT_DIR$/.idea/presenterserver.iml" />
</modules>
</component>
</project>
+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TemplatesService">
<option name="TEMPLATE_CONFIGURATION" value="Jinja2" />
<option name="TEMPLATE_FOLDERS">
<list>
<option value="$MODULE_DIR$/body_pose/ui/templates" />
</list>
</option>
</component>
<component name="TestRunnerService">
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
</component>
</module>
Binary file not shown.

After

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 B

+155
View File
@@ -0,0 +1,155 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="14eee75f-82cc-4cc5-8088-a98a8c71e208" name="Default" comment="" />
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="TRACKING_ENABLED" value="true" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileEditorManager">
<leaf>
<file leaf-file-name="config_parser.py" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/body_pose/src/config_parser.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="688">
<caret line="73" column="61" selection-start-line="73" selection-start-column="30" selection-end-line="73" selection-end-column="65" />
<folding>
<element signature="e#1773#1782#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
</leaf>
</component>
<component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
<component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" />
<component name="JsGulpfileManager">
<detection-done>true</detection-done>
<sorting>DEFINITION_ORDER</sorting>
</component>
<component name="NodePackageJsonFileManager">
<packageJsonPaths />
</component>
<component name="ProjectFrameBounds" extendedState="6">
<option name="x" value="292" />
<option name="y" value="44" />
<option name="width" value="1400" />
<option name="height" value="908" />
</component>
<component name="ProjectView">
<navigator proportions="" version="1">
<foldersAlwaysOnTop value="true" />
</navigator>
<panes>
<pane id="ProjectPane">
<subPane>
<expand>
<path>
<item name="presenterserver" type="b2602c69:ProjectViewProjectNode" />
<item name="presenterserver" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="presenterserver" type="b2602c69:ProjectViewProjectNode" />
<item name="presenterserver" type="462c0819:PsiDirectoryNode" />
<item name="body_pose" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="presenterserver" type="b2602c69:ProjectViewProjectNode" />
<item name="presenterserver" type="462c0819:PsiDirectoryNode" />
<item name="body_pose" type="462c0819:PsiDirectoryNode" />
<item name="config" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="presenterserver" type="b2602c69:ProjectViewProjectNode" />
<item name="presenterserver" type="462c0819:PsiDirectoryNode" />
<item name="body_pose" type="462c0819:PsiDirectoryNode" />
<item name="src" type="462c0819:PsiDirectoryNode" />
</path>
</expand>
<select />
</subPane>
</pane>
<pane id="Scope" />
</panes>
</component>
<component name="PropertiesComponent">
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
<property name="nodejs_npm_path_reset_for_default_project" value="true" />
</component>
<component name="RunDashboard">
<option name="ruleStates">
<list>
<RuleState>
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
</RuleState>
<RuleState>
<option name="name" value="StatusDashboardGroupingRule" />
</RuleState>
</list>
</option>
</component>
<component name="SvnConfiguration">
<configuration />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="14eee75f-82cc-4cc5-8088-a98a8c71e208" name="Default" comment="" />
<created>1581996809387</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1581996809387</updated>
</task>
<servers />
</component>
<component name="ToolWindowManager">
<frame x="64" y="-11" width="1857" height="984" extended-state="6" />
<editor active="true" />
<layout>
<window_info anchor="bottom" id="TODO" order="6" />
<window_info anchor="bottom" id="Event Log" side_tool="true" />
<window_info anchor="bottom" id="Database Changes" show_stripe_button="false" />
<window_info anchor="bottom" id="Run" order="2" />
<window_info anchor="bottom" id="Version Control" show_stripe_button="false" />
<window_info anchor="bottom" id="Python Console" />
<window_info anchor="bottom" id="Terminal" />
<window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.24959569" />
<window_info anchor="bottom" id="Docker" show_stripe_button="false" />
<window_info anchor="right" id="Database" />
<window_info anchor="right" id="SciView" />
<window_info id="Structure" order="1" side_tool="true" weight="0.25" />
<window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
<window_info id="Favorites" side_tool="true" />
<window_info anchor="bottom" id="Find" order="1" />
<window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" />
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
<window_info anchor="bottom" id="Message" order="0" />
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
</layout>
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="1" />
</component>
<component name="VcsContentAnnotationSettings">
<option name="myLimit" value="2678400000" />
</component>
<component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/body_pose/src/config_parser.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="688">
<caret line="73" column="61" selection-start-line="73" selection-start-column="30" selection-end-line="73" selection-end-column="65" />
<folding>
<element signature="e#1773#1782#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</component>
</project>
View File
@@ -0,0 +1,10 @@
[baseconf]
# A socket server address to communicate with presenter agent
# Please ensure that the port does not conflict, only support Ipv4
presenter_server_ip=192.168.1.223
presenter_server_port=7006
# A http server address, you can visit the website by "http//web_server_ip:web_server_port".
# Only support Chrome now.
web_server_ip=192.168.1.223
web_server_port=7007
@@ -0,0 +1,27 @@
[loggers]
keys=root,body_pose
[handlers]
keys=rotatingFileHandler
[formatters]
keys=simpleFmt
[logger_root]
level=DEBUG
handlers=rotatingFileHandler
[logger_body_pose]
level=DEBUG
handlers=rotatingFileHandler
qualname=body_pose
propagate=0
[handler_rotatingFileHandler]
class=handlers.RotatingFileHandler
level=DEBUG
formatter=simpleFmt
args=("body_pose.log", "a", 10*1024*1024, 2)
[formatter_simpleFmt]
format=%(asctime)s-%(levelname)s-%(filename)s:%(lineno)s %(message)s
@@ -0,0 +1,225 @@
# =======================================================================
#
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1 Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2 Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3 Neither the names of the copyright holders nor the names of the
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# =======================================================================
#
"""presenter socket server module"""
import os
import logging
from logging.config import fileConfig
from google.protobuf.message import DecodeError
import common.presenter_message_pb2 as pb2
from common.channel_manager import ChannelManager
from common.presenter_socket_server import PresenterSocketServer
from body_pose.src.config_parser import ConfigParser
class BodyPoseServer(PresenterSocketServer):
'''A server forbody pose'''
def __init__(self, server_address):
'''init func'''
self.channel_manager = ChannelManager(["image", "video"])
super(BodyPoseServer, self).__init__(server_address)
def _clean_connect(self, sock_fileno, epoll, conns, msgs):
"""
close socket, and clean local variables
Args:
sock_fileno: a socket fileno, return value of socket.fileno()
epoll: a set of select.epoll.
conns: all socket connections registered in epoll
msgs: msg read from a socket
"""
logging.info("clean fd:%s, conns:%s", sock_fileno, conns)
self.channel_manager.clean_channel_resource_by_fd(sock_fileno)
epoll.unregister(sock_fileno)
conns[sock_fileno].close()
del conns[sock_fileno]
del msgs[sock_fileno]
def _process_msg(self, conn, msg_name, msg_data):
"""
Total entrance to process protobuf msg
Args:
conn: a socket connection
msg_name: name of a msg.
msg_data: msg body, serialized by protobuf
Returns:
False:somme error occured
True:succeed
"""
# process open channel request
if msg_name == pb2._OPENCHANNELREQUEST.full_name:
ret = self._process_open_channel(conn, msg_data)
# process image request, receive an image data from presenter agent
elif msg_name == pb2._PRESENTIMAGEREQUEST.full_name:
ret = self._process_image_request(conn, msg_data)
# process heartbeat request, it used to keepalive a channel path
elif msg_name == pb2._HEARTBEATMESSAGE.full_name:
ret = self._process_heartbeat(conn)
else:
logging.error("Not recognized msg type %s", msg_name)
ret = False
return ret
def _response_image_request(self, conn, response, err_code):
"""
Assemble protobuf to response image_request
Message structure like this:
--------------------------------------------------------------------
|total message len | int | 4 bytes |
|-------------------------------------------------------------------
|message name len | byte | 1 byte |
|-------------------------------------------------------------------
|message name | string | xx bytes |
|-------------------------------------------------------------------
|message body | protobuf | xx bytes |
--------------------------------------------------------------------
protobuf structure like this:
--------------------------------------------------------------------
|error_code | enum | PresentDataErrorCode |
|-------------------------------------------------------------------
|error_message | string | xx bytes |
|-------------------------------------------------------------------
enum PresentDataErrorCode {
kPresentDataErrorNone = 0;
kPresentDataErrorUnsupportedType = 1;
kPresentDataErrorUnsupportedFormat = 2;
kPresentDataErrorOther = -1;
}
"""
response.error_code = err_code
ret_code = True
if err_code == pb2.kPresentDataErrorUnsupportedFormat:
response.error_message = "Present data not support format."
logging.error("Present data not support format.")
ret_code = False
elif err_code == pb2.kPresentDataErrorNone:
response.error_message = "Present data ok"
ret_code = True
else:
response.error_message = "Present data not known error."
logging.error("Present data not known error.")
ret_code = False
self.send_message(conn, response, pb2._PRESENTIMAGERESPONSE.full_name)
return ret_code
def _process_image_request(self, conn, msg_data):
"""
Deserialization protobuf and process image_request
Args:
conn: a socket connection
msg_data: a protobuf struct, include image request.
Returns:
protobuf structure like this:
------------------------------------
|format | ImageFormat |
|------------------------------------
|width | uint32 |
|------------------------------------
|height | uint32 |
|------------------------------------
|data | bytes |
------------------------------------
enum ImageFormat {
kImageFormatJpeg = 0;
}
"""
request = pb2.PresentImageRequest()
response = pb2.PresentImageResponse()
# Parse msg_data from protobuf
try:
request.ParseFromString(msg_data)
except DecodeError:
logging.error("ParseFromString exception: Error parsing message")
err_code = pb2.kPresentDataErrorOther
return self._response_image_request(conn, response, err_code)
sock_fileno = conn.fileno()
handler = self.channel_manager.get_channel_handler_by_fd(sock_fileno)
if handler is None:
logging.error("get channel handler failed")
err_code = pb2.kPresentDataErrorOther
return self._response_image_request(conn, response, err_code)
# Currently, image format only support jpeg
if request.format != pb2.kImageFormatJpeg:
logging.error("image format %s not support", request.format)
err_code = pb2.kPresentDataErrorUnsupportedFormat
return self._response_image_request(conn, response, err_code)
rectangle_list = []
if request.rectangle_list:
for one_rectangle in request.rectangle_list:
rectangle = []
rectangle.append(one_rectangle.left_top.x)
rectangle.append(one_rectangle.left_top.y)
rectangle.append(one_rectangle.right_bottom.x)
rectangle.append(one_rectangle.right_bottom.y)
rectangle.append(one_rectangle.label_text)
# add the detection result to list
rectangle_list.append(rectangle)
handler.save_image(request.data, request.width, request.height, rectangle_list)
return self._response_image_request(conn, response,
pb2.kPresentDataErrorNone)
def stop_thread(self):
channel_manager = ChannelManager([])
channel_manager.close_all_thread()
self.set_exit_switch()
def run():
'''Entrance function of Body Pose Server '''
# read config file
config = ConfigParser()
# config log
log_file_path = os.path.join(ConfigParser.root_path, "config/logging.conf")
fileConfig(log_file_path)
logging.getLogger('body_pose')
if not config.config_verify():
return None
logging.info("presenter server is starting...")
server_address = (config.presenter_server_ip,
int(config.presenter_server_port))
return BodyPoseServer(server_address)
@@ -0,0 +1,83 @@
# =======================================================================
#
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1 Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2 Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3 Neither the names of the copyright holders nor the names of the
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# =======================================================================
#
"""pose detection config parser module"""
import os
import configparser
import common.parameter_validation as validate
class ConfigParser():
""" parse configuration from the config.conf"""
__instance = None
def __init__(self):
"""init"""
def __new__(cls):
"""ensure class object is a single instance"""
if cls.__instance is None:
cls.__instance = object.__new__(cls)
cls.config_parser()
return cls.__instance
def config_verify(self):
'''Verify configuration Parameters '''
if not validate.validate_ip(ConfigParser.web_server_ip) or \
not validate.validate_ip(ConfigParser.presenter_server_ip) or \
not validate.validate_port(ConfigParser.web_server_port) or \
not validate.validate_port(ConfigParser.presenter_server_port):
return False
return True
@classmethod
def config_parser(cls):
"""parser config from config.conf"""
config_parser = configparser.ConfigParser()
cls.root_path = ConfigParser.get_rootpath()
config_file = os.path.join(cls.root_path, "config/config.conf")
config_parser.read(config_file)
cls.web_server_ip = config_parser.get('baseconf', 'web_server_ip')
cls.presenter_server_ip = \
config_parser.get('baseconf', 'presenter_server_ip')
cls.web_server_port = config_parser.get('baseconf', 'web_server_port')
cls.presenter_server_port = \
config_parser.get('baseconf', 'presenter_server_port')
@staticmethod
def get_rootpath():
"""get presenter server's root directory."""
path = __file__
idx = path.rfind("src")
return path[0:idx]
+474
View File
@@ -0,0 +1,474 @@
# -*- coding: UTF-8 -*-
#
# =======================================================================
#
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1 Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2 Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3 Neither the names of the copyright holders nor the names of the
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# =======================================================================
#
"""
web application for presenter server.
"""
import os
import re
import random
import base64
import threading
import time
import logging
import tornado.ioloop
import tornado.web
import tornado.gen
import tornado.websocket
import body_pose.src.config_parser as config_parser
from common.channel_manager import ChannelManager
class WebApp:
"""
web application
"""
__instance = None
def __init__(self):
"""
init method
"""
self.channel_mgr = ChannelManager(["image", "video"])
self.request_list = set()
self.lock = threading.Lock()
def __new__(cls, *args, **kwargs):
# if instance is None than create one
if cls.__instance is None:
cls.__instance = object.__new__(cls, *args, **kwargs)
return cls.__instance
def add_channel(self, channel_name):
"""
add channel
@param channel_name name of channel
@return: return add status and message (for error status)
"""
ret = {"ret":"error", "msg":""}
# check channel_name validate,
# channel_name can not be None or length = 0
if channel_name is None:
logging.info("Channel name is None , add channel failed")
ret["msg"] = "Channel name can not be empty"
return ret
# strip channel name
channel_name = channel_name.strip()
# check channel_name emtpy or not
if channel_name == "":
logging.info("Channel name is emtpy , add channel failed")
ret["msg"] = "Channel name can not be empty"
return ret
# length of channel name can not over 25
if len(channel_name) > 25:
logging.info("Length of channel name %s > 25 , add channel failed", channel_name)
ret["msg"] = "Length of channel name should less than 25"
return ret
# define pattern support a-z A-Z and /
pattern = re.compile(r"[a-z]|[A-Z]|[0-9]|/")
tmp = pattern.findall(channel_name)
# check reuslt changed or not
if len(tmp) != len(channel_name):
logging.info("%s contain invalidate character, add channel failed", channel_name)
ret["msg"] = "Channel name only support 0-9, a-z, A-Z /"
return ret
# register channel
flag = self.channel_mgr.register_one_channel(channel_name)
# check register result
if self.channel_mgr.err_code_too_many_channel == flag:
logging.info("Only supports up to 10 channels, add channel failed")
ret["msg"] = "Only supports up to 10 channels"
elif self.channel_mgr.err_code_repeat_channel == flag:
logging.info("%s already exist, add channel failed", channel_name)
ret["msg"] = "Channel %s already exist" % channel_name
else:
logging.info("add channel %s succeed", channel_name)
ret["ret"] = "success"
return ret
def del_channel(self, names):
"""
delete channel
@param names: channel name to be deleted, separated by ','
@return: return add status and message (for error status)
"""
# init ret for return
ret = {"ret":"error", "msg":""}
# check length of names
if names.strip() == "":
logging.info("Channel name is empty, delete channel failed")
ret["msg"] = "Channel name should not be empty"
return ret
# split name for multi name
listname = names.split(",")
# unregister name
for item in listname:
item = item.strip()
# if name is emtpy continu
if item == "":
continue
self.channel_mgr.unregister_one_channel(item)
logging.info("delete channel %s succeed", item)
ret["ret"] = "success"
return ret
def list_channels(self):
"""
list all channels information
"""
# list register channels
ret = self.channel_mgr.list_channels()
# id for every channel item , start with 1
idx = 1
# set id for channel
for item in ret:
item['id'] = idx
idx = idx + 1
return ret
def is_channel_exists(self, name):
"""
view channel content via browser.
@param name : channel name
@return return True if exists. otherwise return False.
"""
return self.channel_mgr.is_channel_exist(name)
def add_requst(self, request):
"""
add request
@param requst: request item to be stored
@note: request can not be same with other request.
request is identified by (channel name ,random number)
so this method do not return value.
"""
with self.lock:
self.request_list.add(request)
def has_request(self, request):
"""
whether request exist or not
@param request: request to be checked.
@return: return True if exists, otherwise return False.
"""
with self.lock:
for item in self.request_list:
# check request equal
if item[0] == request[0] and item[1] == request[1]:
return True
return False
def get_media_data(self, channel_name):
"""
get media data by channel name
@param channel_name: channel to be quest data.
@return return dictionary which have for item
type: identify channel type, for image or video.
image: data to be returned.
fps: just for video type
status: can be error, ok, or loading.
"""
# channel exists or not
if self.is_channel_exists(channel_name) is False:
return {'type': 'unkown', 'image':'', 'fps':0, 'status':'error'}
image_data = self.channel_mgr.get_channel_image(channel_name)
# only for image type.
if image_data is not None:
image_data = base64.b64encode(image_data).decode('utf-8')
return {'type': 'image', 'image':image_data, 'fps':0, 'status':'ok'}
fps = 0 # fps for video
image = None # image for video & image
rectangle_list = None
handler = self.channel_mgr.get_channel_handler_by_name(channel_name)
if handler is not None:
media_type = handler.get_media_type()
# if type is image then get image data
if media_type == "image":
image = handler.get_image_data()
# for video
else:
frame_info = handler.get_frame()
image = frame_info[0]
fps = frame_info[1]
rectangle_list = frame_info[4]
status = "loading"
# decode binary to utf-8 when image is not None
if image is not None:
status = "ok"
image = base64.b64encode(image).decode('utf-8')
return {'type': media_type, 'image':image, 'fps':fps, 'status':status, 'rectangle_list':rectangle_list}
else:
return {'type': 'unkown', 'image':None, 'fps':0, 'status':'loading'}
# pylint: disable=abstract-method
class BaseHandler(tornado.web.RequestHandler):
"""
base handler.
"""
# pylint: disable=abstract-method
class HomeHandler(BaseHandler):
"""
handler index request
"""
@tornado.web.asynchronous
def get(self, *args, **kwargs):
"""
handle home or index request only for get
"""
self.render("home.html", listret=G_WEBAPP.list_channels())
# pylint: disable=abstract-method
class AddHandler(BaseHandler):
"""
handler add request
"""
@tornado.web.asynchronous
def post(self, *args, **kwargs):
"""
handle reqeust for add channel
"""
channel_name = self.get_argument('name', '')
self.finish(G_WEBAPP.add_channel(channel_name))
# pylint: disable=abstract-method
class DelHandler(BaseHandler):
"""
handler delete request
"""
@tornado.web.asynchronous
def post(self, *args, **kwargs):
"""
handel requst for delete channel
"""
channel_name = self.get_argument('name', '')
self.finish(G_WEBAPP.del_channel(channel_name))
# pylint: disable=abstract-method
class ViewHandler(BaseHandler):
"""
handler view request
"""
@tornado.web.asynchronous
def get(self, *args, **kwargs):
"""
handler request for view channel
"""
channel_name = self.get_argument('name', '')
if G_WEBAPP.is_channel_exists(channel_name):
req_id = str(random.random())
G_WEBAPP.add_requst((req_id, channel_name))
self.render('view.html', channel_name=channel_name, req=req_id)
else:
raise tornado.web.HTTPError(404)
class WebSocket(tornado.websocket.WebSocketHandler):
"""
web socket for web page socket quest
"""
def open(self, *args, **kwargs):
"""
called when client request by ws or wss
"""
self.req_id = self.get_argument("req", '', True)
self.channel_name = self.get_argument("name", '', True)
# check request valid or not.
if not G_WEBAPP.has_request((self.req_id, self.channel_name)):
self.close()
@staticmethod
def send_message(obj, message, binary=False):
"""
send message to client.
"""
# check socket exist or not
if not obj.ws_connection or not obj.ws_connection.stream.socket:
return False
ret = False
try:
obj.write_message(message, binary)
ret = True
except tornado.websocket.WebSocketClosedError:
ret = False
return ret
def on_close(self):
"""
called when closed web socket
"""
@tornado.web.asynchronous
@tornado.gen.coroutine
def on_message(self, message):
"""
On recv message from client.
"""
if message == "next":
self.run_task()
def run_task(self):
"""
send image to client
"""
# check channel valid
if not G_WEBAPP.is_channel_exists(self.channel_name) or \
not G_WEBAPP.has_request((self.req_id, self.channel_name)):
self.close()
return
result = G_WEBAPP.get_media_data(self.channel_name)
# sleep 100ms if status not ok for frequently query
if result['status'] != 'ok':
time.sleep(0.1)
# if channel not exist close websocket.
if result['status'] == "error":
self.close()
# send message to client
else:
# close websoket when send failed or for image channel.
ret = WebSocket.send_message(self, result)
if not ret or result['type'] == "image":
self.close()
def get_webapp():
"""
start web applicatioin
"""
# get template file and static file path.
templatepath = os.path.join(config_parser.ConfigParser.get_rootpath(), "ui/templates")
staticfilepath = os.path.join(config_parser.ConfigParser.get_rootpath(), "ui/static")
# create application object.
app = tornado.web.Application(handlers=[(r"/", HomeHandler),
(r"/index", HomeHandler),
(r"/add", AddHandler),
(r"/del", DelHandler),
(r"/view", ViewHandler),
(r"/static/(.*)",
tornado.web.StaticFileHandler,
{"path": staticfilepath}),
(r"/websocket", WebSocket)],
template_path=templatepath)
# create server
http_server = tornado.httpserver.HTTPServer(app)
return http_server
def start_webapp():
"""
start webapp
"""
http_server = get_webapp()
config = config_parser.ConfigParser()
http_server.listen(config.web_server_port, address=config.web_server_ip)
print("Please visit http://" + config.web_server_ip + ":" +
str(config.web_server_port) + " for body pose")
tornado.ioloop.IOLoop.instance().start()
def stop_webapp():
"""
stop web app
"""
tornado.ioloop.IOLoop.instance().stop()
global G_WEBAPP
G_WEBAPP = WebApp()
@@ -0,0 +1,39 @@
body, h1, h2, h3, h4, h5, h6, hr, p, blockquote,
dl, dt, dd, ul, ol, li,
pre,
form, fieldset, legend, button, input, textarea,
th, td {
margin: 0;
padding: 0;
}
body,
button, input, select, textarea /* for ie */ {
font: 14px/1.5 tahoma, \5b8b\4f53, sans-serif;
}
h1, h2, h3, h4, h5, h6 { font-size: 100%; font-weight: normal;}
address, cite, dfn, em, var { font-style: normal; }
code, kbd, pre, samp { font-family: courier new, courier, monospace; }
small { font-size: 12px; }
ul, ol { list-style: none; }
a { text-decoration: none; }
a:hover { text-decoration: underline; }
sup { vertical-align: text-top; }
sub { vertical-align: text-bottom; }
legend { color: #000; } /* for ie6 */
fieldset, img { border: 0; }
button, input, select, textarea { font-size: 100%; }
table { border-collapse: collapse; border-spacing: 0; }
article, aside, details, figcaption, figure, footer,header, hgroup, menu, nav, section,
summary, time, mark, audio, video {
display: block;
margin: 0;
padding: 0;
}
mark { background: #ff0; }
@@ -0,0 +1,77 @@
#dlg-mask {
display: none;
position: fixed;
left: 0;
top: 0;
bottom: 0;
right: 0;
z-index: 10000;
background-color: rgba(0,0,0,0.75)/*rgba(140,140,140,0.4)*/;
}
#dlg-mask * {
color: #000;
box-sizing: border-box;
-moz-box-sizing: border-box; /* Firefox */
-webkit-box-sizing: border-box; /* Safari */
}
#dlg-box {
position: absolute;
width: 350px;
z-index: 200001;
padding: 25px;
background-color: rgba(255, 255, 255, 0.88);
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;
}
#dlg-box h1 {
width: 100%;
height: 20px;
line-height: 20px;
margin: 0;
font-weight: bold;
font-size: 18px;
}
#dlg-box p, #dlg-box input {
width: 100%;
margin: 20px 0;
font-size: 15px;
}
#dlg-box p {
width: 100%;
margin: 20px 0;
font-size: 15px;
line-height: 1.2;
word-wrap: break-word;
word-break: normal;
white-space: normal;
}
#dlg-box input {
height: 29px;
cursor: text;
}
#dlg-box div {
height: 30px;
}
#dlg-box div span {
display: inline-block;
float: right;
width: 64px;
height: 30px;
font-size: 15px;
color: #187be1;
text-align: center;
line-height: 30px;
cursor: pointer;
}
#dlg-box div span:hover {
background: #eee;
}
.dot {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@@ -0,0 +1,132 @@
body{
background-color: #edf7f9;
font-family: Arial, , Tahoma;
}
.nav{
width: 100%;
height: 80px;
background-color: #155070;
padding-left: 50px;
padding-right: 50px;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
justify-content: space-between;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
box-sizing: border-box;
}
.nav_left{
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
justify-content: space-between;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
}
.nav_left img{
width: 60px;
height: 60px;
margin-right: 20px;
}
.nav_left p span{
font-size: 24px;
font-weight: bold;
color: #ffffff;
}
.box_top{
width: 1024px;
margin: 0 auto;
height: 50px;
line-height: 50px;
font-weight: bold;
}
.box_content{
width: 1024px;
margin: 0 auto;
background-color: #ffffff;
}
.content_top{
height: 50px;
padding-top: 10px;
box-sizing: border-box;
-webkit-box-sizing: border-box;
}
.content_top li{
width: 82px;
height: 32px;
float: left;
border: 1px solid #51a8da;
margin-right: 5px;
color: #51a8da;
display: flex;
align-items: center;
justify-content: space-around;
padding-left: 7px;
padding-right: 7px;
box-sizing: border-box;
-webkit-box-sizing: border-box;
cursor: pointer;
}
.content_top li:nth-child(3){
background-color: #51a8da;
color: #ffffff;
}
.content_mid{
border-top:2px solid #51a8da;
padding-top: 15px;
height: 0;
display: none;
}
.mid_list{
width: 100%;
height: 40px;
margin-bottom: 10px;
border: 1px solid #ccc;
border-right: 0;
box-sizing: border-box;
-webkit-box-sizing: border-box;
}
.mid_list li{
float: left;
height: 100%;
width: 25%;
line-height: 40px;
padding-left: 20px;
padding-right: 20px;
box-sizing: border-box;
-webkit-box-sizing: border-box;
border-right: 1px solid #ccc;
}
.mid_list li:nth-child(odd){
background-color: #edf7f9;
}
.mid_list li:nth-child(odd) span:nth-child(2){
float: right;
}
.mid_add{
width: 82px;
height: 32px;
background-color: #51a8da;
color: #ffffff;
display: flex;
align-items: center;
justify-content: space-around;
cursor: pointer;
}
.content_bot{
border-top:2px solid #51a8da;
}
#mytable th,td{
height: 40px;
text-align: center;
}
@@ -0,0 +1,71 @@
body{
background-color: #edf7f9;
font-family: Arial, , Tahoma;
}
.nav{
width: 100%;
height: 80px;
background-color: #155070;
padding-left: 50px;
padding-right: 50px;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
justify-content: space-between;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
box-sizing: border-box;
}
.nav_left{
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
justify-content: space-between;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
}
.nav_left img{
width: 60px;
height: 60px;
margin-right: 20px;
}
.nav_left p span{
font-size: 24px;
font-weight: bold;
color: #ffffff;
}
.refresh{
position: absolute;
left: 50%;
top: 50%;
margin: -6px 0 0 -6px ;
}
.video_top{
width: 1024px;
margin: 0 auto;
height: 50px;
line-height: 50px;
font-weight: bold;
}
.video_content{
width: 1024px;
margin: 0 auto;
}
.video_fps{
text-align: right;
padding-right: 100px;
}
.video_inner{
text-align: center;
position: relative;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B

@@ -0,0 +1,97 @@
var dialog = (function Dialog() {
var $mask = $("<div id='dlg-mask'></div>");
//title--
//content--object{type[1 for input, 0 for text], text[display in content]}
//btnFlag--1 for OK+Cancel, 0 for OK
function initHtml(title, content, btnFlag, ok, cancel) {
var div = "";
div += "<div id='dlg-box' class='dot'>";
div += "<h1 class='dot' style=\"margin-bottom:5px\">" + title + "</h1>"
div += "<div style=\"width:100%;height:1px;background-color:#ccc;\"></div>";
if (content.type == 0) {
div += "<p>" + content.text + "</p>"
} else if (content.type == 1) {
div += "<input type='text' value='" + content.text + "' placeholder='" + content.placeholder + "' autocomplete='off'/>";
}
if (btnFlag == 0) {
div += "<div><span class='ok'>OK</span></div>";
} else if (btnFlag == 1) {
div += "<div><span class='ok'>OK</span><span class='cancel'>Cancel</span></div>";
}
div += "</div>";
$mask.html(div);
$mask.find("input").val($mask.find("input").val());
if (content.type == 1) {
$mask.find(".ok").on("click", function() {
var retText = $mask.find("input").val();
hide();
if (ok) {
ok(retText);
}
});
$mask.find(".cancel").on("click", function() {
var retText = $mask.find("input").val();
hide();
if (cancel) {
cancel(retText);
}
});
} else {
$mask.find(".ok").on("click", function() {
hide();
if (ok) {
ok();
}
});
$mask.find(".cancel").on("click", function() {
hide();
if (cancel) {
cancel();
}
});
}
}
function calcBoxPos() {
var $box = $mask.find("#dlg-box");
var mask_w = $mask.outerWidth();
var mask_h = $mask.outerHeight();
var box_w = $box.outerWidth();
var box_h = $box.outerHeight();
var pos_left = (mask_w - box_w) / 2 + "px";
var pos_top = (mask_h - box_h) / 2 + "px";
$box.css("left", pos_left).css("top", pos_top);
}
function show() {
$("body").prepend($mask);
$mask.css("display", "block");
if ($mask.find("input") && $mask.find("input")[0]) {
$mask.find("input")[0].focus();
}
calcBoxPos();
$(window).resize(calcBoxPos);
}
function hide() {
$mask.css("display", "none");
$mask.remove();
}
return {
hide: hide,
tip: function(title, text, ok) {
initHtml(title, { type: 0, text: text }, 0, ok, null);
show();
},
input: function(title, text, placeholder, ok, cancel) {
initHtml(title, { type: 1, text: text, placeholder: placeholder }, 1, ok, cancel);
show();
},
confirm: function(title, text, ok, cancel) {
initHtml(title, { type: 0, text: text }, 1, ok, cancel);
show();
}
}
})();
+1
View File
@@ -0,0 +1 @@
var dialog = (function Dialog() { var e = $("<div id='dlg-mask'></div>"); function d(j, h, i, f, g) { var k = ""; k += "<div id='dlg-box' class='dot'>"; k += "<h1 class='dot'>" + j + "</h1>"; if (h.type == 0) { k += "<p>" + h.text + "</p>" } else { if (h.type == 1) { k += "<input type='text' value='" + h.text + "' placeholder='" + h.placeholder + "' autocomplete='off'/>" } } if (i == 0) { k += "<div><span class='ok'>OK</span></div>" } else { if (i == 1) { k += "<div><span class='ok'>OK</span><span class='cancel'>Cancel</span></div>" } } k += "</div>"; e.html(k); e.find("input").val(e.find("input").val()); if (h.type == 1) { e.find(".ok").on("click", function() { var l = e.find("input").val(); b(); if (f) { f(l) } }); e.find(".cancel").on("click", function() { var l = e.find("input").val(); b(); if (g) { g(l) } }) } else { e.find(".ok").on("click", function() { b(); if (f) { f() } }); e.find(".cancel").on("click", function() { b(); if (g) { g() } }) } } function c() { var k = e.find("#dlg-box"); var h = e.outerWidth(); var j = e.outerHeight(); var l = k.outerWidth(); var g = k.outerHeight(); var f = (h - l) / 2 + "px"; var i = (j - g) / 2 + "px"; k.css("left", f).css("top", i) } function a() { $("body").prepend(e); e.css("display", "block"); if (e.find("input") && e.find("input")[0]) { e.find("input")[0].focus() } c(); $(window).resize(c) } function b() { e.css("display", "none"); e.remove() } return { hide: b, tip: function(h, g, f) { d(h, { type: 0, text: g }, 0, f, null); a() }, input: function(j, i, h, f, g) { d(j, { type: 1, text: i, placeholder: h }, 1, f, g); a() }, confirm: function(i, h, f, g) { d(i, { type: 0, text: h }, 1, f, g); a() } } })();
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,183 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Channels</title>
<link rel="stylesheet" href="/static/css/base.css">
<link rel="stylesheet" href="/static/css/list.css">
<link rel="stylesheet" href="/static/css/dialog.css">
</head>
<body>
<div class="box">
<div class="nav">
<div class="nav_left">
<img src="/static/images/logo.png" alt="">
<p><span>Presenter Server</span></p>
</div>
<div class="nav_right">
</div>
</div>
<div class="box_top">
<span> >View List</span>
</div>
<div style="width:100%;height:2px;background-color:#ccc;"></div>
<div class="box_content">
<ul class="content_top">
<li class="top_refresh"><img src="/static/images/u1.png" alt=""><span>Refresh</span></li>
<li class="top_del"><img src="/static/images/u2.png" alt=""><span>Delete</span></li>
</ul>
<div class="content_bot">
<form name="myForm">
<table id="mytable" border="1" width="100%">
<tr>
<th></th>
<th><input type="checkbox" id="checkAll"></th>
<th>Status</th>
<th>View Name</th>
</tr>
{% for item in listret %}
<tr>
<td>{{item['id']}}</td>
<td><input type="checkbox" name="selectFlag" value="1"></td>
{% if item['status'] == 1 %}
<td><img src="/static/images/u5.png" alt=""></td>
{% else %}
<td><img src="/static/images/u6.png" alt=""></td>
{% end %}
<td ><a class="view_channel" style="cursor:pointer">{{item['name']}}</a></td>
</tr>
{% end %}
</table>
</form>
</div>
</div>
</div>
</body>
<script src="/static/js/jquery-1.10.2.min.js"></script>
<script src="/static/js/dialog.js"></script>
<script>
$("#checkAll").click(function() {
if (this.checked) {
$("input[name='selectFlag']:checkbox").each(function() {
$(this).attr("checked", true);
})
} else { //反之 取消全选
$("input[name='selectFlag']:checkbox").each(function() {
$(this).attr("checked", false);
})
}
});
$(".view_channel").click(function(){
var url = "/view?name=" + encodeURIComponent($(this).text());
window.open(url);
}
);
</script>
<script>
function checkNameValidate()
{
var name = $("#cname").val().trim();
if (name.length == 0)
{
dialog.tip("Tips","Channel name can not be empty");
return false;
}
if (name.length > 25)
{
dialog.tip("Tips", "Length of channel name should less than 25" ,function(){});
return false;
}
for (var i = 0; i < name.length; i++)
{
var c = name.charAt(i).charCodeAt();
var flag = ((c >= 48 && c <= 57) || (c >= 97 && c<= 122) || (c>= 65 && c <= 90) || (c == 47));
if (false == flag)
{
dialog.tip("Tips", "Channel name only support 0-9, a-z, A-Z /" ,function(){});
return false;
}
}
return true;
}
$(".top_create").click(function () {
if($(".content_mid").css("display")=="none"){
$(".content_mid").css("display","block").animate({height:"100px"});
}else{
$(".content_mid").animate({height:"0"}).css("display","none");
}
});
$(".mid_add").click(function () {
var rowlen = $("#mytable").find("tr").length;
if (rowlen >= 11)
{
dialog.tip("Tips", "Presenter supports up to 10 channels" ,function(){});
return;
}
//check
if (true == checkNameValidate())
{
var url = "/add?"+"name=" + encodeURIComponent($("#cname").val().trim()) +"&time="+(new Date().getTime());
$.ajax({
type: "POST",
url: url,
dataType: "json",
success: function(data)
{
if (data["ret"] == "success")
{
window.location.reload()
}
else
{
dialog.tip("Tips", data["msg"], function(){});
}
},
});
}
});
$(".top_refresh").click(function () {
window.location.reload();
});
$(".top_del").click(function () {
if($("input[name='selectFlag']").is(":checked")){
var msg = "";
$("input[name='selectFlag']:checked").each(function() {
// 遍历选中的checkbox
tr = $(this).parents("tr");
td = $(tr).find("td");
msg += encodeURIComponent($(td).eq(3).text());
msg += ",";
});
dialog.confirm("Tips", "Are you sure to delete ", function(){
var url = "/del?"+"time="+(new Date().getTime())+"&name="+msg;
$.ajax({
type: "POST",
url: url,
dataType: "json",
success: function(data)
{
if (data["ret"] == "success")
{
window.location.reload()
}
else
{
dialog.tip("Tips", data["msg"], function(){});
}
},
});
}, function(){});
}else{
dialog.tip("Tips", "Please select one item at least", function(){});
}
});
</script>
</html>
@@ -0,0 +1,155 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>view</title>
<link rel="stylesheet" href="/static/css/base.css">
<link rel="stylesheet" href="/static/css/testvideo.css">
</head>
<body>
<div class="video_box">
<div class="nav">
<div class="nav_left">
<img src="/static/images/logo.png" alt="">
<p><span>Presenter Server</span></p>
</div>
<div class="nav_right">
</div>
</div>
<div class="video_top">
<span> >view</span>
</div>
<div style="width:100%;height:2px;background-color:#ccc;"></div>
<div class="video_content">
<div class="video_fps" id='fpswapper' hidden><p><span> channel name: {{ channel_name }} </span> <span>&nbsp;&nbsp;&nbsp;&nbsp;fps:</span><span id='fpsval'></span></p></div>
<div class="video_inner">
<img src="/static/images/loading.gif" id = "loading" board = "1" alt=""/>
<!-- <img id = "load_media" hidden width = "1024px" board = "1" alt=""/> -->
<canvas id="canvas"></canvas>
</div>
</div>
</div>
</body>
<script src="/static/js/jquery-1.10.2.min.js"></script>
<script>
var canvas=document.getElementById("canvas")
var ctx=canvas.getContext("2d")
$('#fpswapper').hide()
$('#loading').hide()
function startViewVideo(){
$('#loading').show()
$('#canvas').hide()
var image = new Image();
var wsProtocol = "ws://";
if (window.location.protocol == "https:"){
wsProtocol = "wss://";
}
var wsUrl = wsProtocol + window.location.host+"/websocket?req={{req}}&name={{channel_name}}";
var ws = new WebSocket(wsUrl);
var onmessageflag = false;
ws.onopen = function() {
ws.send('next');
};
var count = 0;
var timestart = 0;
ws.onmessage = function (evt) {
$('#loading').hide()
$('#canvas').show()
var data = JSON.parse(evt.data)
var rectangles = []
if ('ok' == data['status']){
$('#fpsval').text(data.fps);
$('#loading').hide();
// $('#load_media').show();
var src = "data:image/jpeg;base64," + data['image'];
// $('#load_media').attr('src', src);
if (data['type'] == 'video'){
$('#fpswapper').show();
rectangles = data['rectangle_list']
}
var wantedWidth = 1024
var img = new Image()
img.src = src
img.onload=function(){
scale_factor = wantedWidth/img.width
canvas.setAttribute("width",1024)
canvas.setAttribute("height",img.height*scale_factor)
ctx.strokeStyle="yellow"
ctx.font="30px serif"
ctx.fillStyle="yellow"
ctx.strokeStyle="yellow"
ctx.font="30px serif"
ctx.fillStyle="yellow"
ctx.drawImage(img,0,0, wantedWidth, img.height*scale_factor)
for (var index in rectangles){
var pos= rectangles[index].slice(0,4) //
for (var i in pos){
pos[i] = pos[i]*scale_factor
}
var msg = rectangles[index].slice(4,5)
//add space between msg and face
//if upper space is not enough show the msg at the bottom
if(50>pos[1]){
// ctx.fillText(msg,pos[0],pos[3]+50)
}
else{
// ctx.fillText(msg,pos[0],pos[1]-10)
}
ctx.beginPath()
// 1/3 space draw line
if(msg == 'points'){
ctx.strokeStyle = "#0F4F00"
ctx.arc(pos[0],pos[1],6,0,2*Math.PI)
ctx.fillStyle = "#6CFF33"
ctx.fill()
}else if(msg == 'hand_box'){
ctx.strokeStyle = "#FF0000"
ctx.lineWidth = 5
ctx.moveTo(pos[0],pos[1])
ctx.lineTo(pos[2],pos[1])
ctx.moveTo(pos[2],pos[1])
ctx.lineTo(pos[2],pos[3])
ctx.moveTo(pos[0],pos[1])
ctx.lineTo(pos[0],pos[3])
ctx.moveTo(pos[0],pos[3])
ctx.lineTo(pos[2],pos[3])
// }else if(msg == 'hand_point'){
// ctx.strokeStyle = "#33FAFF"
// ctx.arc(pos[0],pos[1],3,0,2*Math.PI)
// ctx.fillStyle = "#33FAFF"
// ctx.fill()
// }else if(msg == 'hand'){
// ctx.strokeStyle = "#FC33FF"
// ctx.lineWidth = 3
// ctx.moveTo(pos[0],pos[1])
// ctx.lineTo(pos[2],pos[3])
}else if(msg == 'body'){
ctx.strokeStyle = "#FFF700"
ctx.lineWidth = 5
ctx.moveTo(pos[0],pos[1])
ctx.lineTo(pos[2],pos[3])
}else{
ctx.font = "30px Arial";
ctx.lineWidth = 5
ctx.fillStyle = "#33FAFF"
ctx.fillText(msg, 200, 200);
}
ctx.stroke()
}
}
}
ws.send('next');
}
}
startViewVideo();
</script>
</html>
View File
+209
View File
@@ -0,0 +1,209 @@
# =======================================================================
#
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1 Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2 Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3 Neither the names of the copyright holders nor the names of the
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# =======================================================================
#
"""presenter app manager module"""
import time
import threading
import logging
from common.channel_manager import ChannelManager
# Heartbeat timeout, exceeding the limit, the socket will disconnect
HEARTBEAT_TIMEOUT = 100
class App():
'''App class, When receive an app request from
Presenter Agent, creat an object.
'''
def __init__(self, app_id, conn=None):
self.app_id = app_id
self.heartbeat = time.time()
self.socket_fd = conn.fileno()
# set timeout 1 second
conn.settimeout(1)
self.socket = conn
self.frame_num_dict = {}
class AppManager():
'''A class provides app management features'''
__instance = None
channel_manager = None
app_list_lock = threading.Lock()
app_list = []
thread_switch = False
def __init__(self):
"""init func"""
def __new__(cls):
"""ensure only a single instance created. """
if cls.__instance is None:
cls.__instance = object.__new__(cls)
cls.channel_manager = ChannelManager([])
cls._create_thread()
return cls.__instance
@classmethod
def _create_thread(cls):
"""_create_thread."""
thread = threading.Thread(target=cls._app_thread)
thread.start()
@classmethod
def _app_thread(cls):
"""background thread to process video"""
logging.info('create app manager thread')
while True:
if cls.thread_switch:
break
for i in range(len(cls.app_list)):
if time.time() - cls.app_list[i].heartbeat > HEARTBEAT_TIMEOUT:
app_id = cls.app_list[i].app_id
cls.channel_manager.unregister_one_channel(app_id)
del cls.app_list[i]
logging.info("unregister app: %s", app_id)
time.sleep(1)
def set_thread_switch(self):
AppManager.thread_switch = True
def register_app(self, app_id, socket):
"""
API for registering an app
Args:
app_id: app id, must be globally unique
socket: a socket communicating with the app
"""
with self.app_list_lock:
for i in range(len(self.app_list)):
if self.app_list[i].app_id == app_id:
return False
app = App(app_id, socket)
self.app_list.append(app)
self.channel_manager.register_one_channel(app_id)
logging.info("register app: %s", app_id)
return True
def unregister_app_by_fd(self, sock_fileno):
"""
API for unregistering an app
Args:
sock_fileno: sock_fileno is binded to an app.
Through it, find the app and delete it.
"""
with self.app_list_lock:
for i in range(len(self.app_list)):
if self.app_list[i].socket_fd == sock_fileno:
app_id = self.app_list[i].app_id
self.channel_manager.unregister_one_channel(app_id)
del self.app_list[i]
logging.info("unregister app: %s", app_id)
break
def get_socket_by_app_id(self, app_id):
"""
API for finding an app
Args:
app_id: the id of an app.
"""
with self.app_list_lock:
for i in range(len(self.app_list)):
if self.app_list[i].app_id == app_id:
return self.app_list[i].socket
return None
def get_app_id_by_socket(self, sock_fd):
"""
API for get app id by socket
Args:
sock_fd: sock_fd is binded to an app.
Through it, find the app and delete it.
"""
with self.app_list_lock:
for i in range(len(self.app_list)):
if self.app_list[i].socket_fd == sock_fd:
return self.app_list[i].app_id
return None
def is_app_exist(self, app_id):
"""
API for checking if the app exist
Args:
app_id: the id of an app.
"""
with self.app_list_lock:
for i in range(len(self.app_list)):
if self.app_list[i].app_id == app_id:
return True
return False
def get_app_num(self):
"""
API for getting the number of apps
Args: NA
"""
with self.app_list_lock:
return len(self.app_list)
def set_heartbeat(self, sock_fileno):
with self.app_list_lock:
for i in range(len(self.app_list)):
if self.app_list[i].socket_fd == sock_fileno:
self.app_list[i].heartbeat = time.time()
def increase_frame_num(self, app_id, channel_id):
with self.app_list_lock:
for i in range(len(self.app_list)):
if self.app_list[i].app_id == app_id:
if channel_id in self.app_list[i].frame_num_dict:
self.app_list[i].frame_num_dict[channel_id] += 1
else:
self.app_list[i].frame_num_dict[channel_id] = 1
def get_frame_num(self, app_id, channel_id):
with self.app_list_lock:
for i in range(len(self.app_list)):
if self.app_list[i].app_id == app_id:
if channel_id in self.app_list[i].frame_num_dict:
return self.app_list[i].frame_num_dict[channel_id]
else:
return 0
return 0
def list_app(self):
"""
API for listing all apps
Args: NA
"""
with self.app_list_lock:
return [self.app_list[i].app_id for i in range(len(self.app_list))]
+227
View File
@@ -0,0 +1,227 @@
# =======================================================================
#
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1 Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2 Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3 Neither the names of the copyright holders nor the names of the
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# =======================================================================
#
"""presenter channel manager module"""
import time
import logging
import threading
from threading import get_ident
from common.channel_manager import ChannelManager
# thread event timeout, The unit is second.
WEB_EVENT_TIMEOUT = 2
# thread event timeout, The unit is second.
IMAGE_EVENT_TIMEOUT = 10
# heart beat timeout, The unit is second.
HEARTBEAT_TIMEOUT = 100
class ThreadEvent():
"""An Event-like class that signals all active clients when a new frame is
available.
"""
def __init__(self, timeout=None):
self.events = {}
self.timeout = timeout
def wait(self):
"""Invoked from each client's thread to wait for the next frame."""
ident = get_ident()
if ident not in self.events:
# this is a new client
# add an entry for it in the self.events dict
# each entry has two elements, a threading.Event() and a timestamp
self.events[ident] = [threading.Event(), time.time()]
return self.events[ident][0].wait(self.timeout)
def set(self):
"""Invoked by the camera thread when a new frame is available."""
now = time.time()
remove = None
for ident, event in self.events.items():
if not event[0].isSet():
# if this client's event is not set, then set it
# also update the last set timestamp to now
event[0].set()
event[1] = now
else:
# if the client's event is already set, it means the client
# did not process a previous frame
# if the event stays set for more than 5 seconds, then assume
# the client is gone and remove it
if now - event[1] > 5:
remove = ident
if remove:
del self.events[remove]
def clear(self):
"""Invoked from each client's thread after a frame was processed."""
self.events[get_ident()][0].clear()
class ChannelHandler():
"""A set of channel handlers, process data received from channel"""
def __init__(self, channel_name, media_type):
self.channel_name = channel_name
self.media_type = media_type
self.img_data = None
self._frame = None
self.thread = None
self._frame = None
# last time the channel receive data.
self.heartbeat = time.time()
self.web_event = ThreadEvent(timeout=WEB_EVENT_TIMEOUT)
self.image_event = ThreadEvent(timeout=IMAGE_EVENT_TIMEOUT)
self.lock = threading.Lock()
self.channel_manager = ChannelManager([])
self.rectangle_list = None
if media_type == "video":
self.thread_name = "videothread-{}".format(self.channel_name)
self.heartbeat = time.time()
self.close_thread_switch = False
self.fps = 0
self.image_number = 0
self.time_list = []
self._create_thread()
def close_thread(self):
"""close thread if object has created"""
if self.thread is None:
return
self.set_thread_switch()
self.image_event.set()
logging.info("%s set _close_thread_switch True", self.thread_name)
def set_heartbeat(self):
"""record heartbeat"""
self.heartbeat = time.time()
def set_thread_switch(self):
"""record heartbeat"""
self.close_thread_switch = True
def save_image(self, data, width, height, rectangle_list):
"""save image receive from socket"""
self.width = width
self.height = height
self.rectangle_list = rectangle_list
# compute fps if type is video
if self.media_type == "video":
while self.img_data:
time.sleep(0.01)
self.time_list.append(self.heartbeat)
self.image_number += 1
while self.time_list[0] + 1 < time.time():
self.time_list.pop(0)
self.image_number -= 1
if self.image_number == 0:
break
self.fps = len(self.time_list)
self.img_data = data
self.image_event.set()
else:
self.img_data = data
self.channel_manager.save_channel_image(self.channel_name,
self.img_data, self.rectangle_list)
self.heartbeat = time.time()
def get_media_type(self):
"""get media_type, support image or video"""
return self.media_type
def get_image(self):
"""get image_data"""
return self.img_data
def _create_thread(self):
"""Start the background video thread if it isn't running yet."""
if self.thread is not None and self.thread.isAlive():
return
# start background frame thread
self.thread = threading.Thread(target=self._video_thread)
self.thread.start()
def get_frame(self):
"""Return the current video frame."""
# wait util receive a frame data, and push it to your browser.
ret = self.web_event.wait()
self.web_event.clear()
# True: _web_event return because set()
# False: _web_event return because timeout
if ret:
return (self._frame, self.fps, self.width, self.height, self.rectangle_list)
return (None, None, None, None, None)
def frames(self):
"""a generator generates image"""
while True:
self.image_event.wait()
self.image_event.clear()
if self.img_data:
yield self.img_data
self.img_data = None
# if set _close_thread_switch, return immediately
if self.close_thread_switch:
yield None
# if no frames or heartbeat coming in the last 100 seconds,
# stop the thread and close socket
if time.time() - self.heartbeat > HEARTBEAT_TIMEOUT:
self.set_thread_switch()
self.img_data = None
yield None
def _video_thread(self):
"""background thread to process video"""
logging.info('create %s...', (self.thread_name))
for frame in self.frames():
if frame:
# send signal to clients
self._frame = frame
self.web_event.set()
# exit thread
if self.close_thread_switch:
self.channel_manager.clean_channel_resource_by_name(
self.channel_name)
logging.info('Stop thread:%s.', (self.thread_name))
break
+291
View File
@@ -0,0 +1,291 @@
# =======================================================================
#
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1 Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2 Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3 Neither the names of the copyright holders nor the names of the
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# =======================================================================
#
"""presenter channel manager module"""
import logging
import threading
# max support 10 channels
MAX_CHANNEL_NUM = 10
# when a channel have receive data,
# the active status will last 3 seconds
ACTIVE_LAST_TIME = 3
class ChannelResource():
"""every channel has a ChannelResource object, contains a ChannelHandler object
and a socket fileno. it corresponding to the ChannelFd one by one
"""
def __init__(self, handler, socket=None):
self.handler = handler
self.socket = socket
class ChannelFd():
"""every channel has a ChannelFd object, contains a ChannelHandler
object and channel name. It corresponds to the ChannelResource one by one
"""
def __init__(self, channel_name, handler):
self.channel_name = channel_name
self.handler = handler
class Channel():
"""record user register channels
self.image: if channel type is image, save the image here
"""
def __init__(self, channel_name):
self.channel_name = channel_name
self.image = None
self.rectangle_list = None
class ChannelManager():
"""manage all the api about channel
__instance: ensure it is a single instance
_channel_resources: a dict
key: channel name
value: a ChannelResource() object.
_channel_fds: a dict
key: socket fileno
value: a ChannelFd() object.
_channel_list: a list, member is a Channel() object."""
__instance = None
channel_resources = {}
channel_fds = {}
channel_list = []
channel_resource_lock = threading.Lock()
channel_fds_lock = threading.Lock()
channel_lock = threading.Lock()
err_code_ok = 0
err_code_too_many_channel = 1
err_code_repeat_channel = 2
def __init__(self, channel_list=None):
"""init func"""
def __new__(cls, channel_list=None):
"""ensure only a single instance created. """
if cls.__instance is None:
cls.__instance = object.__new__(cls)
# default create 2 channels: image and video
# if channel_list is not None and isinstance(channel_list, list):
# for i in channel_list:
# cls.channel_list.append(Channel(channel_name=i))
# logging.info("register channel %s", i)
return cls.__instance
def _register_channel_fd(self, sock_fileno, channel_name):
"""Internal func, create a ChannelFd object"""
if self.channel_fds.get(sock_fileno):
del self.channel_fds[sock_fileno]
handler = self.channel_resources[channel_name].handler
self.channel_fds[sock_fileno] = ChannelFd(channel_name, handler)
def create_channel_resource(self, channel_name,
channel_fd,
media_type,
handler):
"""create a ChannelResource object which contains all the resources
binding a channel.
channel_name: channel name.
channel_fd: socket fileno binding the channel.
media_type: support image or video.
handler: an channel handler process image data.
"""
with self.channel_resource_lock:
log_info = "create channel resource,"
log_info += " channel_name:%s, channel_fd:%u, media_type:%s"
logging.info(log_info, channel_name, channel_fd, media_type)
self.channel_resources[channel_name] = \
ChannelResource(handler=handler, socket=channel_fd)
self._register_channel_fd(channel_fd, channel_name)
def _clean_channel_resource(self, channel_name):
"""Internal func, clean channel resource by channel name"""
if self.channel_resources.get(channel_name):
self.channel_resources[channel_name].handler.close_thread()
self.channel_resources[channel_name].handler.web_event.set()
self.channel_resources[channel_name].handler.image_event.set()
del self.channel_resources[channel_name]
logging.info("clean channel: %s's resource", channel_name)
def clean_channel_resource_by_fd(self, sock_fileno):
"""
clean channel resource by socket fileno
sock_fileno: socket fileno which binding to an channel
"""
with self.channel_fds_lock:
with self.channel_resource_lock:
if self.channel_fds.get(sock_fileno):
self._clean_channel_resource(
self.channel_fds[sock_fileno].channel_name)
del self.channel_fds[sock_fileno]
def clean_channel_resource_by_name(self, channel_name):
"""clean channel resource by channel_name
channel_name: channel name"""
if self.channel_resources.get(channel_name):
self.clean_channel_resource_by_fd(
self.channel_resources[channel_name].socket)
def get_channel_handler_by_fd(self, sock_fileno):
"""get channel handler by socket fileno"""
with self.channel_fds_lock:
if self.channel_fds.get(sock_fileno):
return self.channel_fds[sock_fileno].handler
return None
def is_channel_busy(self, channel_name):
"""check if channel is busy """
with self.channel_resource_lock:
if self.channel_resources.get(channel_name):
return True
return False
def close_all_thread(self):
"""if a channel process video type, it will create a thread.
this func can close the thread.
"""
with self.channel_resource_lock:
for channel_name in self.channel_resources:
self.channel_resources[channel_name].handler.close_thread()
def get_channel_handler_by_name(self, channel_name):
"""
get the channel handlerby channel name
"""
with self.channel_resource_lock:
if self.channel_resources.get(channel_name):
return self.channel_resources[channel_name].handler
return None
def list_channels(self):
"""
return all the channel name and the status
status is indicating active state or not
"""
with self.channel_lock:
return [{'status': self.is_channel_busy(i.channel_name),
'name': i.channel_name} for i in self.channel_list]
def register_one_channel(self, channel_name):
"""
register a channel path, user create a channel via browser
"""
with self.channel_lock:
if len(self.channel_list) >= MAX_CHANNEL_NUM:
logging.info("register channel: %s fail, \
exceed max number 10.", channel_name)
return self.err_code_too_many_channel
for i in range(len(self.channel_list)):
if self.channel_list[i].channel_name == channel_name:
logging.info("register channel: %s fail, \
already exist.", channel_name)
return self.err_code_repeat_channel
self.channel_list.append(Channel(channel_name=channel_name))
logging.info("register channel: %s", channel_name)
return self.err_code_ok
def unregister_one_channel(self, channel_name):
"""
unregister a channel path, user delete a channel via browser
"""
with self.channel_lock:
for i in range(len(self.channel_list)):
if self.channel_list[i].channel_name == channel_name:
self.clean_channel_resource_by_name(channel_name)
logging.info("unregister channel: %s", channel_name)
del self.channel_list[i]
break
def is_channel_exist(self, channel_name):
"""
Check if a channel is exist
True: exist
False: not exist
"""
with self.channel_lock:
for i in range(len(self.channel_list)):
if self.channel_list[i].channel_name == channel_name:
return True
return False
def save_channel_image(self, channel_name, image_data, rectangle_list):
"""
when a channel bounding to image type,
server will permanent hold an image for it.
this func save a image in memory
"""
with self.channel_lock:
for i in range(len(self.channel_list)):
if self.channel_list[i].channel_name == channel_name:
self.channel_list[i].image = image_data
self.channel_list[i].rectangle_list = rectangle_list
break
def get_channel_image(self, channel_name):
"""
when a channel bounding to image type,
server will permanent hold an image for it.
this func get the image
"""
with self.channel_lock:
for i in range(len(self.channel_list)):
if self.channel_list[i].channel_name == channel_name:
return self.channel_list[i].image
# channel not exist
return None
def get_channel_image_with_rectangle(self, channel_name):
"""
A new method for display server,
return the image and rectangle list
"""
with self.channel_lock:
for i in range(len(self.channel_list)):
if self.channel_list[i].channel_name == channel_name:
return (self.channel_list[i].image, self.channel_list[i].rectangle_list)
return (None, None)
def clean_channel_image(self, channel_name):
"""
when a channel bounding to image type,
server will permanent hold an image for it.
this func clean the image
"""
with self.channel_lock:
for i in range(len(self.channel_list)):
if self.channel_list[i].channel_name == channel_name:
self.channel_list[i].image = None
break
@@ -0,0 +1,98 @@
# =======================================================================
#
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1 Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2 Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3 Neither the names of the copyright holders nor the names of the
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# =======================================================================
#
"""Parameter Validation module"""
import logging
PORT_INTERVAL_BEGIN = 1024
PORT_INTERVAL_END = 49151
def validate_ip(ip_str):
if ip_str == '0.0.0.0':
logging.error("IP Addr \"0.0.0.0\" is illegal")
print("IP Addr \"0.0.0.0\" is illegal")
return False
sep = ip_str.split('.')
if len(sep) != 4:
return False
for i, x in enumerate(sep):
try:
int_x = int(x)
if int_x < 0 or int_x > 255:
logging.error("Illegal ip: %s", ip_str)
print("Illegal ip: %s"%ip_str)
return False
except ValueError:
logging.error("IP format error:%s", ip_str)
print("IP format error:%s"%ip_str)
return False
return True
def validate_port(value_str):
try:
value = int(value_str)
if value < PORT_INTERVAL_BEGIN or value > PORT_INTERVAL_END:
logging.error("Illegal port: %d", value)
print("Illegal port: %d"%value)
return False
except ValueError:
logging.error("Port format error:%s", value_str)
print("Port format error:%s"%value_str)
return False
return True
def validate_integer(value_str, begin, end):
try:
value = int(value_str)
if value < begin or value > end:
return False
except ValueError:
return False
return True
def Integer_greater(value_str, compared_value):
try:
value = int(value_str)
if value < compared_value:
return False
except ValueError:
return False
return True
def validate_float(value_str, begin, end):
try:
value = float(value_str)
if value < begin or value > end:
return False
except ValueError:
return False
return True
@@ -0,0 +1,525 @@
# =======================================================================
#
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1 Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2 Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3 Neither the names of the copyright holders nor the names of the
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# =======================================================================
#
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: presenter_message.proto
import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf.internal import enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
from google.protobuf import descriptor_pb2
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='presenter_message.proto',
package='ascend.presenter.proto',
syntax='proto3',
serialized_pb=_b('\n\x17presenter_message.proto\x12\x16\x61scend.presenter.proto\"l\n\x12OpenChannelRequest\x12\x14\n\x0c\x63hannel_name\x18\x01 \x01(\t\x12@\n\x0c\x63ontent_type\x18\x02 \x01(\x0e\x32*.ascend.presenter.proto.ChannelContentType\"n\n\x13OpenChannelResponse\x12@\n\nerror_code\x18\x01 \x01(\x0e\x32,.ascend.presenter.proto.OpenChannelErrorCode\x12\x15\n\rerror_message\x18\x02 \x01(\t\"\x12\n\x10HeartbeatMessage\"\"\n\nCoordinate\x12\t\n\x01x\x18\x01 \x01(\r\x12\t\n\x01y\x18\x02 \x01(\r\"\x94\x01\n\x0eRectangle_Attr\x12\x34\n\x08left_top\x18\x01 \x01(\x0b\x32\".ascend.presenter.proto.Coordinate\x12\x38\n\x0cright_bottom\x18\x02 \x01(\x0b\x32\".ascend.presenter.proto.Coordinate\x12\x12\n\nlabel_text\x18\x03 \x01(\t\"\xb7\x01\n\x13PresentImageRequest\x12\x33\n\x06\x66ormat\x18\x01 \x01(\x0e\x32#.ascend.presenter.proto.ImageFormat\x12\r\n\x05width\x18\x02 \x01(\r\x12\x0e\n\x06height\x18\x03 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x12>\n\x0erectangle_list\x18\x05 \x03(\x0b\x32&.ascend.presenter.proto.Rectangle_Attr\"o\n\x14PresentImageResponse\x12@\n\nerror_code\x18\x01 \x01(\x0e\x32,.ascend.presenter.proto.PresentDataErrorCode\x12\x15\n\rerror_message\x18\x02 \x01(\t*\xa5\x01\n\x14OpenChannelErrorCode\x12\x19\n\x15kOpenChannelErrorNone\x10\x00\x12\"\n\x1ekOpenChannelErrorNoSuchChannel\x10\x01\x12)\n%kOpenChannelErrorChannelAlreadyOpened\x10\x02\x12#\n\x16kOpenChannelErrorOther\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01*P\n\x12\x43hannelContentType\x12\x1c\n\x18kChannelContentTypeImage\x10\x00\x12\x1c\n\x18kChannelContentTypeVideo\x10\x01*#\n\x0bImageFormat\x12\x14\n\x10kImageFormatJpeg\x10\x00*\xa4\x01\n\x14PresentDataErrorCode\x12\x19\n\x15kPresentDataErrorNone\x10\x00\x12$\n kPresentDataErrorUnsupportedType\x10\x01\x12&\n\"kPresentDataErrorUnsupportedFormat\x10\x02\x12#\n\x16kPresentDataErrorOther\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x62\x06proto3')
)
_OPENCHANNELERRORCODE = _descriptor.EnumDescriptor(
name='OpenChannelErrorCode',
full_name='ascend.presenter.proto.OpenChannelErrorCode',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='kOpenChannelErrorNone', index=0, number=0,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='kOpenChannelErrorNoSuchChannel', index=1, number=1,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='kOpenChannelErrorChannelAlreadyOpened', index=2, number=2,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='kOpenChannelErrorOther', index=3, number=-1,
options=None,
type=None),
],
containing_type=None,
options=None,
serialized_start=780,
serialized_end=945,
)
_sym_db.RegisterEnumDescriptor(_OPENCHANNELERRORCODE)
OpenChannelErrorCode = enum_type_wrapper.EnumTypeWrapper(_OPENCHANNELERRORCODE)
_CHANNELCONTENTTYPE = _descriptor.EnumDescriptor(
name='ChannelContentType',
full_name='ascend.presenter.proto.ChannelContentType',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='kChannelContentTypeImage', index=0, number=0,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='kChannelContentTypeVideo', index=1, number=1,
options=None,
type=None),
],
containing_type=None,
options=None,
serialized_start=947,
serialized_end=1027,
)
_sym_db.RegisterEnumDescriptor(_CHANNELCONTENTTYPE)
ChannelContentType = enum_type_wrapper.EnumTypeWrapper(_CHANNELCONTENTTYPE)
_IMAGEFORMAT = _descriptor.EnumDescriptor(
name='ImageFormat',
full_name='ascend.presenter.proto.ImageFormat',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='kImageFormatJpeg', index=0, number=0,
options=None,
type=None),
],
containing_type=None,
options=None,
serialized_start=1029,
serialized_end=1064,
)
_sym_db.RegisterEnumDescriptor(_IMAGEFORMAT)
ImageFormat = enum_type_wrapper.EnumTypeWrapper(_IMAGEFORMAT)
_PRESENTDATAERRORCODE = _descriptor.EnumDescriptor(
name='PresentDataErrorCode',
full_name='ascend.presenter.proto.PresentDataErrorCode',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='kPresentDataErrorNone', index=0, number=0,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='kPresentDataErrorUnsupportedType', index=1, number=1,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='kPresentDataErrorUnsupportedFormat', index=2, number=2,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='kPresentDataErrorOther', index=3, number=-1,
options=None,
type=None),
],
containing_type=None,
options=None,
serialized_start=1067,
serialized_end=1231,
)
_sym_db.RegisterEnumDescriptor(_PRESENTDATAERRORCODE)
PresentDataErrorCode = enum_type_wrapper.EnumTypeWrapper(_PRESENTDATAERRORCODE)
kOpenChannelErrorNone = 0
kOpenChannelErrorNoSuchChannel = 1
kOpenChannelErrorChannelAlreadyOpened = 2
kOpenChannelErrorOther = -1
kChannelContentTypeImage = 0
kChannelContentTypeVideo = 1
kImageFormatJpeg = 0
kPresentDataErrorNone = 0
kPresentDataErrorUnsupportedType = 1
kPresentDataErrorUnsupportedFormat = 2
kPresentDataErrorOther = -1
_OPENCHANNELREQUEST = _descriptor.Descriptor(
name='OpenChannelRequest',
full_name='ascend.presenter.proto.OpenChannelRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='channel_name', full_name='ascend.presenter.proto.OpenChannelRequest.channel_name', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='content_type', full_name='ascend.presenter.proto.OpenChannelRequest.content_type', index=1,
number=2, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=51,
serialized_end=159,
)
_OPENCHANNELRESPONSE = _descriptor.Descriptor(
name='OpenChannelResponse',
full_name='ascend.presenter.proto.OpenChannelResponse',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='error_code', full_name='ascend.presenter.proto.OpenChannelResponse.error_code', index=0,
number=1, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='error_message', full_name='ascend.presenter.proto.OpenChannelResponse.error_message', index=1,
number=2, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=161,
serialized_end=271,
)
_HEARTBEATMESSAGE = _descriptor.Descriptor(
name='HeartbeatMessage',
full_name='ascend.presenter.proto.HeartbeatMessage',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=273,
serialized_end=291,
)
_COORDINATE = _descriptor.Descriptor(
name='Coordinate',
full_name='ascend.presenter.proto.Coordinate',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='x', full_name='ascend.presenter.proto.Coordinate.x', index=0,
number=1, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='y', full_name='ascend.presenter.proto.Coordinate.y', index=1,
number=2, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=293,
serialized_end=327,
)
_RECTANGLE_ATTR = _descriptor.Descriptor(
name='Rectangle_Attr',
full_name='ascend.presenter.proto.Rectangle_Attr',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='left_top', full_name='ascend.presenter.proto.Rectangle_Attr.left_top', index=0,
number=1, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='right_bottom', full_name='ascend.presenter.proto.Rectangle_Attr.right_bottom', index=1,
number=2, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='label_text', full_name='ascend.presenter.proto.Rectangle_Attr.label_text', index=2,
number=3, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=330,
serialized_end=478,
)
_PRESENTIMAGEREQUEST = _descriptor.Descriptor(
name='PresentImageRequest',
full_name='ascend.presenter.proto.PresentImageRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='format', full_name='ascend.presenter.proto.PresentImageRequest.format', index=0,
number=1, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='width', full_name='ascend.presenter.proto.PresentImageRequest.width', index=1,
number=2, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='height', full_name='ascend.presenter.proto.PresentImageRequest.height', index=2,
number=3, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='data', full_name='ascend.presenter.proto.PresentImageRequest.data', index=3,
number=4, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='rectangle_list', full_name='ascend.presenter.proto.PresentImageRequest.rectangle_list', index=4,
number=5, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=481,
serialized_end=664,
)
_PRESENTIMAGERESPONSE = _descriptor.Descriptor(
name='PresentImageResponse',
full_name='ascend.presenter.proto.PresentImageResponse',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='error_code', full_name='ascend.presenter.proto.PresentImageResponse.error_code', index=0,
number=1, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='error_message', full_name='ascend.presenter.proto.PresentImageResponse.error_message', index=1,
number=2, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=666,
serialized_end=777,
)
_OPENCHANNELREQUEST.fields_by_name['content_type'].enum_type = _CHANNELCONTENTTYPE
_OPENCHANNELRESPONSE.fields_by_name['error_code'].enum_type = _OPENCHANNELERRORCODE
_RECTANGLE_ATTR.fields_by_name['left_top'].message_type = _COORDINATE
_RECTANGLE_ATTR.fields_by_name['right_bottom'].message_type = _COORDINATE
_PRESENTIMAGEREQUEST.fields_by_name['format'].enum_type = _IMAGEFORMAT
_PRESENTIMAGEREQUEST.fields_by_name['rectangle_list'].message_type = _RECTANGLE_ATTR
_PRESENTIMAGERESPONSE.fields_by_name['error_code'].enum_type = _PRESENTDATAERRORCODE
DESCRIPTOR.message_types_by_name['OpenChannelRequest'] = _OPENCHANNELREQUEST
DESCRIPTOR.message_types_by_name['OpenChannelResponse'] = _OPENCHANNELRESPONSE
DESCRIPTOR.message_types_by_name['HeartbeatMessage'] = _HEARTBEATMESSAGE
DESCRIPTOR.message_types_by_name['Coordinate'] = _COORDINATE
DESCRIPTOR.message_types_by_name['Rectangle_Attr'] = _RECTANGLE_ATTR
DESCRIPTOR.message_types_by_name['PresentImageRequest'] = _PRESENTIMAGEREQUEST
DESCRIPTOR.message_types_by_name['PresentImageResponse'] = _PRESENTIMAGERESPONSE
DESCRIPTOR.enum_types_by_name['OpenChannelErrorCode'] = _OPENCHANNELERRORCODE
DESCRIPTOR.enum_types_by_name['ChannelContentType'] = _CHANNELCONTENTTYPE
DESCRIPTOR.enum_types_by_name['ImageFormat'] = _IMAGEFORMAT
DESCRIPTOR.enum_types_by_name['PresentDataErrorCode'] = _PRESENTDATAERRORCODE
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
OpenChannelRequest = _reflection.GeneratedProtocolMessageType('OpenChannelRequest', (_message.Message,), dict(
DESCRIPTOR = _OPENCHANNELREQUEST,
__module__ = 'presenter_message_pb2'
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.OpenChannelRequest)
))
_sym_db.RegisterMessage(OpenChannelRequest)
OpenChannelResponse = _reflection.GeneratedProtocolMessageType('OpenChannelResponse', (_message.Message,), dict(
DESCRIPTOR = _OPENCHANNELRESPONSE,
__module__ = 'presenter_message_pb2'
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.OpenChannelResponse)
))
_sym_db.RegisterMessage(OpenChannelResponse)
HeartbeatMessage = _reflection.GeneratedProtocolMessageType('HeartbeatMessage', (_message.Message,), dict(
DESCRIPTOR = _HEARTBEATMESSAGE,
__module__ = 'presenter_message_pb2'
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.HeartbeatMessage)
))
_sym_db.RegisterMessage(HeartbeatMessage)
Coordinate = _reflection.GeneratedProtocolMessageType('Coordinate', (_message.Message,), dict(
DESCRIPTOR = _COORDINATE,
__module__ = 'presenter_message_pb2'
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.Coordinate)
))
_sym_db.RegisterMessage(Coordinate)
Rectangle_Attr = _reflection.GeneratedProtocolMessageType('Rectangle_Attr', (_message.Message,), dict(
DESCRIPTOR = _RECTANGLE_ATTR,
__module__ = 'presenter_message_pb2'
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.Rectangle_Attr)
))
_sym_db.RegisterMessage(Rectangle_Attr)
PresentImageRequest = _reflection.GeneratedProtocolMessageType('PresentImageRequest', (_message.Message,), dict(
DESCRIPTOR = _PRESENTIMAGEREQUEST,
__module__ = 'presenter_message_pb2'
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.PresentImageRequest)
))
_sym_db.RegisterMessage(PresentImageRequest)
PresentImageResponse = _reflection.GeneratedProtocolMessageType('PresentImageResponse', (_message.Message,), dict(
DESCRIPTOR = _PRESENTIMAGERESPONSE,
__module__ = 'presenter_message_pb2'
# @@protoc_insertion_point(class_scope:ascend.presenter.proto.PresentImageResponse)
))
_sym_db.RegisterMessage(PresentImageResponse)
# @@protoc_insertion_point(module_scope)
@@ -0,0 +1,463 @@
# =======================================================================
#
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1 Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2 Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3 Neither the names of the copyright holders nor the names of the
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# =======================================================================
#
"""presenter socket server module"""
import threading
import select
import struct
import logging
import socket
from google.protobuf.message import DecodeError
import common.presenter_message_pb2 as pb2
from common.channel_manager import ChannelManager
from common.channel_handler import ChannelHandler
#read nothing from socket.recv()
SOCK_RECV_NULL = b''
# epool will return if no event coming in 1 s
EPOLL_TIMEOUT = 1
# it specifies the number of unaccepted connections that
# the system will allow before refusing new connections.
SOCKET_WAIT_QUEUE = 2
# message head length, include 4 bytes message total length
# and 1 byte message name length
MSG_HEAD_LENGTH = 5
class PresenterSocketServer():
"""a socket server communication with presenter agent.
"""
def __init__(self, server_address):
"""
Args:
server_address: server listen address,
include an ipv4 address and a port.
"""
# thread exit switch, if set true, thread must exit immediately.
self.thread_exit_switch = False
# message head length, include 4 bytes message total length
# and 1 byte message name length
self.msg_head_len = 5
self._create_socket_server(server_address)
def _create_socket_server(self, server_address):
"""
create a socket server
Args:
server_address: server listen address,
include an ipv4 address and a port.
"""
# Create a socket server.
self._sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._sock_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self._sock_server.bind(server_address)
self._sock_server.listen(SOCKET_WAIT_QUEUE)
self._sock_server.setblocking(False)
# Get server host name and port
host, port = self._sock_server.getsockname()[:2]
# Start presenter socket server thread.
threading.Thread(target=self._server_listen_thread).start()
# Display directly on the screen
print('Presenter socket server listen on %s:%s\n' % (host, port))
def set_exit_switch(self):
"""set switch True to stop presenter socket server thread."""
self.thread_exit_switch = True
def _read_socket(self, conn, read_len):
'''
Read fixed length data
Args:
conn: a socket connection
read_len: read fix byte.
Returns:
ret: True or False
buf: read fix byte buf.
'''
has_read_len = 0
read_buf = SOCK_RECV_NULL
total_buf = SOCK_RECV_NULL
while has_read_len != read_len:
try:
read_buf = conn.recv(read_len - has_read_len)
except socket.error:
logging.error("socket %u exception:socket.error", conn.fileno())
return False, None
if read_buf == SOCK_RECV_NULL:
return False, None
total_buf += read_buf
has_read_len = len(total_buf)
return True, total_buf
def _read_msg_head(self, sock_fileno, conns):
'''
Args:
sock_fileno: a socket fileno
conns: all socket connections which created by server.
Returns:
msg_total_len: total message length.
msg_name_len: message name length.
'''
ret, msg_head = self._read_socket(conns[sock_fileno], self.msg_head_len)
if not ret:
logging.error("socket %u receive msg head null", sock_fileno)
return None, None
# in Struct(), 'I' is unsigned int, 'B' is unsigned char
msg_head_data = struct.Struct('IB')
(msg_total_len, msg_name_len) = msg_head_data.unpack(msg_head)
msg_total_len = socket.ntohl(msg_total_len)
return msg_total_len, msg_name_len
def _read_msg_name(self, sock_fd, conns, msg_name_len):
'''
Args:
sock_fd: a socket fileno
conns: all socket connections which created by server.
msg_name_len: message name length.
Returns:
ret: True or False
msg_name: message name.
'''
ret, msg_name = self._read_socket(conns[sock_fd], msg_name_len)
if not ret:
logging.error("socket %u receive msg name null", sock_fd)
return False, None
try:
msg_name = msg_name.decode("utf-8")
except UnicodeDecodeError:
logging.error("msg name decode to utf-8 error")
return False, None
return True, msg_name
def _read_msg_body(self, sock_fd, conns, msg_body_len, msgs):
'''
Args:
sock_fd: a socket fileno
conns: all socket connections which created by server.
msg_name_len: message name length.
msgs: msg read from a socket
Returns:
ret: True or False
'''
ret, msg_body = self._read_socket(conns[sock_fd], msg_body_len)
if not ret:
logging.error("socket %u receive msg body null", sock_fd)
return False
msgs[sock_fd] = msg_body
return True
def _read_sock_and_process_msg(self, sock_fileno, conns, msgs):
'''
Args:
sock_fileno: a socket fileno, return value of socket.fileno()
conns: all socket connections registered in epoll
msgs: msg read from a socket
Returns:
ret: True or False
'''
# Step1: read msg head
msg_total_len, msg_name_len = self._read_msg_head(sock_fileno, conns)
if msg_total_len is None:
logging.error("msg_total_len is None.")
return False
# Step2: read msg name
ret, msg_name = self._read_msg_name(sock_fileno, conns, msg_name_len)
if not ret:
return ret
# Step3: read msg body
msg_body_len = msg_total_len - self.msg_head_len - msg_name_len
if msg_body_len < 0:
logging.error("msg_total_len:%u, msg_name_len:%u, msg_body_len:%u",
msg_total_len, msg_name_len, msg_body_len)
return False
ret = self._read_msg_body(sock_fileno, conns, msg_body_len, msgs)
if not ret:
return ret
# Step4: process msg
ret = self._process_msg(conns[sock_fileno], msg_name, msgs[sock_fileno])
return ret
def _process_epollin(self, sock_fileno, epoll, conns, msgs):
'''
Args:
sock_fileno: a socket fileno, return value of socket.fileno()
epoll: a set of select.epoll.
conns: all socket connections registered in epoll
msgs: msg read from a socket
'''
msgs[sock_fileno] = b''
try:
ret = self._read_sock_and_process_msg(sock_fileno, conns, msgs)
if not ret:
self._clean_connect(sock_fileno, epoll, conns, msgs)
except socket.error:
logging.error("receive socket error.")
self._clean_connect(sock_fileno, epoll, conns, msgs)
def _accept_new_socket(self, epoll, conns):
'''
Args:
epoll: a set of select.epoll.
conns: all socket connections registered in epoll
'''
try:
new_conn, address = self._sock_server.accept()
new_conn.setblocking(True)
epoll.register(new_conn.fileno(), select.EPOLLIN | select.EPOLLHUP)
conns[new_conn.fileno()] = new_conn
logging.info("create new connection:client-ip:%s, client-port:%s, fd:%s",
address[0], address[1], new_conn.fileno())
except socket.error:
logging.error("socket.error exception when sock.accept()")
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:
# thread must exit immediately
if self.thread_exit_switch:
break
events = epoll.poll(EPOLL_TIMEOUT)
# timeout, but no event come, continue waiting
if not events:
continue
for sock_fileno, event in events:
# new connection request from presenter agent
if 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:
logging.info("receive event EPOLLHUP")
self._clean_connect(sock_fileno, epoll, conns, msgs)
# new data coming in a socket connection
elif event & select.EPOLLIN:
self._process_epollin(sock_fileno, epoll, conns, msgs)
# receive event not recognize
else:
logging.error("not recognize event %f", event)
self._clean_connect(sock_fileno, epoll, conns, msgs)
finally:
logging.info("conns:%s", conns)
logging.info("presenter server listen thread exit.")
epoll.unregister(self._sock_server.fileno())
epoll.close()
self._sock_server.close()
def _process_heartbeat(self, conn):
'''
set heartbeat
Args:
conn: a socket connection
Returns:
True: set heartbeat ok.
'''
sock_fileno = conn.fileno()
handler = self.channel_manager.get_channel_handler_by_fd(sock_fileno)
if handler is not None:
handler.set_heartbeat()
return True
def _process_open_channel(self, conn, msg_data):
"""
Deserialization protobuf and process open_channel request
Args:
conn: a socket connection
msg_data: a protobuf struct, include open channel request.
Returns:
protobuf structure like this:
----------------------------------------------
|channel_name | string |
|----------------------------------------------
|content_type | ChannelContentType |
|----------------------------------------------
enum ChannelContentType {
kChannelContentTypeImage = 0;
kChannelContentTypeVideo = 1;
}
"""
request = pb2.OpenChannelRequest()
response = pb2.OpenChannelResponse()
try:
request.ParseFromString(msg_data)
except DecodeError:
logging.error("ParseFromString exception: Error parsing message")
channel_name = "unknown channel"
return self._response_open_channel(conn, channel_name, response,
pb2.kOpenChannelErrorOther)
channel_name = request.channel_name
# check channel name if exist
if not self.channel_manager.is_channel_exist(channel_name):
logging.error("channel name %s is not exist.", channel_name)
# if channel is not exist, need to create the channel
ret = self.channel_manager.register_one_channel(channel_name)
if ret != ChannelManager.err_code_ok:
logging.error("Create the channel %s failed!, and ret is %d", channel_name, ret)
err_code = pb2.kOpenChannelErrorOther
self._response_open_channel(conn, channel_name, response, err_code)
# check channel path if busy
if self.channel_manager.is_channel_busy(channel_name):
logging.error("channel path %s is busy.", channel_name)
err_code = pb2.kOpenChannelErrorChannelAlreadyOpened
return self._response_open_channel(conn, channel_name, response,
err_code)
# if channel type is image, need clean image if exist
self.channel_manager.clean_channel_image(channel_name)
if request.content_type == pb2.kChannelContentTypeImage:
media_type = "image"
elif request.content_type == pb2.kChannelContentTypeVideo:
media_type = "video"
else:
logging.error("media type %s is not recognized.",
request.content_type)
return self._response_open_channel(conn, channel_name, response,
pb2.kOpenChannelErrorOther)
handler = ChannelHandler(channel_name, media_type)
self.channel_manager.create_channel_resource(
channel_name, conn.fileno(), media_type, handler)
return self._response_open_channel(conn, channel_name, response,
pb2.kOpenChannelErrorNone)
def _response_open_channel(self, conn, channel_name, response, err_code):
"""
Assemble protobuf to response open_channel request
Args:
conn: a socket connection
channel_name: name of a channel.
response: a protobuf response to presenter agent
err_code: part of the response
Returns:
ret_code:True or False
Message structure like this:
--------------------------------------------------------------------
|total message len | int | 4 bytes |
|-------------------------------------------------------------------
|message name len | byte | 1 byte |
|-------------------------------------------------------------------
|message name | string | xx bytes |
|-------------------------------------------------------------------
|message body | protobuf | xx bytes |
--------------------------------------------------------------------
protobuf structure like this:
--------------------------------------------------------------------
|error_code | enum | OpenChannelErrorCode |
|-------------------------------------------------------------------
|error_message | string | xx bytes |
|-------------------------------------------------------------------
enum OpenChannelErrorCode {
kOpenChannelErrorNone = 0;
kOpenChannelErrorNoSuchChannel = 1;
kOpenChannelErrorChannelAlreadyOpened = 2;
kOpenChannelErrorOther = -1;
}
"""
response.error_code = err_code
ret_code = False
if err_code == pb2.kOpenChannelErrorNoSuchChannel:
response.error_message = "channel {} not exist." \
.format(channel_name)
elif err_code == pb2.kOpenChannelErrorChannelAlreadyOpened:
response.error_message = "channel {} is busy.".format(channel_name)
elif err_code == pb2.kOpenChannelErrorNone:
response.error_message = "open channel succeed"
ret_code = True
else:
response.error_message = "Unknown err open channel {}." \
.format(channel_name)
self.send_message(conn, response, pb2._OPENCHANNELRESPONSE.full_name)
return ret_code
def send_message(self, conn, protobuf, msg_name):
'''
API for send message
Args:
conn: a socket connection.
protobuf: message body defined in protobuf.
msg_name: msg name.
Returns: NA
'''
message_data = protobuf.SerializeToString()
message_len = len(message_data)
msg_name_size = len(msg_name)
msg_total_size = self.msg_head_len + msg_name_size + message_len
# in Struct(), 'I' is unsigned int, 'B' is unsigned char
s = struct.Struct('IB')
msg_head = (socket.htonl(msg_total_size), msg_name_size)
packed_msg_head = s.pack(*msg_head)
msg_data = packed_msg_head + \
bytes(msg_name, encoding="utf-8") + message_data
conn.sendall(msg_data)
+123
View File
@@ -0,0 +1,123 @@
#!/usr/bin/env python3
# =======================================================================
#
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1 Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2 Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3 Neither the names of the copyright holders nor the names of the
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# =======================================================================
#
"""presenter server module"""
import os
import sys
import signal
import argparse
import logging
WEB_SERVER = None
APP_SERVER = None
RUN_SERVER = None
SERVER_TYPE = ""
USAGE_INFO = "python3 prensenter_server.py [-h] --app \n\t\t\t\t{body_pose}"
BODY_MAP = {"web_server": "body_pose.src.web",
"app_server": "body_pose.src.body_pose_server"
}
APP_CONF_MAP = {"body_pose": BODY_MAP}
def arg_parse():
'''arg_parse'''
global WEB_SERVER
global APP_SERVER
global SERVER_TYPE
parser = argparse.ArgumentParser(usage=USAGE_INFO)
parser.add_argument('--app', type=str, required=True,
choices=['body_pose'],
help="Application type corresponding to Presenter Server.")
args = parser.parse_args()
SERVER_TYPE = args.app
app_conf = APP_CONF_MAP.get(SERVER_TYPE)
WEB_SERVER = __import__(app_conf.get("web_server"), fromlist=True)
APP_SERVER = __import__(app_conf.get("app_server"), fromlist=True)
def start_app():
global RUN_SERVER
# start socket server for presenter agent communication
RUN_SERVER = APP_SERVER.run()
if RUN_SERVER is None:
return False
logging.info("presenter server starting, type: %s", SERVER_TYPE)
# start web ui
return WEB_SERVER.start_webapp()
def stop_app():
WEB_SERVER.stop_webapp()
RUN_SERVER.stop_thread()
def close_all_thread(signum, frame):
'''close all thread of the process, and exit.'''
logging.info("receive signal, signum:%s, frame:%s", signum, frame)
stop_app()
logging.info("presenter server exit by Ctrl + c")
sys.exit()
def check_server_exist():
pid = os.getpid()
cmd = "ps -ef|grep -v {}|grep -w presenter_server|grep {}" \
.format(pid, SERVER_TYPE)
ret = os.system(cmd)
return ret
def main_process():
'''Main function entrance'''
arg_parse()
if check_server_exist() == 0:
print("Presenter Server type \"%s\" already exist!" %(SERVER_TYPE))
return True
# process signal, when receive "Ctrl + c" signal,
# stop all thead and exit the progress.
signal.signal(signal.SIGINT, close_all_thread)
signal.signal(signal.SIGTERM, close_all_thread)
start_app()
return True
if __name__ == "__main__":
main_process()
+2
View File
@@ -0,0 +1,2 @@
tornado == 5.1.0
protobuf == 3.11.3
+267
View File
@@ -0,0 +1,267 @@
#!/bin/bash
app_script_path="$( cd "$(dirname ${BASH_SOURCE})" ; pwd -P )"
app_path=$app_script_path/../
app_name="body_pose"
# ************************convert CIDR to netmask****************************************
# Description: convert CIDR to netmask
# $1: CIDR
# ******************************************************************************
function cidr2mask()
{
# Number of args to shift, 255..255, first non-255 byte, zeroes
set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0
[ $1 -gt 1 ] && shift $1 || shift
echo ${1-0}.${2-0}.${3-0}.${4-0}
}
function check_ip_addr()
{
echo "check ip $1"
ip_addr=$1
ip_addr=$(echo "$ip_addr" | grep "^[0-9]\{1,3\}\.\([0-9]\{1,3\}\.\)\{2\}[0-9]\{1,3\}$")
if [ -z "$ip_addr" ]
then
echo "ip_addr $ip_addr invalid"
return 1
fi
for num in `echo ${ip_addr} | sed "s/./ /g"`
do
if [ $num -gt 255 ] || [ $num -lt 0 ]
then
return 1
fi
done
return 0
}
function check_board_ip()
{
#check format of remost_host ip
board_ip=$(cat ${app_path}/body_pose.conf | grep "presenter_agent_ip" | awk -F'[ =]+' '{print $2}')
board_ip=$(echo $board_ip | sed -e 's/\r//' | sed -e 's/\n//' | sed -e 's/ //')
if [[ "$board_ip" = "" ]];then
echo "please check your body_pose.conf to make sure that each parameter has a value"
return 1
fi
check_ip_addr $board_ip
if [ $? -ne 0 ];then
echo "ERROR: invalid board_ip ip, please check your settings in configuration file"
return 1
fi
}
function check_python3_lib()
{
echo "Check python3 libs ......"
tornado_obj=$(cat ${app_path}/presenterserver/requirements | grep tornado | awk -F'[ =]+' '{print $2}')
if [ $? -ne 0 ];then
echo "ERROR: please check your env."
return 1
elif [ 5.1.0 = ${tornado_obj} ];then
tornado_obj=5.1
fi
protobuf_obj=$(cat ${app_path}/presenterserver/requirements | grep protobuf | awk -F'[ =]+' '{print $2}')
if [ $? -ne 0 ];then
echo "ERROR: please check your env."
return 1
fi
numpy_obj=$(cat ${app_path}/presenterserver/requirements | grep numpy | awk -F'[ =]+' '{print $2}')
if [ $? -ne 0 ];then
echo "ERROR: please check your env."
return 1
fi
if tornado=$(python3 -c "import tornado;print(tornado.version)" 2>/dev/null);then
if [ ${tornado} != ${tornado_obj} ];then
pip3 install tornado==${tornado_obj} 2>/dev/null
if [ $? -ne 0 ];then
echo "ERROR: install tornado failed, please check your env."
return 1
fi
fi
else
pip3 install tornado==${tornado_obj} 2>/dev/null
if [ $? -ne 0 ];then
echo "ERROR: install tornado failed, please check your env."
return 1
fi
fi
if protobuf=$(python3 -c "import google.protobuf;print(google.protobuf.__version__)" 2>/dev/null);then
if [ ${protobuf} != ${protobuf_obj} ];then
pip3 install protobuf==${protobuf_obj} 2>/dev/null
if [ $? -ne 0 ];then
echo "ERROR: install protobuf failed, please check your env."
return 1
fi
fi
else
pip3 install protobuf==${protobuf_obj} 2>/dev/null
if [ $? -ne 0 ];then
echo "ERROR: install protobuf failed, please check your env."
return 1
fi
fi
if numpy=$(python3 -c "import numpy;print(numpy.__version__)" 2>/dev/null);then
if [ ${numpy} != ${numpy_obj} ];then
pip3 install numpy==${numpy_obj} 2>/dev/null
if [ $? -ne 0 ];then
echo "ERROR: install numpy failed, please check your env."
return 1
fi
fi
else
pip3 install numpy==${numpy_obj} 2>/dev/null
if [ $? -ne 0 ];then
echo "ERROR: install numpy failed, please check your env."
return 1
fi
fi
echo "python3 libs have benn prepared."
}
function parse_presenter_view_ip()
{
presenter_view_ip=$(cat ${app_path}/body_pose.conf | grep "presenter_view_ip" | awk -F'[ =]+' '{print $2}')
presenter_view_ip=$(echo $presenter_view_ip | sed -e 's/\r//' | sed -e 's/\n//' | sed -e 's/ //')
if [[ "presenter_view_ip" = "" ]];then
echo "please check your body_pose.conf to make sure that each parameter has a value"
return 1
fi
echo "presenter_view_ip is $presenter_view_ip"
check_ip_addr $presenter_view_ip
if [ $? -ne 0 ];then
echo "ERROR: invalid presenter_view_ip ip, please check your settings in configuration file"
return 1
fi
return 0
}
function check_ips_in_same_segment()
{
ip=$1
mask=$2
board_ip=$3
OLD_IFS_IP="${IFS}"
IFS="."
board_ip_attr=(${board_ip})
ip_attr=(${ip})
mask_attr=(${mask})
IFS=${OLD_IFS_IP}
for i in `seq 0 3`
do
((calc_remote=${board_ip_attr[${i}]}&${mask_attr[${i}]}))
((calc_ip=${ip_attr[${i}]}&${mask_attr[${i}]}))
if [[ calc_remote -ne calc_ip ]];then
return 1
fi
done
return 0
}
# ************************parse presenter_altasdk ip****************************
# Description: parse presenter_altasdk ip right or not
# $1: board_ip ip
# ******************************************************************************
function parse_presenter_altasdk_ip()
{
valid_ips=""
board_ip=$1
for ip_info in `/sbin/ip addr | grep "inet " | awk -F ' ' '{print $2}'`
do
ip=`echo ${ip_info} | awk -F '/' '{print $1}'`
cidr=`echo ${ip_info} | awk -F '/' '{print $2}'`
valid_ips="${valid_ips}\t${ip}\n"
mask=`cidr2mask ${cidr}`
if [[ ${ip}"X" == "X" ]];then
continue
fi
check_ips_in_same_segment ${ip} ${mask} ${board_ip}
if [[ $? -eq 0 ]];then
presenter_atlasdk_ip=${ip}
echo "Find ${presenter_atlasdk_ip} which is in the same segment with ${board_ip}."
break
fi
done
if [[ ${presenter_atlasdk_ip}"X" != "X" ]];then
return 0
fi
echo "Can not find ip in the same segment with ${board_ip}."
while [[ ${presenter_atlasdk_ip}"X" == "X" ]]
do
echo -en "Current environment valid ip list:\n${valid_ips}Please choose one which can connect to Atlas DK Developerment Board:"
read presenter_atlasdk_ip
if [[ ${presenter_atlasdk_ip}"X" != "X" ]];then
check_ip_addr ${presenter_atlasdk_ip}
if [[ $? -ne 0 ]];then
echo "Invlid ip, please choose again..."
presenter_atlasdk_ip=""
else
# using grep to detect the field, using "$?" return non-zero value if corresponding filed is not found
ret=`/sbin/ifconfig | grep ${presenter_atlasdk_ip}`
if [[ $? -ne 0 ]];then
presenter_atlasdk_ip=""
fi
fi
fi
done
return 0
}
function main()
{
stop_pid=`ps -ef | grep "presenter_server\.py" | grep "${app_name}" | awk -F ' ' '{print $2}'`
if [[ ${stop_pid}"X" != "X" ]];then
echo -e "\033[33mNow do presenter server configuration, kill existing presenter process: kill -9 ${stop_pid}.\033[0m"
kill -9 ${stop_pid}
fi
check_python3_lib
if [ $? -ne 0 ];then
return 1
fi
#get and check format of remost_host ip
check_board_ip
if [ $? -ne 0 ];then
return 1
fi
parse_presenter_altasdk_ip ${board_ip}
parse_presenter_view_ip
# 1. copy ip value to config.config after checking ip
echo "Use ${presenter_atlasdk_ip} to connect to Atlas DK Developerment Board..."
sed -i "s/presenter_server_ip=[0-9.]*/presenter_server_ip=${presenter_atlasdk_ip}/g" ${app_path}/presenterserver/body_pose/config/config.conf
echo "Use ${presenter_view_ip} to show information in browser..."
sed -i "s/web_server_ip=[0-9.]*/web_server_ip=${presenter_view_ip}/g" ${app_path}/presenterserver/body_pose/config/config.conf
echo "Finish to prepare ${app_name} presenter server ip configuration."
python3 ${app_path}/presenterserver/presenter_server.py --app ${app_name} &
return 0
}
main
+39
View File
@@ -0,0 +1,39 @@
import cv2
import numpy as np
import math
import os, sys
sys.path.append('../..')
heatmap_width = 92
heatmap_height = 92
"""
14 joints:
0-right shoulder, 1-right elbow, 2-right wrist, 3-left shoulder, 4-left elbow, 5-left wrist,
6-right hip, 7-right knee, 8-right ankle, 9-left hip, 10-left knee, 11-left ankle,
12-top of the head and 13-neck
"""
JOINT_LIMB = [[0, 1], [1, 2], [3, 4], [4, 5], [6, 7], [7, 8], [9, 10], [10, 11], [12, 13], [13, 0], [13, 3], [13, 6], [13, 9]]
COLOR = [[0, 255, 255], [0, 255, 255],[0, 255, 255],[0, 255, 255],[0, 255, 0],[0, 255, 0],[0, 255, 0],[0, 255, 0], [0, 0, 255], [255, 0, 0],[255, 0, 0],[255, 0, 0], [255, 0, 0]]
def decode_pose(heatmaps, scale, image_original):
#obtain joint list from heatmap
joint_list = [peak_index_to_coords(heatmap)*scale for heatmap in heatmaps]
#plot the pose on original image
canvas = image_original
for idx, limb in enumerate(JOINT_LIMB):
joint_from, joint_to = joint_list[limb[0]], joint_list[limb[1]]
canvas = cv2.line(canvas, tuple(joint_from.astype(int)), tuple(joint_to.astype(int)), color=COLOR[idx], thickness=4)
return canvas
def peak_index_to_coords(peak_index):
'''
@peak_index is the index of max value in flatten heatmap
This function convert it back to the coordinates of the original heatmap
'''
peak_coords = np.unravel_index(int(peak_index),(heatmap_height, heatmap_width))
return np.flip(peak_coords)