高通手机跑AI系列之——实时头发识别

伊利丹~怒风
企业官方账号
2025-06-14 12:02:55

 环境准备

手机

测试手机型号:Redmi K60 Pro

处理器:第二代骁龙8移动--8gen2

运行内存:8.0GB ,LPDDR5X-8400,67.0 GB/s

摄像头:前置16MP+后置50MP+8MP+2MP

AI算力:NPU 48Tops INT8 && GPU 1536ALU x 2 x 680MHz = 2.089 TFLOPS

软件

APP:AidLux2.0

系统环境:Ubuntu 20.04.3 LTS

提示:AidLux登录后代码运行更流畅,在代码运行时保持AidLux APP在前台运行,避免代码运行过程中被系统回收进程,另外屏幕保持常亮,一般息屏后一段时间,手机系统会进入休眠状态,如需长驻后台需要给APP权限。

算法Demo

Demo代码介绍

主要功能

这段代码实现了一个实时人物分割应用,主要功能包括:

  1. 摄像头初始化与管理

    • 支持自动检测和选择 USB 摄像头
    • 提供备用方案,在无 USB 摄像头时使用设备内置摄像头
    • 处理摄像头打开失败的情况并进行重试
  2. AI 模型加载与配置

    • 使用 aidlite 框架加载轻量级神经网络模型
    • 配置模型输入输出格式和加速选项(GPU)
    • 初始化模型解释器并准备进行推理
  3. 实时图像处理流程

    • 捕获摄像头视频帧
    • 图像预处理(调整大小、颜色空间转换)
    • 模型推理,获取前景和背景分割结果
    • 后处理生成二值掩码
    • 将掩码与原始图像叠加显示
  4. 性能监控

    • 记录并打印各个处理阶段的耗时
    • 计算总处理时间,评估系统性能

这个应用可以用于简单的实时背景替换、虚拟试衣、视频会议中的背景虚化等场景。通过调整掩码生成算法和叠加方式,可以获得更丰富的视觉效果。

Aidlite 框架

Aidlite 框架 是一个用于模型推理的框架,而非具体模型。它提供了模型加载、加速和执行的功能。

框架功能:

• 模型管理:创建实例、设置输入输出格式

• 硬件加速:支持 CPU/GPU/NPU 等多种后端

• 张量操作:输入数据传递、输出结果获取

OpenCV 计算机视觉功能

代码中使用了 OpenCV 的图像处理功能(如cv2.resizecv2.addWeighted),但这些属于传统计算机视觉算法,并非 AI 模型。

关键功能

  • 图像预处理:调整尺寸、颜色空间转换
  • 图像合成:将分割掩码与原始图像叠加
  • 视频处理:摄像头捕获、帧显示

总结

代码中实际使用的 AI 模型只有1 个segmentation.tnnmodel),用于人物分割。另外两个组件是:

  • Aidlite 框架:负责模型推理的执行环境
  • OpenCV 库:提供传统计算机视觉处理功能

这种架构体现了典型的 AI 应用模式:AI 模型负责核心任务(分割),传统算法负责前后处理(图像调整、结果可视化)

 

AI模型介绍

这段代码中的模型是一个轻量级的图像分割模型,专门用于实时人物与背景的分离。下面从模型架构、功能和应用场景三个方面进行详细分析:

1. 模型架构

根据代码中的参数配置,可以推测该模型的特点:

  • 输入要求

    • 输入尺寸为 256×256×3(RGB 图像)
    • 数据类型为 uint8(0-255 像素值)
    • 需将 BGR 格式转为 RGB(符合大多数深度学习模型的输入要求)
  • 输出结构

    • 两个并行输出张量,形状均为 256×256
    • 数据类型为 float32(浮点数值)
    • 结合后处理代码,推测两个输出分别对应:
      • pred_0:背景分割概率图
      • pred_1:前景(人物)分割概率图
  • 模型格式

    • 使用 .tnnmodel 格式,表明基于 TNN(Tencent Neural Network)框架优化
    • 适合移动端或边缘设备部署(如 Aidlux 平台)

2. 应用场景

基于人物分割功能,该模型可用于:

• 视频会议:背景虚化、虚拟背景替换

• 直播与短视频:绿幕抠像替代方案

• AR 试衣 / 美妆:实时叠加虚拟服装或妆容

• 安防监控:人物检测与跟踪的预处理步骤

 3. 性能与限制

•  优势:

◦ 实时性强:单帧处理时间约几十毫秒(取决于设备性能)

◦ 资源占用低:轻量级模型适合嵌入式设备运行

◦ 效果自然:能处理复杂场景(如头发、透明物体)  

•  局限性:

◦ 依赖光照条件:强光或弱光环境可能降低分割精度

◦ 边界细节不足:在复杂边缘(如薄纱、眼镜)可能出现锯齿

◦ 仅支持单人物:多人物场景可能需要额外的实例分割模型

Demo代码

import cv2
import time
from time import sleep
import subprocess
import remi
import sys
import numpy as np
import aidlite
import os

# 获取USB摄像头ID函数
def get_cap_id():
    try:
        # 执行shell命令获取所有USB视频设备的ID
        cmd = "ls -l /sys/class/video4linux | awk -F ' -> ' '/usb/{sub(/.*video/, \"\", $2); print $2}'"
        result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
        output = result.stdout.strip().split()

        # 将设备ID转换为整数并返回最小值(优先使用第一个检测到的USB摄像头)
        video_numbers = list(map(int, output))
        if video_numbers:
            return min(video_numbers)
        else:
            return None
    except Exception as e:
        print(f"获取摄像头ID时出错: {e}")
        return None

# 图像合成函数:将分割掩码与原始图像叠加
def transfer(image, mask):
    # 调整掩码大小与原始图像一致
    mask = cv2.resize(mask, (image.shape[1], image.shape[0]))
    # 创建与原始图像相同尺寸的三通道掩码
    mask_n = np.zeros_like(image)
    mask_n[:, :, 0] = mask  # 将掩码值赋给蓝色通道

    # 设置透明度参数
    alpha = 0.7  # 原始图像透明度
    beta = (1.0 - alpha)  # 掩码图像透明度
    # 加权叠加原始图像和掩码图像
    dst = cv2.addWeighted(image, alpha, mask_n, beta, 0.0)
    return dst

# 模型输入输出参数配置
w = 256  # 模型输入宽度
h = 256  # 模型输入高度

# 定义模型输入输出形状
inShape = [[1, w, h, 3]]  # 输入: 1张RGB图像,尺寸256x256
outShape = [[1, w, h], [1, w, h]]  # 输出: 两个256x256的分割图
model_path = "models/segmentation.tnnmodel"  # 模型文件路径

# 加载模型
model = aidlite.Model.create_instance(model_path)
if model is None:
    print("模型创建失败!")

# 设置模型属性:输入为uint8类型,输出为float32类型
model.set_model_properties(inShape, aidlite.DataType.TYPE_UINT8, outShape, aidlite.DataType.TYPE_FLOAT32)

# 配置模型加速类型为GPU
config = aidlite.Config.create_instance()
config.accelerate_type = aidlite.AccelerateType.TYPE_GPU

# 构建并初始化模型解释器
fast_interpreter = aidlite.InterpreterBuilder.build_interpretper_from_model_and_config(model, config)
if fast_interpreter is None:
    print("解释器创建失败!")
result = fast_interpreter.init()
if result != 0:
    print("解释器初始化失败!")
result = fast_interpreter.load_model()
if result != 0:
    print("模型加载失败!")
print("模型加载成功!")

# 设备类型和摄像头ID配置
aidlux_type = "basic"
# 0-后置摄像头,1-前置摄像头
camId = 1
opened = False

# 尝试打开摄像头,失败则重试
while not opened:
    if aidlux_type == "basic":
        # 基本设备使用MIPI接口打开前置摄像头
        cap = cv2.VideoCapture(camId, device='mipi')
    else:
        # 其他设备优先使用USB摄像头
        capId = get_cap_id()
        print("USB摄像头ID: ", capId)
        if capId is None:
            print("未找到USB摄像头")
            # 默认使用前置摄像头
            cap = cv2.VideoCapture(1, device='mipi')
        else:
            camId = capId
            cap = cv2.VideoCapture(camId)
            # 设置视频编码格式为MJPG
            cap.set(6, cv2.VideoWriter.fourcc('M', 'J', 'P', 'G'))
    
    # 检查摄像头是否成功打开
    if cap.isOpened():
        opened = True
    else:
        print("摄像头打开失败")
        cap.release()  # 释放摄像头资源
        time.sleep(0.5)  # 等待0.5秒后重试

# 主循环:实时捕获、处理和显示视频
while True:
    # 读取一帧图像
    ret, frame = cap.read()
    if not ret:
        continue  # 读取失败则跳过当前帧
    if frame is None:
        continue  # 空帧则跳过
    
    # 如果使用前置摄像头,水平翻转图像以获得镜像效果
    if camId == 1:
        frame = cv2.flip(frame, 1)
    
    # 记录处理时间点
    t0 = time.time()
    
    # 图像预处理
    img = cv2.resize(frame, (w, w))  # 调整图像大小为模型输入尺寸
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # 转换颜色空间从BGR到RGB
    
    t1 = time.time()
    print('tnn: 开始设置输入')
    
    # 将预处理后的图像数据传入模型
    result = fast_interpreter.set_input_tensor(0, img.data)
    print(result)
    if result != 0:
        print("设置输入张量失败")
    
    t2 = time.time()
    print('tnn: 开始推理')
    
    # 执行模型推理
    result = fast_interpreter.invoke()
    if result != 0:
        print("模型推理失败")
    
    t3 = time.time()
    
    # 获取模型输出结果
    pred_1 = fast_interpreter.get_output_tensor(1)
    if pred_1 is None:
        print("获取输出张量1失败!")
    
    pred_0 = fast_interpreter.get_output_tensor(0)
    if pred_0 is None:
        print("获取输出张量0失败!")
    
    print('预测结果形状:', pred_0.shape, pred_1.shape)
    t4 = time.time()
    
    # 重塑输出张量为二维数组
    pred0 = (pred_0).reshape(w, h)
    pred1 = (pred_1).reshape(w, h)
    
    # 提取背景和前景预测结果
    back = ((pred0)).copy()
    front = ((pred1)).copy()
    t5 = time.time()
    
    # 计算前景掩码:前景分数减去背景分数
    mask = front - back
    print('掩码值范围:', mask)
    
    # 二值化掩码:大于0的区域为前景(255),小于等于0的区域为背景(0)
    mask[mask > 0] = 255
    mask[mask <= 0] = 0
    
    # 将掩码与原始图像叠加
    dst = transfer(frame, mask)
    
    # 打印各处理阶段耗时
    print('预处理耗时:%f===设置输入耗时:%f===推理耗时:%f===获取输出耗时:%f===后处理耗时:%f' % (
        t1 - t0, t2 - t1, t3 - t2, t4 - t3, t5 - t4))
    print('总耗时', t5 - t0)
    
    # 显示处理结果
    cv2.imshow("", dst)
    
    # 按ESC键退出程序
    key = cv2.waitKey(1)
    if key == 27:  # ESC键
        break

# 释放资源
cap.release()
cv2.destroyAllWindows()

模型位置

/opt/aidlux/app/aid-examples/hair_seg

模型效果 

...全文
37 回复 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

2,852

社区成员

发帖
与我相关
我的任务
社区描述
本论坛以AI、WoS 、XR、IoT、Auto、生成式AI等核心板块组成,为开发者提供便捷及高效的学习和交流平台。 高通开发者专区主页:https://qualcomm.csdn.net/
人工智能物联网机器学习 技术论坛(原bbs) 北京·东城区
社区管理员
  • csdnsqst0050
  • chipseeker
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧