手把手玩转 MP4 文件人脸检测

Viewed 12

问题描述


用 K230 处理 MP4 视频时,想加实时人脸检测却卡壳?最新适配的 MP4 人脸检测 Demo 来了 —— 手把手教你从文件读取到视频解码,再到人脸框叠加,跑通全流程,零基础也能让 MP4 视频 “认出” 人脸!

一、硬件环境

K230 开发板

软件环境

1、K230 最新固件包

获取地址:
https://kendryte-download.canaan-creative.com/developer/releases/canmv_k230_micropython/daily_build/

2、demo 代码地址
\CanMV\sdcard\examples\21-AI-With-Others\face_detect_yunet_from_mp4.py

整体流程框架

image.png

在 K230 的 MP4 人脸检测 Demo 里,需 5 个 “专业工位” 无缝协作,把数据从 “打包状态” 逐步处理成可检测、可显示的效果:

  1. MP4解复用:拆 MP4 “快递箱”,分离出 H264/H265 视频流,为后续解码铺路;
  2. VDEC(视频解码器):解压视频流,输出 YUV420SP 格式的原始图像数据;
  3. CSC(色彩空间转换):当 “格式转换器”,把 YUV420SP 转成 RGB888P,适配人脸模型输入;
  4. KPU(AI 推理模块):当 “检测大脑”,对 RGB 图像做 AI 推理,输出人脸框坐标;
  5. DISPLAY(显示模块):叠加 YUV 视频画面和人脸框,呈现带人脸框的画面。5个模块环环相扣,既保视频流畅,又让 AI 检测不卡顿,全程像条高效的 “数据处理流水线”!

代码小诀窍

1. 各个模块之间连接最好使用 bind 模式

//VDEC与DISPLAY之间bind
bind_info = vdec.bind_info(width=video_info.width, height=video_info.height,chn=vdec.get_vdec_channel())
Display.bind_layer(**bind_info, layer = Display.LAYER_VIDEO1)

//VDEC与CSC模块之间bind
vdec_link = MediaManager.link((VIDEO_DECODE_MOD_ID, VDEC_DEV_ID, vdec.get_vdec_channel()), (NONAI_2D_CSC_MOD_ID, 0, 2))

bind之后,VDEC 的数据会直接送到 Display 和 CSC 模块,不需要应用层取数据再送到下一个模块,有效减少数据拷贝次数。

同时,VDEC 可以与 Display 和 VDEC 模块绑定。

2. 不同模块间的通信数据格式需要匹配才能正常工作

CSC模块就是用于这个用途,比方说 AI 需要的输入格式是 RGB888P,我们可以选择用 CSC 或者AI2D 进行格式转换。

  • Display 用的是 YUV420 的数据,所以用 CSC 直接转成 RGB888p 送给 AI,减少一次格式转换
  • CSC 输出的数据需要转换成 AI 使用的 numpy,并根据 AI 输入的需要 reshape
img = vf.to_image()
img_np_hwc = img.to_numpy_ref()
shape = img_np_hwc.shape
img_np_nhwc=img_np_hwc.reshape((1,shape[0],shape[1],shape[2]))

3.如何优化速度

  • 考虑跳帧检测,比方说两帧检测一帧
//每两帧检测一帧
count += 1
if count % 2 ==0:
    vf = vf_info.v_frame
    img = vf.to_image()
    img_np_hwc = img.to_numpy_ref()
    shape = img_np_hwc.shape
    img_np_nhwc=img_np_hwc.reshape((1,shape[0],shape[1],shape[2]))
    res = face_det.run(img_np_nhwc)
    csc.releaseframe(vf_info)
    osd_img.clear()
    face_det.draw_result(osd_img, res)   # 绘制结果
    Display.show_image(osd_img)
else:
    csc.releaseframe(vf_info)
    time.sleep_ms(10)
  • 输入的码流缩小分辨率,图片越大,检测速度越慢
  • 模型优化,尽量轻量化模型

4. 注意资源的释放和线程退出

  • 这里设置了两个地方退出线程:文件播放到结尾和用户主动点击退出

     while (main_thread_flag):
          try:
              frame_data =  k_mp4_frame_data_s()
              ret = kd_mp4_get_frame(mp4_handle.value, frame_data)
              if (ret < 0):
                  raise OSError("get frame data failed")
              #文件播放到结尾,退出两个线程
              if (frame_data.eof):
                  sub_thread_flag = False
                  main_thread_flag = False
                  raise OSError("get frame data failed")
              。。。。
          except KeyboardInterrupt as e:
              print("user stop: ", e)
          except BaseException as e:
              print(f"Exception {e}")
              #退出两个线程
              sub_thread_flag = False
              main_thread_flag = False
              time.sleep_ms(100)
              #资源释放
              face_det.deinit()
              kd_mp4_destroy(mp4_handle.value)
              vdec.stop()
              vdec.destroy()
              Display.deinit()
              csc.destroy()
              time.sleep_ms(200)
              MediaManager.deinit()
              print("release end")
    

    5. debug方法分享

  • IDE log输出

在代码中增加 print,输出各种需要的变量信息

if (track_info.track_type == K_MP4_STREAM_VIDEO):
    if (track_info.video_info.codec_id == K_MP4_CODEC_ID_H264 or track_info.video_info.codec_id == K_MP4_CODEC_ID_H265):
        video_track = True
        video_info = track_info.video_info
        print("    codec_id: ", video_info.codec_id)
        print("    track_id: ", video_info.track_id)
        print("    width: ", video_info.width)
        print("    height: ", video_info.height)
    else:
        print("video not support codecid:",track_info.video_info.codec_id)
  • 连接串口,查看串口 log 信息

    image.png

    查看串口信息(波特率115200)

    image.png

  • 后台运行 micropython,使用各种命令 debug 目前情况

在串口按 ctrl+C 退出 micropython ,改成后台运行。

#按ctrl+C退出micropython
[mpy] enter repl

^C[mpy] exit, reset
<3>[4] [Func]:vb_do_exit [Line]:1569 [Info]:vb already exited!

#后台运行micropython
msh />cd /sdcard/
msh /sdcard>micropython &
msh /sdcard>CanMV K230 start in 349970133 us
IDE debugger built Oct 27202509:55:21
[mpy] enter repl

#可以在运行的时候输入各种命令查看后台信息
msh /sdcard>cat /proc/umap/vb
-----VB PUB CONFIG--------------------------------------------------------------
MaxPoolCnt
         0
-----VB SUPPLEMENT ATTR---------------------------------------------------------
Config  Size    VbCnt
0       0       0

参考文献

官网API文档参考:
https://www.kendryte.com/k230_canmv/zh/main/index.html

配套视频教程:
https://www.bilibili.com/video/BV1Ke1nBSEic

快来试试吧!

1 Answers

文章已同步发表在嘉楠开发者微信公众号上面