1. 前言
基于云端实时视频智能检测的功能,在居家安防监控领域有着较高的价值。这一场景的实现通常如下图所示分为如下几个阶段:视频流产生(Producer)、视频流存储(Storage)、视频流处理(Consumer)。
当前使用低成本的网络摄像头(硬件资源有限,不支持边缘推理计算)+云端存储推理实现家用及中小商户安防监控成为一个流行的方式。在实际的应用过程中往往需要根据AI场景的复杂性、多样性、成本的考量、技术难度差异选择适合当前现状的方案。例如基于成本优化的考虑,我们希望采用图片作为智能检测的数据输入,发送用户告警通知的媒体信息通常也是图片格式,因此通常需要从视频流中提取图片,但从视频流中抽取图片往往需要维护可扩展的计算资源来将视频转码为图片格式,这对没有的专业领域技术积累的团队来说是个不小的挑战。本文将详细介绍如何使用AWS新推出的Amazon Kinesis Video Streams Images来简化云端抽图。
1.1 相关产品介绍
- Amazon Kinesis Video Streams 是一项完全托管的 Amazon 服务,您可以使用 Kinesis Video Streams 捕获来自数百万种源 (包括智能手机、安全摄像头、网络摄像头、车载摄像头、无人机及其他源) 的海量实时视频数据传输到 Amazon云,或者构建应用程序以进行实时视频处理或进行面向批处理的视频。
- Amazon Kinesis Video Stream Images是KVS上一组完全托管的API,它提供了如下的功能特性:
- 以完全托管的方式从KVS视频流中抽取图片并保存到S3。
- 使用KVS Consumer侧提供的GetImages API按需从KVS视频流中抽取图片。
- 基于标签KVS Producer端的标签,自动触发Amazon SNS的通知。
借助上述功能,您可以构建视频流检测的通知,基于视频流中的抽取的图片构建智能视频检测应用。
- Amazon Rekognition 提供预先训练和可定制的计算机视觉 (CV) 功能,可从您的图像和视频中提取信息和获得洞察力。提供高精度的人脸分析检测、人脸比较和人脸搜索、标签文本检测等功能。Amazon Rekognition 基于同样由Amazon计算机视觉科学家开发的成熟且高度可扩展的深度学习技术,每天能够分析数十亿图像和视频。它不需要机器学习专业知识即可使用。Amazon Rekognition 包含一个简单易用的API,该API 可快速分析存储在Amazon S3 中的任何图像或视频文件。
2.Amazon Kinesis Video Stream Images方案分析
2.1 方案概述
Kinesis Video Stream Images方案整体架构分为:设备端、AWS云端、用户应用端。
为带有一定视频检测能力的摄像头设备、通过集成KVS SDK作为KVS的Producer向云端KVS Stream推送视频流,并基于摄像头设备的检测能力给KVS MKV数据打Tag,这些Tag的用途一是作为KVS Image API的触发标志,二是作为业务逻辑处理的依据。
- AWS云端
- Amazon Kinesis Video Stream :提供设备视频持久化存储、视频检索、视频在线查看、视频下载等能力,并向Rekognition提供用于视频检测的数据。
- Amazon Rekognition:提供自动执行视频和图像分析的能力,包括基于视频或图像的内容审核、人脸检测、人脸比较、标签检测等完全托管的能力,并且可以方便的与KVS、S3、SNS等服务集成。
- Amazon S3:提供视频检测结果的存储。
- Amazon SNS:完全托管的发布/订阅消息收发、SMS、电子邮件和移动推送通知在本方案中提供通知发送的能力。
该方案的整体架构图如下
2.2方案说明
设备端通常是带有一定检测能力的摄像头设备,集成KVS Prouder SDK。借助自身的视频检测能力给视频帧打标签,并使用KVS prouder SDK将视频流推送到云端。
云端视频流Processor通过AWS Service提供如下处理能力:
视频云存:KVS Video Streams是AWS在云端的视频流存储资源,它可以提供视频数据的持久化存储,并提供视频检测和回放的API以实现复杂的需求场景。
抽图:通过KVS您可以使用KVS GetMedia或GetImages API从视频流中抽取图片、发送告警通知、智能视频检测处理。
通知告警:采用SNS与KVS images无缝集成的方式,您只需调用API进行一些简单的配置就可以构建视频通知告警的方案。
智能视频检测:云端的视频检测实现方式有三种:基于Sagemaker、基于Rekognition、基于EC2自建模型。
应用端通常是APP,集成KVS Consumer SDK和消息推送服务,可以从KVS中按需回看视频或者查看存储在S3中的图片。
3. 方案集成验证
3.1 实验准备工作
3.1.1 准备AWS资源
1、本次实验需要用到的AWS资源都在Ireland Region中创建,您需要提前准备好一个AWS account。
2、在AWS IAM中创建一个Admin User,赋予arn:aws:iam::aws:policy/AdministratorAccess策略,后续的资源创建都使用这个用户来操作。
3、在AWS IAM的Admin User创建一个AKSK,并记录下来,后面的实验环境需要用到。创建IAM User AKSK的方法请参考如下的文档:https://docs.thinkwithwp.com/IAM/latest/UserGuide/id_credentials_access-keys.html
- 创建Cloud9用于模拟KVS Producer和Consumer
创建Amazon Cloud9的方法请参考如下的文档:
https://catalog.us-east-1.prod.workshops.aws/workshops/b95b9381-baf0-4bef-ba31-63817d54c2a6/en-US/lab-1/cloud9
注意:由于默认创建的Cloud9的存储空间有限,建议在执行后面的操作之前先扩展Cloud9的空间,如何扩展Cloud9的存储空间请参照如下链接中的Disk Space Expansion章节。
https://catalog.us-east-1.prod.workshops.aws/workshops/b95b9381-baf0-4bef-ba31-63817d54c2a6/en-US/lab-1/cloud9
在Cloud9的终端中执行如下命令配置profile
$ aws configure --profile your-profile-name
AWS Access Key ID [None]:your AWS Access Key ID
AWS Secret Access Key [None]:your AWS Secret Access Key
Default region name [None]: eu-west-1
Default output format [None]: json
- 创建Amazon S3 Bucket用于保存从KVS中抽取的图片
aws s3 mb s3://sample-bucket-name --region eu-west-1
注意上面创建的Cloud9、S3 Bucket和SNS需要位于同一个AWS的Region。如下图所示:
- 创建云端的Kinesis Video Stream
3.1.2 模拟KVS Producer设备端环境准备
sudo apt-get update
sudo apt-get install -y cmake git gcc g++ autoconf
sudo apt-get install -y libssl-dev libcurl4-openssl-dev liblog4cplus-dev pkg-config
1.下载工程代码
git clone --recursive https://github.com/awslabs/amazon-kinesis-video-streams-producer-c.git
2.工程代码
mkdir -p amazon-kinesis-video-streams-producer-c/build
cd amazon-kinesis-video-streams-producer-c/build
cmake .. -DBUILD_TEST=TRUE
make
3.1.2 模拟KVS Consumer端环境准备
sudo apt update
sudo apt install software-properties-common
sudo add-apt-repository ppa:deadsnakes/ppa
Consumer端的代码依赖于Python3.7 您需要按如下操作将Python的版本升级到3.7
执行如下命令查看Python的版本,如果版本是python3.6需要将Python版本更新到3.7
python3 —version
如果您的Python版本已经是python3.7可以跳过下面的步骤,如果是python3.6执行如下的操作
sudo apt install python3.7
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 1
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.7 2
sudo update-alternatives --config python3
Selection Path Priority Status
------------------------------------------------------------
* 0 /usr/bin/python3.7 2 auto mode
1 /usr/bin/python3.6 1 manual mode
2 /usr/bin/python3.7 2 manual mode
Press <enter> to keep the current choice[*], or type selection number:0
选择0
再次执行python3 —version
Python 3.7.13
1.下载工程代码
git clone https://github.com/arch-team/amazon-kinesis-video-streams-time-lapse-video-main.git
2.更新pip工具
sudo python3 -m pip install -U pip
sudo python3 -m pip install -U setuptools
sudo apt-get update
sudo apt-get install ffmpeg libsm6 libxext6 -y
在Cloud9的终端中执行如下命令配置profile
export AWS_SESSION_TOKEN=your-SessionToken
export AWS_DEFAULT_REGION=eu-west-1
export AWS_ACCESS_KEY_ID=your AccessKeyId
export AWS_SECRET_ACCESS_KEY=your SecretAccessKey
python3 main.py —stream-name your-stream-name
—start-time 2022-05-31T09:40:33 # 开始时间
—end-time 2022-05-31T09:42:19 # 结束时间
—duration 3 # 采用周期
—width 1920 —height 1080 # 图片分辨率
—output-path result1.mp4
3.2 自动从KVS中抽图流程说明
基于KVS Image功能之Auto Image Generation的处理流程如下图所示
3.2.1 执行UpdateImageGenerationConfiguration配置KVS自动抽图
UpdateImageGenerationConfiguration是配置KVS 图片抽取参数的API,通过该API您可以配置KVS自动抽图的采样周期、图片保存的S3存储桶、图片格式、图片像素等信息。
- 准备
update-image-generation-input.json
文件
{
"StreamName": "TestStream", # 为您在3.1.1中创建的KVS Stream的名称
"ImageGenerationConfiguration": {
"Status": "ENABLED", # ENABLED或DISABLE 控制该项功能的启用或禁止
"DestinationConfig": {
"DestinationRegion": "us-east-1", # 为您在3.1.1中创建的S3所在的Region,本实验使用eu-west-1
"Uri": "s3://bucket-name" # bucket-name为您在3.1.1中创建的S3的Bucket名称
},
"SamplingInterval": 3000, # 抽取图片的间隔时间
"ImageSelectorType": "PRODUCER_TIMESTAMP", # 时间类型
"Format": "JPEG", # 图片格式
"FormatConfig": {
"JPEGQuality": "80"
},
"WidthPixels": 320, # 图片像素
"HeightPixels": 240 # 图片像素
}
}
- 执行UpdateImageGenerationConfiguration API
aws kinesisvideo update-image-generation-configuration \
--cli-input-json file://./update-image-generation-input.json \
3.2.2 执行UpdateNotificationConfiguration配置KVS基于SNS通知下发
UpdateNotificationConfiguration是配置基于SNS自动化通知下发的API,通过该API配置KVS Stream之后,当KVS接受到producer发送到带有AWS_KINESISVIDEO_NOTIFICATION
标签的帧后,会触发SNS通知。
- 准备update-notification-configuration.json文件
{
"NotificationConfiguration": {
"DestinationConfig": {
"Uri": "string" # SNS ARN
},
"Status": "string" # ENABLED或DISABLE 控制该项功能的启用或禁止
},
"StreamARN": "string", # StreamARN 与 StreamName二者选填一个,用于标识KVS
"StreamName": "string"
}
该命令执行如果报权限错误,您需要在该命令中指定profile, 在上面的命令后加上–profile your profile name
- 执行UpdateNotificationConfiguration API
aws kinesisvideo update-notification-configuration —cli-input-json file://./updateNotificationConfiguration.json
注意:
1、执行UpdateImageGenerationConfiguration或UpdateNotificationConfiguration后,KVS Stream的自动图片抽取和基于SNS需要1分钟之后才能生效。
2、UpdateImageGenerationConfiguration采样的时间间隔最小是3秒钟,如果您想要提高采样频率可以联系AWS support来提升。
3.2.3 Cloud9模拟KVS Producer推送视频流
执行如下命令:aws sts get-session-token —profile your profile name获取临时 token
"Credentials": {
"AccessKeyId": "your AccessKeyId",
"SecretAccessKey": "your SecretAccessKey",
"SessionToken": "your SessionToken",
"Expiration": "2022-05-30T21:03:10Z"
}
export AWS_SESSION_TOKEN=your SessionToken
export AWS_DEFAULT_REGION=eu-west-1
export AWS_ACCESS_KEY_ID=your AccessKeyId
export AWS_SECRET_ACCESS_KEY=your SecretAccessKey
status = putKinesisVideoFrame(data->streamHandle, &frame);
if (data->firstFrame) {
startUpLatency = (DOUBLE)(GETTIME() - data->startTime) / (DOUBLE) HUNDREDS_OF_NANOS_IN_A_MILLISECOND;
DLOGD("Start up latency: %lf ms", startUpLatency);
data->firstFrame = FALSE;
}
else if (frame.flags == FRAME_FLAG_KEY_FRAME) {
if(gKeyFrameCount%KEYFRAME_EVENT_INTERVAL == 0)
{
//reset to 0 to avoid overflow in long running applications
gKeyFrameCount = 0;
switch (gEventsEnabled) {
// NOTIFICATION标签
case 1:
putKinesisVideoEventMetadata(data->streamHandle, STREAM_EVENT_TYPE_NOTIFICATION, NULL);
break;
// IMAGE_GENERATION标签
case 2:
putKinesisVideoEventMetadata(data->streamHandle, STREAM_EVENT_TYPE_IMAGE_GENERATION, NULL);
break;
// NOTIFICATION和IMAGE_GENERATION标签
case 3:
putKinesisVideoEventMetadata(data->streamHandle, STREAM_EVENT_TYPE_NOTIFICATION | STREAM_EVENT_TYPE_IMAGE_GENERATION, NULL);
break;
default:
break;
}
}
gKeyFrameCount++;
}
Producer端视频帧无标签,这时不会触发自动抽图和Notification
./kvsAudioVideoStreamingSample kvs-images-lab 600 ../samples aac
Producer端给视频帧打上STREAM_EVENT_TYPE_IMAGE_GENERATION,仅自动抽图
./kvsAudioVideoStreamingSample kvs-images-lab 600 ../samples aac image
Producer端给视频帧打上STREAM_EVENT_TYPE_NOTIFICATION,仅notification
./kvsAudioVideoStreamingSample kvs-images-lab 600 ../samples aac notification
Producer端给视频帧打上STREAM_EVENT_TYPE_IMAGE_GENERATION 和STREAM_EVENT_TYPE_IMAGE_GENERATION两种标签,自动抽图并发送notification
./kvsAudioVideoStreamingSample kvs-images-lab 600 ../samples aac both
3.2.4 KVS Stream自动抽图结果
- s3 object key说明如下图所示:由如下字段组成:file-extension
1.ImagePrefix - Value of AWS_KINESISVIDEO_IMAGE_PREFIX.
2.AccountID - Account ID under which the stream is created.
3.StreamName - Name of the stream for which the image is generated.
4.ImageTimecode - Epoch timecode in the fragment at which the image is generated.
5.RandomID - Random GUID.
6.file-extension - JPG or PNG based on the Image format requested.
{
// KVS S3 object metadata
x-amz-meta-aws_kinesisvideo_fragment_number : 'string',
x-amz-meta-aws_kinesisvideo_producer_timestamp: 'number',
x-amz-meta-aws_kinesisvideo_server_timestamp: 'number',
// Optional key value pair sent as part of the MKV tags
custom_key_1: custom_value_1,
custom_key_2: custom_value_2,
}
您可以基于其中的aws_kinesisvideo_fragment_number、timestamp和Producer自定义tag来满足具体的业务场景,比如使用aws_kinesisvideo_fragment_number对kvs视频流进行定位回放等。
3.2.5 KVS Stream基于SNS的通知结果
{
"StreamArn": "your kvs stream arn",
"FragmentNumber": "91343852333182293998949405270547347888495435985",
"FragmentStartProducerTimestamp": 1653905243571,
"FragmentStartServerTimestamp": 1653905243687,
"NotificationType": "PERSISTED"
}
3.3 基于KVS GetImage抽图流程
GetImages是KVS最新推出的一个API,使用该API您可以采用完成托管的方式从存储在KVS Stream视频流中按照您期望的方式抽取图片。您可以将该图片用于机器学习推理,如对视频流进行人形、宠物、车辆等物体检测或者推送给最终用户进行预览。
3.3.1 KVS GetImages API说明
{
"StreamARN": "string", # KVS stream标识
"StreamName": "string",
"Format": "string", # 返回图片的格式 JPEG|PNG
"FormatConfig": {
"string": "string"
},
"HeightPixels": number, # 图片像素
"WidthPixels": number # 图片像素
"ImageSelectorType": "string", # PRODUCER_TIMESTAMP | SERVER_TIMESTAMP
"MaxResults": number, # 返回图片最大数量
"NextToken": "string",
"SamplingInterval": number, # 采样的时间间隔
"StartTimestamp": number, # 抽图的开始时间
"EndTimestamp": number, # 抽图的结束时间
}
{
"Images": [ # GetImages API 返回的图片集合
{
"Error": "string",
"ImageContent": "string", # 图片数据采用BASE64编码后的内容
"TimeStamp": number
}
],
"NextToken": "string"
}
3.3.1 KVS GetImages实验步骤
- 按照2.3 Cloud9模拟KVS Producer推送视频流到对应的KVS Stream
- 记录下上一步骤中KVS Producer推流中terminal中打印的时间
2022-05-31 14:00:33 DEBUG logStreamMetric(): Total elementary frame rate (fps): 25.000000
2022-05-31 14:00:33 DEBUG logStreamMetric(): Average API call retry count for client: 0.000000
2022-05-31 14:00:33 DEBUG postReadCallback(): Wrote 65524 bytes to Kinesis Video. Upload stream handle: 0
2022-05-31 14:00:33 DEBUG postReadCallback(): Wrote 39363 bytes to Kinesis Video. Upload stream handle: 0
2022-05-31 14:00:33 DEBUG postReadCallback(): Wrote 25886 bytes to Kinesis Video. Upload stream handle: 0
2022-05-31 14:00:33 DEBUG postWriteCallback(): Curl post body write function for stream with handle: kvs-images-lab and upload handle: 0 returned: {"EventType":"RECEIVED","FragmentTimecode":0,"FragmentNumber":"91343852333182358371831448110348590349566628324"}
2022-05-31 14:00:33 DEBUG postReadCallback(): Wrote 20922 bytes to Kinesis Video. Upload stream handle: 0
2022-05-31 14:00:33 DEBUG postWriteCallback(): Curl post body write function for stream with handle: kvs-images-lab and upload handle: 0 returned: {"EventType":"BUFFERING","FragmentTimecode":1800,"FragmentNumber":"91343852333182358376783208267490111901301663845"}
2022-05-31 14:00:33 DEBUG postReadCallback(): Wrote 17251 bytes to Kinesis Video. Upload stream handle: 0
2022-05-31 14:00:33 DEBUG postReadCallback(): Wrote 20494 bytes to Kinesis Video. Upload stream handle: 0
2022-05-31 14:00:33 DEBUG postReadCallback(): Wrote 709 bytes to Kinesis Video. Upload stream handle: 0
2022-05-31 14:00:33 DEBUG postWriteCallback(): Curl post body write function for stream with handle: kvs-images-lab and upload handle: 0 returned: {"EventType":"PERSISTED","FragmentTimecode":0,"FragmentNumber":"91343852333182358371831448110348590349566628324"}
- 如下图所示执行1.2 模拟KVS Consumer端环境准备的样例代码
核心代码说明:如下图是基于Python代码
def get_and_write_frame(args, kvs_am_client, timestamp, writer):
""" Fetch a frame at the timestamp and write it to the video writer """
try:
res = kvs_am_client.get_images(
StreamName=args.stream_name,
ImageSelectorType='SERVER_TIMESTAMP',
StartTimestamp=timestamp,
EndTimestamp=timestamp + datetime.timedelta(seconds=3),
SamplingInterval=3000,
Format='JPEG',
WidthPixels=args.width,
HeightPixels=args.height,
MaxResults=3,
)
except kvs_am_client.exceptions.ResourceNotFoundException as e:
print(f"{e} at {timestamp}")
return
for image in res["Images"]:
if "Error" not in image:
content = image["ImageContent"]
path = "/tmp/image.jpg"
print(f"Write a frame at {timestamp}")
with open(path, "wb") as fw:
fw.write(base64.b64decode(content))
cv2_image = cv2.imread(path)
writer.write(cv2_image)
return
print(f"Couldn't find a valid image frame at {timestamp}")
运行main.py,并传入封装好的参数
python3 main.py —stream-name your stream name
—start-time 2022-05-31T09:40:33 # 开始时间
—end-time 2022-05-31T09:42:19 # 结束时间
—duration 3 # 采用周期
—width 1920 —height 1080 # 图片分辨率
—output-path result1.mp4
- 观测KVS Images GetImages抽取图片,如下图所示Consumer端抽取图片成功
Couldn't find a valid image frame at 2022-05-31 09:40:33
Write a frame at 2022-05-31 09:40:35
Write a frame at 2022-05-31 09:40:37
Write a frame at 2022-05-31 09:40:39
Write a frame at 2022-05-31 09:40:41
Write a frame at 2022-05-31 09:40:43
Write a frame at 2022-05-31 09:40:45
Write a frame at 2022-05-31 09:40:47
Write a frame at 2022-05-31 09:40:49
4.结束语
在端到端的处理流程中,按照检测数据输入来源、输入数据格式、数据处理方案、智能检测方式这几个维度的可选的组合有如下几种技术方案可供选择。AWS提供的云服务能力可以很好的支持这些方案的实现。
媒体数据来源 |
媒体数据格式 |
媒体数据处理 |
智能检测技术 |
摄像头 |
Video |
不涉及 |
Rekognition Video(云端) |
自建模型(云端/设备端) |
Image |
抽图(端侧) |
Rekognition Image(云端) |
自建模型(云端/设备端) |
云端视频流(KVS) |
Video |
不涉及 |
Rekognition Image(云端) |
自建模型(云端) |
Image |
基于KVS GetMedia(云测) |
自建模型(云端) |
基于KVS Images(云测) |
Rekognition Image(云端) |
基于Rekognition Video Stream Events(云侧) |
Rekognition Video Stream Events(云端) |
部署位置 |
成本 |
时延 |
技术实现难度 |
说明 |
设备端 |
可控 |
低 |
高 |
需要自行实现模型部署、训练的工程化,无法借助云端的能力 |
云端 |
可控 |
中 |
低 |
可以自行选择Rekognition、Sagemaker、EC2自建降低开发与维护成本 |
数据格式 |
成本 |
技术实现难度 |
说明 |
Video |
高 |
低 |
无需数据格式的处理 |
Images |
可控 |
高 |
Video到Image格式的处理,自行管理视频处理程序包括解码和分辨率处理 |
云端抽图方式 |
成本 |
技术实现难度 |
智能检测对接 |
说明 |
KVS GetMedia |
可控 |
高 |
自建或托管 |
自行管理视频处理程序包括解码和分辨率处理 |
KVS GetImages |
可控 |
适中 |
自建或托管 |
只需要调用 KVS 相关API即可 |
Rekognition Video Stream Events |
可控 |
低 |
全托管 |
无需处理,AI场景支持有限 |
智能检测方案 |
成本 |
技术实现难度 |
AI场景支持 |
说明 |
Rekognition Video |
较高 |
适中 |
较为丰富 |
自行管理视频处理程序包括解码和分辨率处理 |
Rekognition Image |
可控 |
适中 |
较为丰富 |
只需要调用 KVS 相关API即可 |
Rekognition Video Stream Events |
可控 |
低 |
固定的几种 |
完全托管,AI场景支持有限 |
自建模型(云端) |
可控 |
高 |
可定制化AI场景 |
借助Sagemaker,EC2自建降低开发与维护成本 |
自建模型(设备端) |
可控 |
较高 |
可定制化AI场景 |
需要自行实现模型部署、训练的工程化,无法借助云端的能力 |
实际应用中您可以根据AI场景的复杂度、团队的技术储备、成本、项目交付周期这几个维度选择适合当前状况的方案。
5. 参考资料
Kinesis Video Streams Images 官方文档
https://docs.thinkwithwp.com/kinesisvideostreams/latest/dg/images.html
C语言版本的KVS Producer包含了KVS Images功能的样例代码
https://github.com/awslabs/amazon-kinesis-video-streams-producer-c
CPP语言版本的KVS Producer包含了KVS Images功能的样例代码
https://github.com/awslabs/amazon-kinesis-video-streams-producer-sdk-cpp
Python语言版本的KVS 包含了KVS Images功能的样例代码
https://github.com/arch-team/amazon-kinesis-video-streams-time-lapse-video-main
Python升级到Python3.7版本说明
https://www.itbulu.com/up-ubuntu-python37.html
本篇作者