RK3568-USB摄像头实时AI物品识别

这篇具有很好参考价值的文章主要介绍了RK3568-USB摄像头实时AI物品识别。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

RK3568具有1TOPS算力的NPU,可以在板子上进行AI计算。飞凌OK3568板子资料中自带了一些AI识别的例子,但只是对一张图片进行识别,且需要单独使用图片查看工具查看识别结果。

为了更直观的体验RK3568的AI算力,将AI识别例程与摄像头功能结合起来,对摄像头的每一帧图像进行物品识别,这里使用的是RK提供的SSD模型。

演示视频:
RK3568-AI物品检测

1 SSD模型介绍

SSD,全称为Single Shot MultiBox Detector,是Wei Liu在ECCV 2016上提出的一种目标检测算法,属于一阶段One Stage方法,SSD 模型利用不同尺度的特征图进行目标的检测,其模型结构图如下:

RK3568-USB摄像头实时AI物品识别

SSD具有如下主要特点:

  • 从YOLO中继承了将detection转化为regression的思路,同时一次即可完成网络训练
  • 基于Faster RCNN中的anchor,提出了相似的prior box
  • 加入基于特征金字塔(Pyramidal Feature Hierarchy)的检测方式,相当于半个FPN思路

SSD网络结构图如下:

RK3568-USB摄像头实时AI物品识别

其算法步骤为:

  • 将图像输入预训练好的分类网络(基于VGG16-Atrous)得到不同大小的特征映射
  • 分别提取Conv4_3、Conv7、Conv8_2、Conv9_2、Conv10_2、Conv11_2层的特征映射feature map,在每个特征映射的每个点构造6个不同大小尺度的bounding box,进行检测和分类来生成一些列bounding box
  • 采用NMS处理不同特征映射的bounding box,删掉部分重叠或者不正确的bounding box,得到最终的检测框

OK3568-C开发板中自带了已训练好的AI模型,位于/userdata/model目录下的ssd_inception_v2.rknn,我们直接用就可以了。

2 USB摄像头实现物品识别代码

先来看下整个代码的项目结构,然后再来分别介绍各个功能模块。

  • imageutil.h:图像类型转换相关函数
  • myvideosourceface.cpp/h:用于USB摄像头图像显示
  • qtcamera.cpp/h:qt界面
  • rknn_ssd_process.cpp/h:用于SSD模型进行AI物品识别的接口函数
  • rknn_ssd.cpp/h:SSD模型相关函数

RK3568-USB摄像头实时AI物品识别

3 按帧获取USB摄像头图像

Qt读取并显示USB摄像头,需要3个基本元素:

  • QCamera:它是用于读取摄像头视频信号的接口函数
  • QCameraInfo:它提供相机设备的常规信息,可以用来查询系统上当前可用的相机设备
  • QCameraViewfinder:它提供了一个相机取景器的小部,该类继承于QVideoWidget类,用于显示多媒体类提供的视频

3.1 USB相机获取图像

查找USB相机

//可用相机列表
const QList<QCameraInfo> availableCameras = QCameraInfo::availableCameras();
for (const QCameraInfo &cameraInfo : availableCameras)
{
    qDebug() << cameraInfo.description();
    if (cameraInfo.description().contains("USB", Qt::CaseSensitive))
    {
        //USB摄像头
        QPushButton *camera = new QPushButton;
        camera->setText(cameraInfo.description());
        camera->setFont(font);
        camera->setCheckable(true);
        if (cameraInfo == QCameraInfo::defaultCamera())
        {
            camera->setDefault(true);
        }
        else
        {
            camera->setDefault(false);
        }

        //启动相机
        connect(camera, SIGNAL(clicked(bool)), this, SLOT(on_cameraClick()));
        vLayout->addWidget(camera);

        m_cameraInfo = cameraInfo;
        break;
    }
}

启动相机与显示

//创建摄像头对象
m_camera = new QCamera(m_cameraInfo);

//创建取景器
m_viewfinder = new QCameraViewfinder();

//配置摄像头的模式--捕获静止图像
QCamera::CaptureModes captureMode = QCamera::CaptureStillImage;
if (m_camera->isCaptureModeSupported(captureMode))
{
    m_camera->unload();
    m_camera->setCaptureMode(captureMode);
    //设置取景器显示
    m_camera->setViewfinder(m_viewfinder);
    //启动摄像头
    m_camera->start();
}

3.2 改为自己的Viewfinder

上面的USB摄像头显示程序,使用的是Qt的QCameraViewfinder用来显示摄像头图像,为了能获取到每一帧的图像,可以自己实现一个Viewfinder,然后在m_camera->setViewfinder时设置为自己的,并添加槽函数rcvFrame,当获取到一帧图像时,会触发此函数。

void qtCamera::on_cameraClick()
{
    //创建摄像头对象
    m_camera = new QCamera(m_cameraInfo);

    m_camera->unload();
    //配置摄像头的模式--捕获静止图像
    m_camera->setCaptureMode(QCamera::CaptureStillImage);

    //设置默认摄像头参数
    QCameraViewfinderSettings set;
    set.setResolution(640, 480);                 //设置显示分辨率
    set.setMaximumFrameRate(25);                 //设置帧率

    //自己用QPainter将每一帧视频画出来
    myvideosurface *surface = new myvideosurface(this);

    //设置取景器显示
    m_camera->setViewfinder(surface);
    connect(surface, SIGNAL(frameAvailable(QVideoFrame)), this, SLOT(rcvFrame(QVideoFrame)), Qt::DirectConnection);
    connect(this,SIGNAL(sendOneQImage(QImage)), this, SLOT(recvOneQImage(QImage)));

    //启动摄像头
    m_camera->start();
}

接收到一帧图像后,其原始图像格式是QVideoFrame类型的,需要先转为QImage类型,然后就可以进行显示或进行图像处理了,这里触发一个sendOneQImage信号来通知进行图像处理:

void qtCamera::rcvFrame(QVideoFrame m_currentFrame)
{
    m_currentFrame.map(QAbstractVideoBuffer::ReadOnly);

    QImage videoImg =  QImage(m_currentFrame.bits(),
                   m_currentFrame.width(),
                   m_currentFrame.height(),
                   QVideoFrame::imageFormatFromPixelFormat(m_currentFrame.pixelFormat())).copy(); 
    
    m_currentFrame.unmap();  
    QWidget::update();     

    emit sendOneQImage(videoImg); //发送信号
}

4 图像类型的转换与显示

4.1 QImage转Mat

Qt是QCamera创建的USB摄像头,获取到的图片格式是QImage类型,而使用OpenCV进行图像处理,需要转换为cv::Mat类型,转换的方式如下:

cv::Mat QImageToMat(QImage image)
{
    image = image.convertToFormat(QImage::Format_RGB888);
    cv::Mat tmp(image.height(), image.width(), CV_8UC3, (uchar *)image.bits(), image.bytesPerLine());
    cv::Mat result; // deep copy just in case (my lack of knowledge with open cv)
    cvtColor(tmp, result, CV_BGR2RGB);
    return result;
}

4.2 Mat转QImage

OpenCV进行图像处理完成后,比如进行AI物品识别完成,并将识别的信息标记到图像上后,需要再转成QImage的类型用于在Qt中显示出来,转换的方式如下:

QImage MatToQImage(cv::Mat mat)
{
    cv::cvtColor(mat, mat, CV_BGR2RGB);
    QImage qim((const unsigned char *)mat.data, mat.cols, mat.rows, mat.step,
               QImage::Format_RGB888);
    return qim;
}

4.3 QImage转QPixmap

QImage在Qt中还不能直接显示出来,还需要再转为QPixmap类型,转换的方式如下:

QImage qImage;
QPixmap tempPixmap = QPixmap::fromImage(qImage);

4.4 图像的显示

这里创建一个QLabel用于显示图像,调用setPixmap方法即可将图像显示出来,最后的adjustSize用来自动调整大小。

//创建一个label用于显示图像
m_lableShowImg = new QLabel();
m_lableShowImg->setPixmap(tempPixmap);
m_lableShowImg->adjustSize();

5 RKNN例程移植

飞凌OK3568-C开发板资料中,自带了ssd模型的测试程序,代码位置如下,ssd的测试代码是这3个文件:

RK3568-USB摄像头实时AI物品识别

测试代码,需要在执行时,输入模型的目录位置和测试图片的位置,AI物品识别之后会产生一个输出图片,需要再使用图片查看器查看结果。

为了方便功能的调用,这里将fltest_opencv_rknn_ssd_main.cc改写为rknn_ssd_process.cpp,并将具体功能进行拆分,封装为C++的形式。

5.1 按功能封装为C++形式

自己封装的RknnSsdModel类定义:

class RknnSsdModel
{
public:
    RknnSsdModel(){};
    ~RknnSsdModel(){};

    int RknnInit(const char *model_path);
    int RknnDeInit();
    unsigned char *LoadModel(const char *filename, int *model_size);
    int DoRknnSsd(cv::Mat &src, cv::Mat &res);

private:
    unsigned char *m_pModel = nullptr;
    rknn_context m_rknnCtx;
    rknn_input_output_num m_rknnIoNum;

};

5.1.1 RKNN初始化

主要功能是根据传入的rknn模型进行相关的初始化

int RknnSsdModel::RknnInit(const char *model_path)
{
    int ret = 0;
    int model_len = 0;

    // Load RKNN Model
    printf("Loading model ...\n");
    m_pModel = LoadModel(model_path, &model_len);

    printf("rknn_init ...\n");
    ret = rknn_init(&m_rknnCtx, m_pModel, model_len, 0, NULL);
    if (ret < 0)
    {
        printf("rknn_init fail! ret=%d\n", ret);
        return -1;
    }

    //省略...
}

5.1.2 RKNN运行

传入一张Mat格式的图片(一帧视频图像),经过AI识别,并将识别的信息标注到图片上后,将识别结果也以Mat格式传出:

int RknnSsdModel::DoRknnSsd(cv::Mat &src, cv::Mat &res)
{
    const int img_width = 300;
    const int img_height = 300;
    const int img_channels = 3;
    int ret = 0;

    cv::Mat img = src.clone();
    if (src.cols != img_width || src.rows != img_height)
    {
        printf("resize %d %d to %d %d\n", src.cols, src.rows, img_width, img_height);
        cv::resize(src, img, cv::Size(img_width, img_height), (0, 0), (0, 0), cv::INTER_LINEAR);
    }

    // Set Input Data
    rknn_input inputs[1];
    memset(inputs, 0, sizeof(inputs));
    inputs[0].index = 0;
    inputs[0].type = RKNN_TENSOR_UINT8;
    inputs[0].size = img.cols * img.rows * img.channels();
    inputs[0].fmt = RKNN_TENSOR_NHWC;
    inputs[0].buf = img.data;

    ret = rknn_inputs_set(m_rknnCtx, m_rknnIoNum.n_input, inputs);
    if (ret < 0)
    {
        printf("rknn_input_set fail! ret=%d\n", ret);
        return -1;
    }

    // Run
    printf("rknn_run\n");
    ret = rknn_run(m_rknnCtx, nullptr);
    if (ret < 0)
    {
        printf("rknn_run fail! ret=%d\n", ret);
        return -1;
    }

    // Get Output
    rknn_output outputs[2];
    memset(outputs, 0, sizeof(outputs));
    outputs[0].want_float = 1;
    outputs[1].want_float = 1;
    ret = rknn_outputs_get(m_rknnCtx, m_rknnIoNum.n_output, outputs, NULL);
    if (ret < 0)
    {
        printf("rknn_outputs_get fail! ret=%d\n", ret);
        return -1;
    }

    // Post Process
    detect_result_group_t detect_result_group;
    postProcessSSD((float *)(outputs[0].buf), (float *)(outputs[1].buf), src.cols, src.rows, &detect_result_group);
    // Release rknn_outputs
    rknn_outputs_release(m_rknnCtx, 2, outputs);

    // Draw Objects
    for (int i = 0; i < detect_result_group.count; i++)
    {
        detect_result_t *det_result = &(detect_result_group.results[i]);
        printf("%s @ (%d %d %d %d) %f\n",
               det_result->name,
               det_result->box.left, det_result->box.top, det_result->box.right, det_result->box.bottom,
               det_result->prop);
        int x1 = det_result->box.left;
        int y1 = det_result->box.top;
        int x2 = det_result->box.right;
        int y2 = det_result->box.bottom;
        rectangle(src, Point(x1, y1), Point(x2, y2), Scalar(255, 0, 0, 255), 3);
        putText(src, det_result->name, Point(x1, y1 - 12), 1, 4, Scalar(0, 255, 0, 255), 4);
    }

    res = src;
    return 0;
}

5.2 AI识别调用

OK3568-C开发板中自带了已训练好的AI模型,位于/userdata/model目录下的ssd_inception_v2.rknn,在程序初始化时需要用到。

RK3568-USB摄像头实时AI物品识别

AI识别的代码逻辑为:先在qtCamera初始化时调用RKNN的初始化,然后打开USB摄像头,USB获取到每帧图像后, 调用DoRknnSsd进行AI物品识别,最后将识别的结果通过setPixmap方法展示出来

//先在qtCamera初始化时调用RKNN的初始化
std::string ssd_model = "/userdata/model/ssd_inception_v2.rknn";
m_rknnModel.RknnInit(ssd_model.c_str());

//USB获取到每帧图像后, 调用DoRknnSsd进行AI物品识别
void qtCamera::recvOneQImage(QImage qImage)
{
    cv::Mat srcImg = ImageUtil::QImageToMat(qImage);
    cv::Mat dstImg;
    m_rknnModel.DoRknnSsd(srcImg, dstImg);
    QImage qDstImage = ImageUtil::MatToQImage(dstImg);
    QPixmap tempPixmap = QPixmap::fromImage(qDstImage);

    m_lableShowImg->setPixmap(tempPixmap);
    m_lableShowImg->adjustSize();
}

5.3 编译

需要注意下Qt工程的配置文件,要把opencv的一些库链接进去

qcamera.pri

INCLUDEPATH         += $$PWD/src

HEADERS += \
    $$PWD/src/qtcamera.h \
    $$PWD/src/myvideosurface.h \
    $$PWD/src/rknn_ssd.h \
    $$PWD/src/rknn_ssd_process.h \
    $$PWD/src/imageutil.h

SOURCES += \
    $$PWD/src/qtcamera.cpp \
    $$PWD/src/myvideosurface.cpp \
    $$PWD/src/rknn_ssd.cpp \
    $$PWD/src/rknn_ssd_process.cpp

qcamera.pro

TARGET = USBCameraSSD
TEMPLATE = app

QT += widgets multimedia multimediawidgets

SOURCES += main.cpp

include($$PWD/qcamera.pri)

LIBS+=-lopencv_core -lopencv_objdetect -lopencv_highgui -lopencv_videoio -lopencv_imgproc -lopencv_imgcodecs -lrknn_api -lOpenCL -lpthread

#temp file
DESTDIR         = $$PWD/app_bin
MOC_DIR         = $$PWD/build/qcamera
OBJECTS_DIR     = $$PWD/build/qcamera

最后的编译脚本还和之前的一样:

#! /bin/bash

mkdir -p build
cd build

export PATH=/home/xxpcb/myTest/OK3568/sourcecode/OK3568-linux-source/buildroot/output/OK3568/host/bin:$PATH

qmake .. && make

6 总结

本篇介绍了在飞凌OK3568-C开发板中,外接USB摄像头,利用Qt和RKNN进行AI物品识别,通过已训练好的SSD模型,进行摄像头画面的实时AI物品检查的代码实现原理。

RK3568-USB摄像头实时AI物品识别文章来源地址https://www.toymoban.com/news/detail-495577.html

到了这里,关于RK3568-USB摄像头实时AI物品识别的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • RK3568驱动OV13850摄像头模组调试过程

    品牌:Omnivision 型号:CMK-OV13850 接口: MIPI 像素:1320W OV13850彩色图像传感器是一款低电压、高性能1/3.06英寸1320万像素 CMOS图像传感器 ,使用OmniBSI+?技术提供了单-1320万像素(4224×3136)摄像头的功能。通过串行摄像头控制总线(SCCB)接口的控制,它提供了全帧、下采样、开窗的

    2023年04月27日
    浏览(58)
  • rk3568mipi摄像头调试(gc2385 + gc2053)

    RK3568平台仅有一个标准物理mipi csi2 dphy,可以工作在full mode 和split mode两个模式, 拆分为csi2_dphy0/csi2_dphy1/csi2_dphy2三个逻辑dphy Full Mode: 仅使用csi2_dphy0,csi2_dphy0与csi2_dphy1/csi2_dphy2互斥,不可同时使用; data lane最大4 lanes; 最大速率2.5Gbps/lane; Split Mode: 仅使用csi2_dphy1和csi2_dphy2, 与csi2_dph

    2024年02月16日
    浏览(59)
  • RK3568 android11 调试mipi摄像头 gc2093

    GC2093是一个高质量的1080P CMOS图像传感器,用于安全相机产品、数码相机产品和手机相机应用程序。包含了一个1920H x 1080V像素阵列、片上10位ADC和图像信号处理器。高性能和低功耗功能的全面集成使GC2093最适合设计,减少了实现过程,并延长了运动相机、汽车DVR和各种移动应用

    2024年01月17日
    浏览(71)
  • RK平台USB摄像头FAQ

    (记录android9以后调试所遇到的常见问题,有错请批评指正)         UVC全称为USB video(device) class,是微软与另外几家设备厂商联合推出的为usb视频捕获设备定义的协议标准;所以说UVC仅仅是usb规范协议中设备类规范的其中一种,是用作usb接口的视频设备的一个统一的数据

    2023年04月20日
    浏览(57)
  • RK3568平台开发系列讲解(视频篇)摄像头采集视频的相关配置

    🚀返回专栏总目录 沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 Android 平台的摄像头的采集核心部分都是在 Native 层构建的,所以这就会涉及 JNI 层的一些转换操作。 要想使用 Android 平台提供的摄像头,必须在配置文件里添加权限要求。

    2023年04月08日
    浏览(66)
  • yolov5-6.0项目部署+自用Pytorch模型转换rknn模型并在RK3568 linux(Debian)平台上使用qt部署使用NPU推理加速摄像头目标识别详细新手教程

    1 我们打开yolov的官网,Tags选择6.0版本 2. 下载该压缩包并解压到工程目录下 3. 我们这里使用pycharm,专门针对python的IDE,用起来非常方便,下载方式就是官网直接下载,用的是社区版 4. 我们需要安装环境,这里我推荐安装Anaconda在电脑上,这是一个非常方便的包管理工具,可

    2024年02月05日
    浏览(68)
  • RK3588安装Qt+opencv+采集USB摄像头画面

    Qt:5.12.8 opencv:3.4.14 qt安装 ---------------------------------------------------------------------------------- 因为使用官网下载的版本始终安装失败,所以我可以直接使用命令行进行下载安装: 1:首先先将ubuntu的软件更新,并更新镜像源 sudo apt-get update sudo apt-get upgrade 2:使用如下步骤安装Qt

    2023年04月10日
    浏览(59)
  • 基于android的 rk3399 同时支持多个USB摄像头

    一、前文 在这里插入图片描述 二、CameraHal_Module.h 三、CameraHal_Module.cpp 四、编译烧录Image 该部分的修改要生效的话,需要进行全编译 五、App验证 AndroidManifest.xml MainActivity.java activity_main.xml

    2024年02月08日
    浏览(50)
  • RK3568 android11 移植 v4l2loopback 虚拟摄像头

    v4l2loopback是一个Linux内核模块,它允许用户创建虚拟视频设备。这种虚拟视频设备可以用于各种用途,例如将实际摄像头的视频流复制到虚拟设备上,或者用于视频流的处理和分析等。v4l2loopback的主要作用是 创建一个虚拟的Video4Linux2设备,它可以接收来自其他应用程序的视频

    2024年01月19日
    浏览(67)
  • AHD同轴摄像头接入电脑USB录制视频的方法,AHD转USB,AI图像算法(ADAS\DMS\360环视\BSD\人脸识别),图像接入电脑处理

            在图像算法训练时,有时候需要接入电脑进行算法调试和处理,很多摄像头是AHD同轴信号,例如安防和汽车后装市场很多摄像头都是AHD同轴的接口,而电脑没有可以接入同轴的接口,所以需要转换成电脑可以接入的接口才可以将摄像头接入电脑,而USB绝对是最常用

    2024年02月09日
    浏览(138)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包