本专栏主要是提供一种国产化图像识别的解决方案,专栏中实现了YOLOv5/v8在国产化芯片上的使用部署,并可以实现网页端实时查看。根据自己的具体需求可以直接产品化部署使用。
B站配套视频:https://www.bilibili.com/video/BV1or421T74f
基础背景
对于国产化芯片来说,是采用NPU进行推理,无论从性能、功耗、软件环境来说都是比不过英伟达显卡的。所以在进行推理的时候除了实现我们正常的业务逻辑还需要将核心推理部分改造成线程池,实现快速推理。
在此之前我们大概知道推理需要分成三个部分,预处理、推理、后处理。此处我们参照上节课的代码、官方模型来和大家讲解。
预处理部分
首先我们看一下模型的输入部分,是640640,这个是在我们训练的时候就决定好了,所以进行推理的时候我们也一样先要把图片处理成640640。
除此之外,使用过opencv的同学应该知道,opencv读取图片时候一半都是BGR的颜色通道,预处理的时候我们一样要把图片处理成RGB才可以。
// yolo的预处理
void cvimg2tensor(const cv::Mat &img, uint32_t width, uint32_t height, tensor_data_s &tensor)
{
// img has to be 3 channels
if (img.channels() != 3)
{
NN_LOG_ERROR("img has to be 3 channels");
exit(-1);
}
// BGR to RGB
cv::Mat img_rgb;
cv::cvtColor(img, img_rgb, cv::COLOR_BGR2RGB);
// resize img
cv::Mat img_resized;
NN_LOG_DEBUG("img size: %d, %d", img.cols, img.rows);
NN_LOG_DEBUG("resize to: %d, %d", width, height);
cv::resize(img_rgb, img_resized, cv::Size(width, height), 0, 0, cv::INTER_LINEAR);
// BGR to RGB
memcpy(tensor.data, img_rgb.data, tensor.attr.size);
}
此处有一个小知识点,opencv的cv::resize是将图片进行强制拉伸,也就是图片中的元素都会变形。其实还有别的预处理方法,比如将图片扩充到640*640大小,然后多余部分进行黑色填充,一样可以实现效果,而且识别结果较好,下面就是实例代码。
LetterBoxInfo letterbox(const cv::Mat &img, cv::Mat &img_letterbox, float wh_ratio)
{
// img has to be 3 channels
if (img.channels() != 3)
{
NN_LOG_ERROR("img has to be 3 channels");
exit(-1);
}
float img_width = img.cols;
float img_height = img.rows;
int letterbox_width = 0;
int letterbox_height = 0;
LetterBoxInfo info;
int padding_hor = 0;
int padding_ver = 0;
if (img_width / img_height > wh_ratio)
{
info.hor = false;
letterbox_width = img_width;
letterbox_height = img_width / wh_ratio;
info.pad = (letterbox_height - img_height) / 2.f;
padding_hor = 0;
padding_ver = info.pad;
}
else
{
info.hor = true;
letterbox_width = img_height * wh_ratio;
letterbox_height = img_height;
info.pad = (letterbox_width - img_width) / 2.f;
padding_hor = info.pad;
padding_ver = 0;
}
// 使用cv::copyMakeBorder函数进行填充边界
cv::copyMakeBorder(img, img_letterbox, padding_ver, padding_ver, padding_hor, padding_hor, cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0));
return info;
}
推理部分
yolo的推理部分官方已经帮我进行了较好的封装,此处我们继续沿用就好,由于是调用底层的API,外部封装代码我们就不过多说明了。感兴趣的朋友可以看视频,其中我们会简单过一下。
后处理部分
模型在推理的时候会图片拆分成三个大小去识别,8080、4040、20*20,然后通过极大值抑制,将识别的结果计算出来。我们可以从模型里面看到模型里面输出了这三个部分。
但是这部分的计算处理其实在NPU中的速度并不快,我们会对模型进行修改,然后将后处理部分放到CPU中进行运算,图中就是我们修改之后的模型样子。具体处理方式官方也已经给出我们不做过多描述,关于模型如何修改,我们会在小节课的训练导出和大家说。
多线程处理
虽然进行了模型的裁剪和量化,但是国产嵌入式芯片毕竟起步较晚,受限于性能,对于1080P的视频来说可能推理速度只能每秒2-5帧左右,对于这种新能是远远无法达到产品使用要求的,所以我们需要进行多线程处理,让更多的线程去参与到推理过程中,提高整体性能效率。
更多内容查看视频>>>>>>>>>>>>>>>>> https://www.bilibili.com/video/BV1or421T74f](https://www.bilibili.com/video/BV1or421T74f
多媒体流处理
此处我们多媒体流处理使用的是zlmediakit,这是一款国人开发的流媒体服务器,也提供了相关C++的接口,几乎所有做流媒体的项目都会使用到,但是关于它C++的使用会有所不同需要另外学习一下。
更多内容查看视频>>>>>>>>>>>>>>>>> https://www.bilibili.com/video/BV1or421T74f](https://www.bilibili.com/video/BV1or421T74f