手把手教程|基于 Amazon IoT Greengrass 端侧实时人脸检测

Amazon IoT Greengrass很容易部署在设备侧/网关侧,同时也提供良好的运行时环境,针对安防监控厂商Camera设备可以结合Amazon IoT Greengrass来实现边缘侧AI/ML场景。这里通过树莓派部署Amazon IoT Greengrass跑dlib库从摄像机实时视频流中抽取视频帧来实现人脸识别和比对。

准备工作

  • 一台树莓派设备,本方案采用RaspberryPi 4B ,CSI摄像头。

  • 将CSI摄像头处理为Raspbian OS能识别的设备,需开启V4l2 Module

  • 树莓派上安装python3运行环境

  • 安装Amazon IoT Greengrass,参考官方文档,这里创建名称为“raspberrypiGroup”组

  • 上传一张照片到树莓派指定目录下用于后续人脸比对。

架构图

创建存储桶

创建名称为”greengrass-detect-realtime-video”图片桶,区域选择”新加坡”

创建访问密钥

IAM服务中新建一个用户,选择编程访问,选择

选择创建策略,选择JSON,输入内容如下

 1{
 2    "Version": "2012-10-17",
 3    "Statement": [
 4        {
 5            "Effect": "Allow",
 6            "Action": "s3:ListAllMyBuckets",
 7            "Resource": "arn:aws:s3:::*"
 8        },
 9        {
10            "Effect": "Allow",
11            "Action": [
12                "s3:ListBucket",
13                "s3:GetBucketLocation"
14            ],
15            "Resource": "arn:aws:s3:::greengrass-detect-realtime-video"
16        },
17        {
18            "Effect": "Allow",
19            "Action": [
20                "s3:PutObject",
21                "s3:PutObjectAcl",
22                "s3:GetObject",
23                "s3:GetObjectAcl",
24                "s3:DeleteObject"
25            ],
26            "Resource": "arn:aws:s3:::greengrass-detect-realtime-video/*"
27        }
28    ]
29}

选择安全证书,创建访问密钥

下载保存密钥后,回到服务界面选择Amazon Secrets Manager服务,选择“存储新的密钥”,选择“其他类型的密钥”,密钥键/值新增1行,输入上面保存的密钥信息。密钥ID名称”access_key_id”,密钥名称“access_secret_key”。

输入密钥名称“greengrass-lambda-access-s3-secretkey”

创建Local Lambda函数

进入Amazon Lambda控制台,创建名称为 “local_face_detection” Lambda函数,选择运行时环境Python 3.7,导入Greengrass Core Python SDK. SDK下载地址:https://github.com/aws/aws-greengrass-core-sdk-python.

localFaceDetection.py主要代码实现

初始化Greengrass 客户端

1client = greengrasssdk.client('iot-data')

指定iot topic,face_recongnition用于上报人脸识别结果,recognition_failed用于识别错误日志

1iotTopic = 'face_recognition'
2
3errTopic = 'recognition_failed'

获取Secret Manager中存储的访问密钥,密钥内容写入secret

1get_secret()
2secret_json = json.loads(secret)
3#提取访问密钥ID
4access_key_id = secret_json['access_key_id']
5#提取访问密钥KEY
6access_secret_key = secret_json['access_secret_key']

初始化S3客户端

1clientS3 = boto3.client(
2    's3',
3    aws_access_key_id=access_key_id,
4    aws_secret_access_key=access_secret_key
5)

指定树莓派上传人脸图片的bucket名称

1bucket='greengrass-detect-realtime-video'

指定树莓派上进行人脸比对的基准照片,这个基准照需要提前上传到树莓派,比如:/home/pi/XXX.jpg,基准照也可以从S3下载,这里略过。

1filesUrl = ['<RASPBERRYPI_LOCAL_FACE_IMAGE>']

从Secrets Manager提取访问密钥

 1def get_secret():
 2    session = boto3.session.Session()
 3    client = session.client(
 4        service_name='secretsmanager',
 5        region_name=region_name
 6    )
 7    try:
 8        get_secret_value_response = client.get_secret_value(SecretId=secret_name)
 9    except ClientError as e:
10        print(e)
11    else:
12        if 'SecretString' in get_secret_value_response:
13            global secret
14            secret = get_secret_value_response['SecretString']
15        else:
16            decoded_binary_secret = base64.b64decode(get_secret_value_response['SecretBinary'])

从Camera设备或RTSP Proxy获取实时视频流,将视频帧写入队列,队列中始终保持留存1帧,丢弃队列中其他帧,这里主要解决消费视频帧过慢导致视频帧积压处理不及时。

 1def frame_input(q):
 2    cap = cv2.VideoCapture('/dev/video0')
 3    print("Raspberry Pi 4B - connected")
 4    while True:
 5        st = time.time()
 6        ret,frm = cap.read()
 7        if not(ret):
 8            cap.release()
 9            cap = cv2.VideoCapture('/dev/video0')
10            #cap = cv2.VideoCapture("rtsp://localhost:8554/unicast")
11            print("total time lost due to reinitialization : ",time.time()-st)
12            continue
13        q.put(frm)
14        if q.qsize() > 1:
15            for i in range(q.qsize()-1):
16                q.get()

定义线程从Camera获取实时视频流

 1class Frame_Thread(Thread):
 2    def __init__(self):
 3        ''' Constructor. '''
 4        Thread.__init__(self)
 5
 6    def run(self):
 7        print("start queue read frame")
 8        mp.set_start_method('fork',True)
 9        process = mp.Process(target=frame_input,args=(queue,))
10        process.daemon = True
11        process.start()

定义队列深度为4,启动线程读取视频帧

1queue = mp.Queue(maxsize=4)
2frame_thread=Frame_Thread()
3frame_thread.start()
4print("started read read-time video frame from src [camera device / rtsp server]")

提取基准照片的面部编码和文件路径的文件名key-value形式存入faces_dict中

 1def load_local_image(filesToLoad,newFile):
 2    global filesUrl
 3    global faces_dict
 4    for url in filesToLoad:
 5        img=scipy.misc.imread(url,mode='RGB')
 6        faces_dict.update({remove_file_ext(url):face_recognition.face_encodings(img)[0]})
 7        if(newFile):
 8            filesUrl.append(url)
 9        client.publish(topic=iotTopic, payload="images are loaded from local")
10
11load_local_image(filesUrl,0)

从队列queue中获取视频帧,resize ¼ ,颜色转换从BGR转RGB

 1frame = queue.get()
 2if frame is None:
 3    client.publish(topic=errTopic, payload="Failed to get frame from the stream")
 4    continue
 5else:
 6    # 为加速人脸识别处理这里将视频帧size缩小为原有1/4 
 7    small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)
 8    # 将图像从BGR颜色(OpenCV使用颜色)转换为RGB颜色(face_recognition使用颜色)
 9    rgb_small_frame = small_frame[:, :, ::-1]
10# 仅处理其他视频帧以节省时间

查找当前视频帧中的所有面部和面部编码,面部编码匹配人脸

 1face_locations = face_recognition.face_locations(rgb_small_frame)
 2face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations)
 3print('process this frame start:',len(face_locations),len(face_encodings))
 4face_names = []
 5for face_encoding in face_encodings:
 6    name = "Unknown"
 7    images_encodings = list(faces_dict.values())
 8    global dist
 9    dist = 0
10    #面部编码匹配人脸
11    match_result = face_recognition.compare_faces(images_encodings,face_encoding,tolerance=0.45)
12    for idx, match in enumerate(match_result):
13        if match:
14            image_encoding = images_encodings[idx]
15            dist = face_recognition.face_distance([image_encoding],face_encoding)[0]
16            dist = (1.0 - dist) * 100
17            print("name : {} face_recogniton dist value : {}".format(list(faces_dict.keys())[idx],dist))

如果dist>70 上传图片 & 上报识别结果

 1global jpeg
 2if dist > 70.0 :
 3    try:
 4        imgID = time.strftime("%Y%m%d%H%M%S")+str(random.randint(0,99))
 5        #将置信度>70的视频帧转成图片上传S3指定桶'greengrass-detect-realtime-video'
 6        s3Resp =clientS3.put_object(Bucket='greengrass-detect-realtime-video', Key=imgID+'.jpg', Body=jpeg.tobytes(), ACL="private")
 7        print(s3Resp)
 8        #上报人脸识别结果和识别图片名称
 9        msg = '{{"FaceName":"{0}","dist":"{1}","imageName":"{2}","time":"{3}","desc":"{4}"}}'.format(str(name),str(dist),(imgID+".jpg"),time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()),"Uploaded Rapsberry Pi face detection image.")
10        #上报IoT Core 人脸名称,置信度,S3图片名称,时间戳等
11        client.publish(topic=iotTopic, payload=msg)

local_face_detection.py的完整源代码可以从以下链接获取

https://github.com/beiyue/gg-realtime-face-recognition/blob/main/localFaceDetection.py

在local_face_detection函数console界面选择“操作”,选择“发布新版本”,这里版本号是37。选择“创建别名”,输入名称“prod”,选择版本37

Amazon Lambda添加Greengrass组

将函数local_face_detection添加Greengrass组“raspberrypiGroup”

选择上面别名”prod”

添加完成后,选择“编辑”:

  • 运行身份:使用默认组 (当前: ggc_user/ggc_group)

  • 容器化:Greengrass 容器 (始终)

  • 内存限制:512MB , 超时:默认3秒

  • Amazon Lambda 生命周期:使此函数长时间生存,保持其无限期运行

  • 对 /sys 目录的只读访问权限:启用

  • 输入负载数据类型:json

添加资源camera

  • 资源名称:Camera

  • 资源类型:设备

  • 设备路径:/dev/video0

  • 组拥有文件访问权限:自动添加拥有资源的 Linux 组的操作系统组权限

  • 为此 Amazon Lambda 函数选择权限:读写访问权限

添加资源tmp

  • 资源名称:tmp

  • 资源类型:卷

  • 源路径:/tmp 目的地路径: /tmp

  • 组拥有文件访问权限:自动添加拥有资源的 Linux 组的操作系统组权限

  • 为此 Amazon Lambda 函数选择权限:读写访问权限

创建Greengrass组角色

Identity and Access Management (IAM)控制台创建一个角色GreengrassRole,将策略AWSGreengrassResourceAccessRolePolicy添加到角色

选择“添加内联策略”

输入下面的策略

1{
2    "Version": "2012-10-17",
3    "Statement": {
4        "Effect": "Allow",
5        "Action": "secretsmanager:GetSecretValue",
6        "Resource": "*"
7    }
8}

输入策略名称GreengrassSecretValuePolicy

创建订阅

创建订阅界面,选择源为“local_face_detection”,选择目标“IoT Cloud”

主题筛选条件输入“#”

测试

测试界面选择订阅主题“face_recognition”

设备检测到人脸,从实时视频流获取frame生成图片推到S3。

从S3存储桶中可以看到设备传上来的图片

小结,本方案展示了树莓派系统上运行 Amazon IoT Greengrass 实现人脸检测功能。很多客户希望通过边缘侧实现AI/ML 场景可以结合Greengrass+Lambda来实现。权限部分可以选择Amazon Secret Manager来管理密钥,Amazon IoT Greengrass角色添加Amazon Secret Manager 访问权限后,设备可按需获取密钥从而避免本地硬编码。

参考链接

raspberrypiGroup:

https://ap-southeast-1.console.aws.amazon.com/iot/home?region=ap-southeast-1#/greengrass/groups/6806da7c-c732-4709-9870-03ae6ec66d21

Secrets Manager:

https://ap-southeast-1.console.aws.amazon.com/secretsmanager/home?region=ap-southeast-1

raspberrypiGroup:

https://ap-southeast-1.console.aws.amazon.com/iot/home?region=ap-southeast-1#/greengrass/groups/6806da7c-c732-4709-9870-03ae6ec66d21

本篇作者

周晓明

亚马逊云科技GCR解决方案架构师。

听说,点完下面4个按钮

就不会碰到bug了!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值