基于Aidlux平台实现ONNX Runtime部署-水果分类-摄像头和视频

基于Aidlux平台的人工智能开发部署全流程

第一步:

连接Aidlux后,使用jupyter notebook --allow-root进行Aidlux平台联系的jupyter notebook安装配置环境:

1.安装ONNX、ONNX Runtime

!pip install onnx onnxruntime

2.安装其他第三方工具包

!pip install protobuf==3.20.1

3.下载中文字体文件

!wget https://zihao-openmmlab.obs.cn-east-3.myhuaweicloud.com/20220716-mmclassification/dataset/SimHei.ttf

4.验证安装配置成功

import torch print('PyTorch版本', torch.__version__)

import onnxprint('ONNX版本', onnx.__version__)

import onnxruntime as ortprint('ONNX Runtime版本', ort.__version__)

第二步:

准备ONNX模型文件:

!wget https://zihao-tutorial.obs.cn-east-3.myhuaweicloud.com/aidlux/ckpt/resnet18_imagenet.onnx

!wget https://zihao-tutorial.obs.cn-east-3.myhuaweicloud.com/aidlux/ckpt/resnet18_fruit30.onnx

resnet18_imagenet.onnx:PyTorch官方预训练模型-ImageNet1000类图像分类模型 转ONNX

resnet18_fruit30.onnx:自己训练得到的30类水果图像分类模型 转ONNX

第三步:

水果图像分类素材准备:

上传自己要测试的图像和视频。

下载类别ID和类别名称对应文件:

!wget https://zihao-openmmlab.obs.cn-east-3.myhuaweicloud.com/20220716-mmclassification/dataset/fruit30/idx_to_label

第四步:

使用ONNX Runtime 推理引擎,载入自己训练得到的图像分类 onnx 模型,预测摄像头实时画面。

具体代码如下:

##导入工具包

importonnxruntime

importtorchfromtorchvision importtransformsimporttorch.nn.functional asF

importpandas aspdimportnumpy asnp

fromcvs import *fromPIL importImage, ImageFont, ImageDraw

importmatplotlib.pyplot asplt%matplotlibinline

# 导入中文字体,指定字号

font =ImageFont.truetype('SimHei.ttf', 32)

# 载入ONNX模型,获取ONNX Runtime推理器

ort_session =onnxruntime.InferenceSession('resnet18_fruit30.onnx')

# 载入类别和ID对应字典

idx_to_labels =np.load('idx_to_labels.npy', allow_pickle=True).item()

# 图像预处理

# 测试集图像预处理-RCTN:缩放裁剪、转 Tensor、归一化test_transform =transforms.Compose([transforms.Resize(256),

transforms.CenterCrop(256),

transforms.ToTensor(),

transforms.Normalize(

mean=[0.485, 0.456, 0.406],

std=[0.229, 0.224, 0.225])

])

# 初始化摄像头

# 摄像头ID 0-后置 1-前置

Camera_ID =0

cap =cvs.VideoCapture(Camera_ID)

 

# 调用摄像头获取一帧画面

img_bgr = cap.read()

img_bgr.shape

plt.imshow(img_bgr[:,:,::-1])

plt.show()

#画面转成RGB 的 Pillow 格式

img_bgr.shape

img_rgb =cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB) # BGR转RGB

img_pil =Image.fromarray(img_rgb)


#预处理

input_img =test_transform(img_pil)

input_tensor =input_img.unsqueeze(0).numpy()

#ONNX Runtime预测

# onnx runtime 输入

ort_inputs ={'input': input_tensor}

# onnx runtime 输出

pred_logits =ort_session.run(['output'], ort_inputs)[0]

pred_logits =torch.tensor(pred_logits)

 

pred_softmax =F.softmax(pred_logits, dim=1) # 对 logit 分数做 softmax 运算

pred_softmax.shape

#解析top-n预测结果的类别和置信度

n =3top_n =torch.topk(pred_softmax, n) # 取置信度最大的 n 个结果pred_ids =top_n[1].cpu().detach().numpy().squeeze() # 解析出类别

confs =top_n[0].cpu().detach().numpy().squeeze() # 解析出置信度

#在图像上写中文

draw =ImageDraw.Draw(img_pil) # 在图像上写字

fori inrange(len(confs)):

pred_class =idx_to_labels[pred_ids[i]]

text ='{:<8} {:>.2f}'.format(pred_class, confs[i])

    # 文字坐标,中文字符串,字体,rgba颜色

draw.text((50, 100 +50 *i), text, font=font, fill=(255, 0, 0, 1))

img =np.array(img_pil) # PIL 转 array

plt.imshow(img)

plt.show()

#处理单帧画面的函数

# 处理帧函数

defprocess_frame(img):        '''    输入摄像头拍摄画面bgr-array,输出图像分类预测结果bgr-array    '''


    # 记录该帧开始处理的时间

start_time =time.time()


    ## 画面转成 RGB 的 Pillow 格式

img_rgb =cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # BGR转RGB

img_pil =Image.fromarray(img_rgb) # array 转 PIL


    ## 预处理

input_img =test_transform(img_pil) # 预处理

input_tensor =input_img.unsqueeze(0).numpy()


    ## onnx runtime 预测

ort_inputs ={'input': input_tensor} # onnx runtime 输入

pred_logits =ort_session.run(['output'], ort_inputs)[0] # onnx runtime 输出

pred_logits =torch.tensor(pred_logits)

pred_softmax =F.softmax(pred_logits, dim=1) # 对 logit 分数做 softmax 运算


    ## 解析top-n预测结果的类别和置信度

n =3

top_n =torch.topk(pred_softmax, n) # 取置信度最大的 n 个结果

pred_ids =top_n[1].cpu().detach().numpy().squeeze() # 解析出类别

confs =top_n[0].cpu().detach().numpy().squeeze() # 解析出置信度


    ## 在图像上写中文

draw =ImageDraw.Draw(img_pil)

    fori inrange(len(confs)):

pred_class =idx_to_labels[pred_ids[i]]

text ='{:<8} {:>.2f}'.format(pred_class, confs[i])

        # 文字坐标,中文字符串,字体,rgba颜色

draw.text((50, 100 +50 *i), text, font=font, fill=(255, 0, 0, 1))

img =np.array(img_pil) # PIL 转 array

img =cv2.cvtColor(img, cv2.COLOR_RGB2BGR) # RGB转BGR


    # 记录该帧处理完毕的时间

end_time =time.time()

    # 计算每秒处理图像帧数FPS

FPS =1/(end_time -start_time)  

    # 图片,添加的文字,左上角坐标,字体,字体大小,颜色,线宽,线型

img =cv2.putText(img, 'FPS  '+str(int(FPS)), (50, 80), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 255), 4, cv2.LINE_AA)

    returnimg

#逐帧实时处理手机摄像头拍摄的画面

while True:

img_bgr =cap.read()


    ifimg_bgr is None:

        continue


img_bgr =process_frame(img_bgr)


cvs.imshow(img_bgr)

 

#视频逐帧处理

importcv2importnumpy asnpimporttimefromtqdm importtqdm

# 视频逐帧处理代码模板# 不需修改任何代码,只需定义process_frame函数即可# 同济子豪兄 2021-7-10

defgenerate_video(input_path='videos/robot.mp4'):

filehead =input_path.split('/')[-1]

output_path ="out-" +filehead


print('视频开始处理',input_path)


    # 获取视频总帧数

cap =cv2.VideoCapture(input_path)

frame_count =0

    while(cap.isOpened()):

success, frame =cap.read()

frame_count +=1

        if notsuccess:

            break

cap.release()

print('视频总帧数为',frame_count)


    # cv2.namedWindow('Crack Detection and Measurement Video Processing')

cap =cv2.VideoCapture(input_path)

frame_size =(cap.get(cv2.CAP_PROP_FRAME_WIDTH), cap.get(cv2.CAP_PROP_FRAME_HEIGHT))


    # fourcc = int(cap.get(cv2.CAP_PROP_FOURCC))

    # fourcc = cv2.VideoWriter_fourcc(*'XVID')

fourcc =cv2.VideoWriter_fourcc(*'mp4v')

fps =cap.get(cv2.CAP_PROP_FPS)


out =cv2.VideoWriter(output_path, fourcc, fps, (int(frame_size[0]), int(frame_size[1])))


    # 进度条绑定视频总帧数

    withtqdm(total=frame_count-1) aspbar:

        try:

            while(cap.isOpened()):

success, frame =cap.read()

                if notsuccess:

                    break


                # 处理帧

                # frame_path = './temp_frame.png'

                # cv2.imwrite(frame_path, frame)

                try:

frame =process_frame(frame)

                except:

print('报错!', error)

                    pass


                ifsuccess == True:

                    # cv2.imshow('Video Processing', frame)

out.write(frame)


                    # 进度条更新一帧

pbar.update(1)


                # if cv2.waitKey(1) & 0xFF == ord('q'):

                    # break

        except:

print('中途中断')

            pass


cv2.destroyAllWindows()

out.release()

cap.release()

print('视频已保存', output_path)

generate_video(input_path='fruits_video.mp4')

个人体会:

笔者是在Aidlux团队以及B站up主张子豪老师的训练营中学习而来,期间张子豪老师区别以往的视频课,以一种更加直观的方式展现出整个项目的流程与细节。不管是AI算法小白还是AI算法的老手都在这次训练营受益匪浅。Aidlux工程实践内容全是干货,同时过程也遇见了很多问题,但是张子豪老师和训练营的其他同学们都很认真为其他学员解决,耐心辅导,对我来言,刚刚接触这一领域,以及Aidlux平台的使用,让我耳目一新。整个流程下,我已经学会了如何在Aidlux进行ONNX Runtime模型部署,令我也感觉到成就感,在此特别感谢张子豪老师和Aidlux团队的贡献,希望他们以后在AI算法开发的道路事业更加顺利。

最后放上本次基于Aidlux平台实现ONNX Runtime部署-水果分类-摄像头和视频的效果视频的地址。

基于Aidlux平台实现ONNX Runtime部署-水果分类-摄像头实时:https://www.bilibili.com/video/BV1UX4y1L76H/?vd_source=d3b09cd0849dbba42c427a4dccbd3c54

基于Aidlux平台实现ONNX Runtime部署-水果分类-视频解析:https://www.bilibili.com/video/BV1HX4y1L7B4/?vd_source=d3b09cd0849dbba42c427a4dccbd3c54

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容